一、简介
JavaScript诞生于1995年,它的出现主要用于处理网页中的前端验证。当时,网速很慢而且上网费很贵,有些操作不宜在服务器端完成。比如,如果用户忘记填写“用户名”,就点了“发送”按钮,到服务器再发现这一点就有点太晚了,最好能在用户发出数据之前,就告诉用户“请填写xx栏”。这就需要在网页中嵌入小程序,让浏览器检查每一栏是否都填写了。
ECMAScript 是一个标准,而这个标准需要由各厂商去实现,不同浏览器厂商对该标准会有不同的实现:
一般认为ECMAScript和JavaScript一个意思,实际JavaScript的含义更大一些。
一个完整的JavaScript实现应该由以下三个部分构成:
特点:
- 解释型语言
- 类似于C和Java的语法结构
- 动态语言
- 基于原型的面向对象
二、基本语法
编写位置
1.标签内部,不推荐
2.script标签中
3.外部文件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <!--可以将js代码编写到外部js文件中,然后通过script标签引入 写到外部文件中,可以在不同的页面同时引用,也可以利用到浏览器的缓存机制 --> <script type="text/javascript" src="js/script.js"> alert('hello') <!--一旦引入外部文件,这里的代码都被忽略, 如果想写可以再创建新的script标签写 --> </script> <!--可以将js代码写在script标签中--> <script type="text/javascript"> alert('我是script标签中的代码') </script> </head> <body> <!--可以将js代码编写到标签的onclick属性中 当我们点击按钮时,js代码才会执行 虽然可以写在标签的属性中,但是结构与行为耦合,不方便维护,不推荐使用 --> <button onclick="alert('讨厌,别点我')">点我</button> <!-- 可以将js代码写在超链接的href属性中,这样当点击超链接时,会执行js代码 --> <a href="javascript:alert('汪汪')">点我</a> <a href="javascript:;">点我</a> </body> </html>
严格区分大小写
注释
单行注释: // 这是注释
多行注释:/* 这是注释 */
标识符
在JS中所有可以自主命名的都可以称为标志符
例如:变量名、函数名、属性名
1.标志符中可以包括字母、数字、下划线和$
2.不能以数字开头
3.不能是ES中的关键字或保留字
4.标志符一般采用驼峰命名法
首字母小写,每个单词开头字母大写,其他小写 helloWorld
JS底层保存标志符式,实际采用的Unicode编码,所以,理论上所有的utf-8中含有的内容都可以作为标志符,如:
var 变量 = 789; //千万别用
关键字和保留字
关键字
保留字符
其他不建议使用的标识符
变量
变量的作用是给某个值或对象标注名称。
变量声明
使用var关键字
var a;
变量的赋值
a = 123;
声明和赋值同时进行
var a = 123;
数据类型
数据类型决定了一个数据特征,对于不同的数据类型进行的操作会有很大不同。总体而言,JavaScript共有六种数据类型。
5种基本数据类型,首字母都大写:
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
这5种之外的类型都称为Object。
typeof运算符
使用typeof操作符可以用来检查一个变量的数据类型
使用方式:typeof 数据
返回结果:
String
String用于表示一个字符序列,即字符串。字符串需要使用'或"括起来。转义字符:
将其他数值转换为字符串有三种方式:toString()、String()、拼串。
Number
Number 类型用来表示整数和浮点,最常用的功能就是用来表示 10 进制的整数和浮点数。
Number表示的数字大小是有限的,范围是:
NaN,即非数值(Not a Number)是一个特殊的数值,当数值进行计算时没有结果返回,则返回NaN。
数值的转换
有三个函数可以把非数值转换为数值:Number()、parseInt()和parseFloat()。
Number()可以用来转换任意类型的数据,而后两者只能用于转换字符串。
parseInt()只会将字符串转换为整数,而parseFloat()可以转换为浮点数。
Boolean
布尔型也被称为逻辑值类型或真假类型。布尔型只能够取真(true)和假(false)两种数值。除此以外其他的值都不被支持。
其他的数据类型也可以通过Boolean()函数转换为布尔类型。
转换规则:
Undefined
Undefined类型只有一个值,即特殊的undefined。
使用var声明变量但未对其初始化时,这个变量的值就是undefined。如:
var message;
message的值就是undefined。
typeof对没有初始化和没有声明的变量都会反变换undefined。
Null
是第二个只有一个值的数据类型,这个特殊的值是null。
从语义上看null表示的是一个空对象,所以使用typeof检查null返回一个Object。
undefined值实际上是由null值衍生出来的,所以如果比较undefined和null是否相等,会返回true。
运算符
JavaScript中的运算符包括:算数运算符、位运算符、关系运算符等。
算术运算符
自增和自减
自增++ 自减--
自增和自减分为前置运算和后置运算,所谓的前置元素就是将元素符放到变量的前边,而后置将元素符放到变量的后边。
var a=3;
var b=++a;
b的值为4
var a=3;
var b=a++;
b的值为3
逻辑操作符
一般情况下使用逻辑运算符会返回一个布尔值。逻辑运算符主要有三个:非、与、或。
在进行逻辑操作时如果操作数不是布尔类型则会将其转为布尔类型再进行计算。
赋值运算符
简单的赋值操作符由=表示,如果再等号左边添加加减乘除等运算符就可以完成复合赋值操作:+=、*=、-+、/=、%=。
关系运算符
<、>、<=、>=
相等
==、!=
null和undefined使用==判断时是相等的
全等
===、!===
== 在判断两个值时会进行自动转换,===不会进行自动转换。
逗号
使用逗号可以在一条语句中执行多次操作,从左到右依次执行。
var num1=1, num2=2, num3=3;
条件运算符
也称为三元运算符,通常写为 ?: 。需要三个操作数,第一在?之前,第二个在?和:之间,第三个在:之后。
运算符的优先级
语句
语句是一个程序的基本单位,JavaScript的程序就是由一条一条语句构成的,每一条语句使用;结尾。默认是由上至下顺序执行的,也可以通过一些流程控制语句来控制语句的执行。
代码块
代码块是在大括号{}中所写的语句,以此将多条语句的集合视为一条语句来使用。
条件语句
通过判断指定表达式的值来决定执行还是跳过某些语句。
if...else
switch...case
循环语句
while
do...while
for
break
continue
label语句
在代码中添加标签,以便将来使用。
三、对象
基本数据类型的局限?
JS的基本数据类型有Number、String、Boolean、Null和Undefined,这些基本数据类型是有局限的:
都是单一的值,值和值之间没有联系,如在JS中表示一个人的信息(name gender age)
var name = "孙悟空";
var gender = "男";
var age = 18;
如果使用基本数据类型,所创建的变量都是独立的,不能成为一个整体。对象属于一种复合的数据类型,在对象中可以保存多个不同的数据类型的属性。
于是,我们需要引用数据类型。
Object类型,也称为一个对象,是JS中的引用数据类型,只要不是基本数据类型的都是对象。它是一种复合值,将很多值聚合在一起,可以通过名字访问这些值。
对象除了可以创建自有属性,还可以通过从一个名为原型的对象哪里继承属性。
引用类型的值是保存在内存中的对象。当一个变量是一个对象时,实际上变量中保存的并不是对象本身,而是对象的引用。当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象。此时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个。
创建对象
两种方式:
第一种
var person = new Object();
person.name = "孙悟空";
person.age = 18;
第二种
var person = {
name: "孙悟空",
age: 18
};
对象属性的访问
语法:对象.属性名
console.log(obj.name);
如果读取对象中没有的属性,返回Undefined
修改对象的属性值
语法:对象.属性名= 新值
删除对象的属性
语法:delete 对象.属性名
使用 ['属性名'] 操作属性,更加灵活
JS对象的属性值可以是任意数据类型,甚至可以是一个对象
var obj = new Object();
obj.test = true;
var obj2 = new Object();
obj2.name = "猪八戒";
obj.test = obj2;
in运算符
通过该运算符可以检查一个对象是否含有指定的属性
如果有则返回true,没有则返回false
语法:“属性名” in 对象
//检查obj中是否含有test2属性
console.log("test2" in obj)
基本数据类型和引用数据类型的区别
var a = 1;
var b = a;
var a = 2;
//b的值不会变
var obj = new Object();
obj.name = "孙悟空";
var obj2 = obj;
//修改obj的name属性
obj.name = "猪八戒";
//obj2的name也变为猪八戒
JS在运行时数据是保存到栈内存和堆内存中的。
简单来说,栈内存用来保存变量和基本数据类型。堆内存用来保存对象。
基本数据类型的值直接在栈内存中存储,值与值之间是独立存在的,修改一个变量不会影响其他变量。
声明一个变量时实际上就是在内存中创建了一个空间用来保存变量,如果是基本类型则在栈内存中直接保存。如果是引用类型则会在堆内存中保存,变量中保存的实际上是对象在堆内存中的地址。
基本数据类型保存在栈内存中
对象保存在堆内存中
JS的变每创建一个新对象,就会在堆内存中开辟一个新的空间,而变量保存的是对象的内存地址(对象的引用)。如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也受影响。
obj2 = null;
当比较两个基本数据类型的值时,就是比较值。
而比较两个引用数据类型时,它是比较对象的内存地址,如果两个对象是一模一样的,地址不同也会返回false。
对象字面量
使用对象字面量创建对象
var obj = {};
obj.name = "swk";
使用对象字面量,可以在创建对象时,直接指定对象中的属性
属性名可以加引号,也可以不加,建议不加
一些特殊的名字要加
属性名和属性值是一组的名值对结构,名和值之间使用:连接,多个名值对之间使用,隔开
如果一个属性之后没有其他的属性,就不要写逗号(,)
var obj2 = {
name:'swk',
age:28,
test:{name:'shs'}
};
工厂方式创建对象
重复创建对象很麻烦:
var obj = { name:"swk", age:18, gender:"male", sayName:function(){ alert(this.name); } }; var obj2 = { name:"zbj", age:18, gender:"male", sayName:function(){ alert(this.name); } }; var obj3 = { name:"shs", age:18, gender:"male", sayName:function(){ alert(this.name); } };
使用工厂方法创建对象:
function createPerson(){ //创建一个新对象 var obj = new Object(); //向对象中添加属性 obj.name=name; obj.age=age; obj.gender=gender; obj.sayName=function(){ alert(this.name); } return obj; }
Date对象
表示时间
如果直接使用构造函数创建一个Data对象,则会封装为当前代码执行的时间
var d = new Date(); //创建对象 console.log(d); //打印当前时间
创建一个指定的时间对象
需要在构造函数中传递一个表示时间的字符串作为参数
日期的格式 月份/日/年 时:分:秒
var d2 = new Date("12/03/2016 11:10:30");
getDate()获取当前日期对象是几日
getDay()获取当前日期对象是一周中的某一天,即周几,1-6,周日是0
getMonth()获取月份,会返回0-11的值,0表示1月,11表示12月,用时表示正常月份可以加1
getFullYear()获取年份
getTime()获取当前日期对象的时间戳,从格林威治标准时间1970年1月1日,0时0分0秒,
到当前的毫秒数(1秒=1000毫秒)
Date.time() 获取当前的时间,返回该代码执行时的时间
Math对象
Math和其他对象不同,不是构造函数,它属于一个工具类,不用创建对象
里面封装了数学运算相关的属性和方法
var m = new Math()会报错 Math.PI 圆周率 Math.E 自然对数的底数 ... abs() ceil()向上取整 floor()向下取整 round()四舍五入 random()生成0-1之间的随机数 Math.random()*(y-x)+x生成x-y之间随机数 max() min() pow()
数组
数组也是对象的一种。
它和普通的对象功能类似,也是用来存储一些值,不同的是普通对象时使用字符串作为属性名,数组使用数字作为索引来操作元素。
var arr = new Array(); console.log(type arr); //object //添加元素 语法:数组[索引] = 值; arr[0] = 10; //取元素 语法:数组[索引] console.log(arr[0]); //获取数组长度 语法:数组.length //连续数组,使用length可以获取到数组的长度,不连续数组会获得最大的索引+1 //尽量不要创建非连续数组 console.log(arr.length) //修改length,如果修改的length大于原长度,则多出的部分会空出来 //小于,则多出的元素会被删除 arr.length = 11; //向数组最后一个位置添加元素 //语法:数组[数组.length] = 值; arr[arr.length] = 70; var arr2 = new Array(1, 2, 3); var arr3 = [1, 2, 3]; //同上 //只有一个元素时要注意 var arr3 = new Array(10); //创建一个长度为10的数组,空数组 var arr4 = [10]; //创建一个只有一个元素为10的数组
读取不存在的索引,不会报错,返回Undefined。
数组的字面量
语法:[]
var arr = []; var arr1 = [1, 2, 3];
数组中的元素可以是任意数据类型,也可以是对象,也可以是数组(二维数组)
arr = ["hello", 1, true, null];
数组的四个方法
push()向数组末尾添加一个或多个元素,并返回数组的新的长度
可以将要添加的元素作为方法的参数传递
这样元素自动添加到数组的末尾
arr.push(5);
pop()删除数组的最后一个元素,返回值是被删除的元素 arr.pop()
unshift()向数组开头添加一个或多个元素,并返回新数组的长度
shift()删除数组第一个元素,并返回被删除元素
数组的遍历
取出数组中所有元素
for(var i=0;i<arr.length;i++){ console.log(arr[i]); }
forEach
只支持IE8以上浏览器,一般用个匿名函数,回调函数,对每个元素起作用
arr.forEach(function(value,index,obj){});
浏览器会传三个参数 正在遍历的元素,索引,正在此遍历的数组
slice()切片
splice(a, b)删除数组中的指定元素
a开始位置的索引
b删除的数量
第三个及以后的参数可以传递一些新的元素,这些元素将会自动插入到开始位置索引的前边
数组的剩余方法
concat()
连接两个或多个数组,也可以添加元素,并将新的数组返回
该方法不会对原数组产生影响,返回一个新数组
var arr = ["swk", "shs", "zbj"]; var arr1 = ["bgj", "ytj", "zzj"]; var arr2 =["yhdd", "els"] arr2 = arr.concat(arr1, arr2, "nmw"); console.log(arr2);
join()
把数组转换为一个字符串
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
在join中,可以指定字符串作为参数,这个字符串将会成为数组中元素的连接符
result = arr.join(); console.log(result); //默认所有元素用逗号拼接的字符串 result2 = arr.join("-"); //用-连接符 console.log(result2);
reverse()
该方法翻转数组,该方法会改变原数组
arr.reverse();
sort()
排序,该方法改变原数组,默认按Unicode编码排序
纯数字也会按Unicode编码排序,结果可能会出错,要指定排序规则
可以在sort()中添加回调函数,回调函数中要两个形参
浏览器将会分别使用数组中的元素作为实参去调用回调函数
浏览器会根据回调函数的返回值来决定元素的顺序
如果返回值大于0,则元素交换位置
如果返回0,不交换
返回小于0的值,元素位置不变
var arr = ['b', 'd', 'e', 'a', 'c']; arr.sort(); arr = [3, 4, 11, 2, 5] arr.sort(function(a,b){ if(a>b){ return 1; } if(a<b){ return -1; } if(a=b){ return 0; } }); arr.sort(function(a, b){ return a-b; //升序 return b-a; //降序 });
函数
函数也是一个对象,和普通函数一样添加属性,除此之外,函数中可以封装一些功能,在需要时执行。
Function
Function类型代表一个函数,每个函数都是一个Function类型的对象,而且都与其他引用类型一样具有属性。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数的声明有两种方式:
function sum(){}; var sum = function(){};
由于存在函数声明提升的过程,第一种方式在函数声明前就可以调用函数,第二种不行。
创建一个函数对象
var fun = new Function();
可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('Hello,这是我的第一个函数');")
封装到函数中的代码不会立即执行
函数中的代码在函数调用时执行,语法:函数对象()
fun();
在实际中很少使用构造函数创建函数,而是使用函数声明
语法:
function 函数名([形参1, 形参2...形参N]){ 语句 ... }
使用函数表达式来创建一个函数
var 函数名 = function([形参1, 形参2...形参N]){ 语句... }
使用时: 函数名();
匿名函数:
function(){ console.log("我是匿名函数"); }
这样的匿名函数没法使用,所以用函数表达式。
函数的参数
定义一个用来求两个数和的函数
可以在函数()中指定一个或多个形参
多个形参之间用逗号隔开
声明形参相当于在函数内部声明了对应的变量,但是并不赋值
在调用函数时,可以在()中指定实参
实参将会赋值给对应的形参
调用函数时,解析器不会检查实参的类型,也不检查实参的数量,多余的实参不会被赋值
函数实参可以是任意数据类型
function sum(a, b){ console.log(a+b); } sum(1,1);
函数的返回值
创建一个函数,计算三个数的和
function sum(a, b, c){ alert(a+b+c); }
往往需要返回,而不用输出
可以使用return来设置函数返回值
function sum(a, b, c){ var d = a+b+c; return d; } var result = sum(1, 2, 3);
如果return语句后不跟任何值或不写return,相当于返回一个Undefined
return后可以跟任意类型的值
函数中还可以声明函数
函数立即执行
(function(){
语句...
})();
(function(a, b){ alert(a+b); })(1, 2);
对象的属性值可以是函数
var obj = new Object(); obj.name = "swk"; obj.sayName = function(){ console.log(obj.name); }; obj.sayName();
如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法。
var obj2 = { name:'猪八戒', age:18, sayName:function(){ console.log(obj2.name); } }
函数可以作为参数
函数和其他对象一样可以作为一个参数传递给另外一个函数。使用函数作为参数时,变量后边千万不要加(),不加()表示将函数本身作为参数,加上以后表示将函数执行的结果作为参数。
枚举对象中的属性
对象是别人创建的,不一定知道对象中的属性
使用for...in语句
语法:
for(var 变量 in 对象){
}
var obj = { name: 'swk', age: 18, gender: 'male' } for(var n in obj){ console.log(n); //属性名 console.log(obj[n]); //不能用.,属性值,[]可以传变量 }
call()和apply()
这两个方法都是函数对象的方法,需要通过函数对象来调用
当对函数调用call()和apply()都会调用函数执行
在调用call()和apply()可以将一个对象指定为第一个参数,那么这个对象将会成为函数执行时的this
call()方法可以将实参在对象之后依次传递
appl()方法需要将实参封装到数组中统一传递
function fun(){ alert(this.name); } var obj = { naem:"obj", sayName:function(){ alert(this.name); } }; var obj2 = { name: "obj2", } fun.call(obj); obj.sayName.apply(obj2); function fun(a, b){ console.log("a=" + a); console.log("b=" + b); alert(this.name); } fun.call(obj, 2, 3); fun.apply(obj, [2, 3]);
this
解析器(浏览器)在调用函数时,每次都会向函数内部传递一个隐含的参数。这个隐含参数就是this,this指向的是一个对象,这个对象我们称之为函数执行的上下文对象。
根据函数调用方式的不同,this会指向不同的对象:
1.以函数形式调用永远是window
2.以构造函数形式调用,this是新创建的对象
3.使用call和apply调用时,this是指定的那个对象
以方法形式调用,this是调用方法的那个对象。
function fun(){ console.log(this); } var obj = { name:"swk", sayName:fun }; console.log(obj.sayName == fun); //true,一样的 fun(); //this为Window obj.sayName(); //this是name为swk的这个对象
arguments
在调用函数时,浏览器每次都会传递进两个隐含参数;
1.函数的上下文对象this
2.封装实参的对象arguments
arguments是一个类数组对象(很像数组的对象,但不是数组),也可以通过索引来操作数据,也可以获取长度。在调用函数时,我们所传递的实参都会在arguments中保存。
arguments.length可以用来获取实参的长度
即使不定义形参,也可以通过arguments来使用实参
arguments[0]表示第一个实参
arguments[1]表示第二个实参
arguments里有一个属性callee,这个属性对应一个函数对象,就是当前正在指向的函数对象
function fun(a, b){ console.log(arguments.length); } fun(1, 2); //长度为2 func fun(){ console.log(arguments[1]); } fun("hello", true); //控制台会打印true function fun(a, b){ console.log(arguments.callee == fun); } fun(); //打印true
构造函数
//创建人的对象 function createPerson(){ //创建一个新对象 var obj = new Object(); //向对象中添加属性 obj.name=name; obj.age=age; obj.gender=gender; obj.sayName=function(){ alert(this.name); } return obj; } //创建狗的对象 function createPerson(){ //创建一个新对象 var obj = new Object(); //向对象中添加属性 obj.name=name; obj.age=age; obj.sayHello=function(){ alert("旺旺"); } return obj; }
使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型。狗和人都是Object,只看名无法区分哪个是人哪个是狗。
可以创建一个构造函数,专门用来创建Person对象。构造函数就是一个普通函数,创建方式和普通函数没有区别,不同的构造函数习惯上首字母大写。构造函数和普通函数的区别是调用方式不同,普通函数时直接调用,构造函数需要使用new关键字来调用。使用同一个构造函数创建的对象,称为一类对象,也将一个构造函数称为一个类,将通过一个构造函数创建的对象,称为该类的实例
new关键字
构造函数总是由new关键字调用。
使用new关键字执行一个构造函数流程
1.立刻创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可用this来引用新建的对象
3.执行函数中的代码
4.将创建对象作为返回值返回
function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; this.sayName = function(){ alert(this.name); } } var per = new Person();
使用instancof可以检查一个对象是否是一个类的实例,所有对象都是Object的后代。
构造函数修改
在Person构造函数中,为每一个对象都添加了一个sayName方法,也是所有实例的sayName都是唯一的,这就导致构造函数执行一次就会创建一个新的方法,而这些方法都是一样的。
可以使所有对象共享同一个方法,将sayName()方法在全局作用域中定义
function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; this.sayName = fun; } } function fun(){ alert(this.name); }
将函数定义在全局作用域中,污染了全局作用域的命名空间,而且定义在全局作用域中不安全,不同的人可能重复命名覆盖掉。
垃圾回收
不再使用的对象的内存将会自动回收,所谓不再使用的对象,指的是没有被任何一个属性(变量)引用的对象。
EC:函数执行环境(或执行上下文),Execution Context
ECS:执行环境栈,Execution Context Stack
VO:变量对象,Variable Object
AO:活动对象,Active Object
scope chain:作用域链
闭包
闭包是JS一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。因为函数是JS中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。也可以将闭包的特征理解为,其相关的局部变量在函数调用结束之后将会继续存在。
包装类
在JS中有三个包装类,通过这三个包装类可以将基本数据类型转换为对象
String() 可以将基本数据类型字符串转为String对象
Number() 可以将基本数据类型的数字转换为Number对象
Boolean() 可以将基本数据类型的布尔值转换为Boolean对象
都是构造函数
在实际应用中不会像下面那样使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
var a = 3; var num = new Number(3); var str = new String("hello"); //变为对象功能强大 //向num中添加属性 num.hello = "abc";
方法和属性只能添加给对象,不能添加给基本数据类型,但是下面toString为什么不报错呢?
var s = 123; s = s.toString();
当对一些基本数据类型的值调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后再调用对象属性和方法调用完后,还是基本数据类型。
包装类是浏览器用的。
原型
JS是一门面向对象的语言,同时还是一个基于原型的面向对象的语言。我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应一个对象,这个对象就是原型对象。
原型继承
所谓的原型实际上指的是,在构造函数中存在着一个名为原型的(prototype)对象,这个对象中保存着一些属性,凡是通过该构造函数创建的对象都可以访问存在于原型中的属性。
最典型的原型中的属性就是toString()函数,实际上我们的对象中没有定义这个函数,但是却可以调用,那是因为这个函数存在于Object对应的原型中。
如果函数作为普通函数调用,prototype没有任何作用。当函数作为构造函数调用,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__来访问该属性。
原型对象相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有内容,统一设置到原型对象中。
当我们访问对象的一个属性或方法时,会先在对象自身中寻找,如果找到则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。
<script type="text/javascript"> function MyClass(){} // 向MyClass原型中添加属性a MyClass.prototype.a = 123; // 向MyClass的原型中添加一个方法 MyClass.prototype.sayHello = function(){alert("hello")}; var mc1 = new MyClass(); var mc2 = new MyClass(); console.log(MyClass.prototype); console.log(mc1.__proto__ == MyClass.prototype); </script>
结果:
以后创建构造函数时,可以直接将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
JS 中 __proto__ 和 prototype 存在的意义是什么?
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
原型链
每个对象都有原型对象,原型对象也有原型对象。我们的对象,和对象的原型,以及原型的原型,就构成了一个原型链。
当从一个对象中获取属性时,会首先从当前对象中查找,如果没有则顺着向上查找原型对象,直到找到Object对象的原型位置,找到则返回,找不到则返回undefined。
五、DOM
DOM,全称是Document Object Model文档对象模型。JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲地操作Web页面。
- 文档:表示整个HTML网页文档。
- 对象:表示将网页中的每一个部分都转换为一个对象。
- 模型:使用模型表示对象之间的关系,方便获取对象。
模型
节点
节点Node,是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为一个节点。比如:html标签、属性、文本、注释、整个文档等都是一个节点。标签称为元素节点,属性称为属性节点,文本称为文本节点,文档称为文档节点。节点的类型不同,属性和方法也都不尽相同。
节点的属性
文档节点
浏览器已经提供了 文档节点 对象,这个对象是window属性,可以在页面中直接使用,文档节点代表整个网页。
console.log(document); //可直接使用 var btn = document.getElementById("btn"); //通过文档节点查找元素
通过document对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
元素节点
HTML中的各种标签都是元素节点,这也是我们最常用的一个节点。浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点。
document.getElementById() // 根据id属性值获取一个元素节点对象
文本节点(Text)
文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。它包括可以字面解释的纯文本内容。文本节点一般是作为元素节点的子节点存在的。获取文本节点时,一般先要获取元素节点,再通过元素节点获取文本节点。
元素节点.firstChild; // 获取元素节点的第一个子节点,一般为文本节点
属性节点(Attr)
属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。可以通过元素节点来获取指定的属性节点,如:
元素节点.getAttributeNode("属性名")
一般不使用属性节点。
事件
事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。JS与HTML之间的交互是通过事件实现的。对于Web应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘某个键等等。
我们可以在事件对应的属性中设置一些JS代码,这样当事件被触发时,这些代码会执行。
// 获取按钮对象 var btn = document.getElementById('btn'); // 绑定一个单击事件 btn.onclick = function(){ alert("你还点~~"); };
浏览器加载一个页面时,是自上而下加载的,读取一行就运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载,DOM对象没有加载,无法获得DOM对象。将js代码编写到页面的下部就是为了,可以在页面加载完毕以后再执行JS代码。
如果想把js代码放在页面上面,可以使用onload 事件,该事件会在整个页面加载完成之后才触发,支持该事件的对象:image、layer和window。
为window绑定一个onload事件:
window.onload = function(){ alert("hello"); };
该事件对应的响应函数将会在页面加载完成之后执行,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕。
获取元素节点
DOM是针对XML(HTML)的基于树的API,把一个文档表示为一棵家谱树(父、子、兄弟)。
通过document对象调用:
getElementById() // 通过id属性获取一个元素节点对象 getElementsByTagName() // 通过标签名获取一组元素节点对象 getElementsByName() // 通过name属性获取一组元素节点对象
获取元素节点的子节点
通过具体的元素节点调用:
getElementsByTagName() 方法,返回当前节点的指定标签名后代节点
上面的getElementsByTagName()是通过document对象调用
childNodes 属性,表示当前节点的所有子节点 一些浏览器把空白也当成节点
firstChild 属性,表示当前节点的第一个子节点(包括空白文本节点)
lastChild 属性,表示当前节点的最后一个子节点
children属性,获取当前元素的所有子元素
firstElementChild属性,获取当前元素的第一个元素,不支持IE8及以下的浏览器
获取父节点和兄弟节点
通过具体的节点调用:
1.parentNode 属性,表示当前节点的父节点
2.previousSibling 属性,表示当前节点的前一个兄弟节点(也可能是空白文本)
previousElementSibling 属性,获取前一个兄弟元素,不会是空白文本,IE8及以下不支持
3.nextSibling 属性,表示当前节点的后一个兄弟节点
<script type="text/javascript"> /* * 定义一个函数,专门用来为指定元素绑定单击响应函数 * 参数: * idStr 要绑定单击响应函数的对象的id属性值 * fun 事件的回调函数,当单击元素时,该函数将会被触发 */ function myClick(idStr , fun){ var btn = document.getElementById(idStr); btn.onclick = fun; } window.onload = function(){ //为id为btn01的按钮绑定一个单击响应函数 var btn01 = document.getElementById("btn01"); btn01.onclick = function(){ //查找#bj节点 var bj = document.getElementById("bj"); //打印bj //innerHTML 通过这个属性可以获取到元素内部的html代码 alert(bj.innerHTML); }; //为id为btn02的按钮绑定一个单击响应函数 var btn02 = document.getElementById("btn02"); btn02.onclick = function(){ //查找所有li节点 //getElementsByTagName()可以根据标签名来获取一组元素节点对象 //这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中 //即使查询到的元素只有一个,也会封装到数组中返回 var lis = document.getElementsByTagName("li"); //打印lis //alert(lis.length); //变量lis for(var i=0 ; i<lis.length ; i++){ alert(lis[i].innerHTML); } }; //为id为btn03的按钮绑定一个单击响应函数 var btn03 = document.getElementById("btn03"); btn03.onclick = function(){ //查找name=gender的所有节点 var inputs = document.getElementsByName("gender"); //alert(inputs.length); for(var i=0 ; i<inputs.length ; i++){ /* * innerHTML用于获取元素内部的HTML代码的 * 对于自结束标签,这个属性没有意义 */ //alert(inputs[i].innerHTML); /* * 如果需要读取元素节点属性, * 直接使用 元素.属性名 * 例子:元素.id 元素.name 元素.value * 注意:class属性不能采用这种方式, * 读取class属性时需要使用 元素.className */ alert(inputs[i].className); } }; //为id为btn04的按钮绑定一个单击响应函数 var btn04 = document.getElementById("btn04"); btn04.onclick = function(){ //获取id为city的元素 var city = document.getElementById("city"); //查找#city下所有li节点 var lis = city.getElementsByTagName("li"); for(var i=0 ; i<lis.length ; i++){ alert(lis[i].innerHTML); } }; //为id为btn05的按钮绑定一个单击响应函数 var btn05 = document.getElementById("btn05"); btn05.onclick = function(){ //获取id为city的节点 var city = document.getElementById("city"); //返回#city的所有子节点 /* * childNodes属性会获取包括文本节点在呢的所有节点 * 根据DOM标签标签间空白也会当成文本节点 * 注意:在IE8及以下的浏览器中,不会将空白文本当成子节点, * 所以该属性在IE8中会返回4个子元素而其他浏览器是9个 */ var cns = city.childNodes; //alert(cns.length); /*for(var i=0 ; i<cns.length ; i++){ alert(cns[i]); }*/ /* * children属性可以获取当前元素的所有子元素 */ var cns2 = city.children; alert(cns2.length); }; //为id为btn06的按钮绑定一个单击响应函数 var btn06 = document.getElementById("btn06"); btn06.onclick = function(){ //获取id为phone的元素 var phone = document.getElementById("phone"); //返回#phone的第一个子节点 //phone.childNodes[0]; //firstChild可以获取到当前元素的第一个子节点(包括空白文本节点) var fir = phone.firstChild; //firstElementChild获取当前元素的第一个子元素 /* * firstElementChild不支持IE8及以下的浏览器, * 如果需要兼容他们尽量不要使用 */ //fir = phone.firstElementChild; alert(fir); }; //为id为btn07的按钮绑定一个单击响应函数 myClick("btn07",function(){ //获取id为bj的节点 var bj = document.getElementById("bj"); //返回#bj的父节点 var pn = bj.parentNode; alert(pn.innerHTML); /* * innerText * - 该属性可以获取到元素内部的文本内容 * - 它和innerHTML类似,不同的是它会自动将html去除 */ //alert(pn.innerText); }); //为id为btn08的按钮绑定一个单击响应函数 myClick("btn08",function(){ //获取id为android的元素 var and = document.getElementById("android"); //返回#android的前一个兄弟节点(也可能获取到空白的文本) var ps = and.previousSibling; //previousElementSibling获取前一个兄弟元素,IE8及以下不支持 //var pe = and.previousElementSibling; alert(ps); }); //读取#username的value属性值 myClick("btn09",function(){ //获取id为username的元素 var um = document.getElementById("username"); //读取um的value属性值 //文本框的value属性值,就是文本框中填写的内容 alert(um.value); }); //设置#username的value属性值 myClick("btn10",function(){ //获取id为username的元素 var um = document.getElementById("username"); um.value = "今天天气真不错~~~"; }); //返回#bj的文本值 myClick("btn11",function(){ //获取id为bj的元素 var bj = document.getElementById("bj"); //alert(bj.innerHTML); //alert(bj.innerText); //获取bj中的文本节点 /*var fc = bj.firstChild; alert(fc.nodeValue);*/ alert(bj.firstChild.nodeValue); }); }; </script>
其他方法
document中有一个属性body,保存的是body的引用
documentElement保存html根标签
document.all代表页面中所有的元素和document.getElementsByTagName("*")相同
var body = document.body; var html = document.documentElement; var all = document.all;
根据元素class属性值查询一组元素节点对象
IE9以上浏览器才支持
document.getElementsByClassName("box1");
使用CSS选择器进行查询
下面两个方法都是用document对象来调用,两个方法使用相同,都是传递一个选择器字符串作为参数,方法会自动根据选择器字符串去网页查找元素
querySelector() 只返回找到的第一个元素
querySelectorAll() 返回所有符合条件的元素
document.querySelector()
需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
虽然IE8中没有getElementsByClassName(),但可以用querySelector
document.querySelector(".box1 div");
使用该方法总会返回唯一的元素,如果满足条件的元素有多个,只会返回第一个
document.querySelectorAll()返回所有满足条件的元素到数组中,即使符合条件的元素只有一个
元素节点的属性
获取
元素对象.属性名
element.value
element.id
element.className
设置
元素对象.属性名 = 新的值
element.value = "hello" element.id = "id01" element.className = "newClass"
其他属性
nodeValue 文本节点可以通过nodeValue属性获取和设置文本节点的内容
innerHTML 通过这个属性可以获取到元素内部的html代码(一般是文本)
innerText 该属性可以获取到元素内部的文本内容,和innerHTML类似,不同的是会自动将html标签去除
节点的修改
增删替换插入
document.createElement() 可用于创建一个元素节点对象,它需要一个标签名作为参数,将会根据该标签名创建元素节点对象,并将创建好的对象返回值返回。
document.createTextNode() 可以用来创建一个文本节点,需要一个文本内容作为参数,将会根据内容创建文本节点,并将新的节点返回。
appendChild() 向一个父节点添加一个新节点
父节点.appendChild(子节点)
var li = document.createElement("li"); var gzText = document.createTextNode("广州"); var city = document.getElementById("city"); li.appendChild(gzText); //上面只是创建, 并不会显示在页面中 //定位页面本来就有的元素,添加到该元素下 var city = document.getElementById("city"); city.appendChild(li);
建议用下面的方式,使用innerHTML:
//创建一个li var li = document.createElement("li"); var city = document.getElementById("city"); //向li中设置文本 li.innerHTML = "广州"; //将li添加到city中 city.appendChild(li);
insertBefore()
在指定的子节点前面插入新的子节点。先要有父节点,因此是父节点调用。
需要:要插的子节点(下面是创建的节点)、被插的子节点、父节点
//将"广州"节点插入到#bj前面 要插的子节点 myClick("btn02",function(){ //创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); //获取id为bj的节点 被插的子节点 var bj = document.getElementById("bj"); //获取city 父节点 var city = document.getElementById("city"); /* * insertBefore() * - 可以在指定的子节点前插入新的子节点 * - 语法: * 父节点.insertBefore(新节点,旧节点); */ city.insertBefore(li , bj);
replaceChild()
替换子节点,父节点调用
//创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); //获取id为bj的节点 var bj = document.getElementById("bj"); //获取city var city = document.getElementById("city"); /* * replaceChild() * - 可以使用指定的子节点替换已有的子节点 * - 语法:父节点.replaceChild(新节点,旧节点); */ city.replaceChild(li , bj);
removeChild()
删除子节点
//获取id为bj的节点 var bj = document.getElementById("bj"); //获取city var city = document.getElementById("city"); /* * removeChild() * - 可以删除一个子节点 * - 语法:父节点.removeChild(子节点); * * 子节点.parentNode.removeChild(子节点); */ //city.removeChild(bj);
更常用
bj.parentNode.removeChild(bj);
实例1
window.onload = function() { //创建一个"广州"节点,添加到#city下 myClick("btn01",function(){ //创建广州节点 <li>广州</li> //创建li元素节点 /* * document.createElement() * 可以用于创建一个元素节点对象, * 它需要一个标签名作为参数,将会根据该标签名创建元素节点对象, * 并将创建好的对象作为返回值返回 */ var li = document.createElement("li"); //创建广州文本节点 /* * document.createTextNode() * 可以用来创建一个文本节点对象 * 需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回 */ var gzText = document.createTextNode("广州"); //将gzText设置li的子节点 /* * appendChild() * - 向一个父节点中添加一个新的子节点 * - 用法:父节点.appendChild(子节点); */ li.appendChild(gzText); //获取id为city的节点 var city = document.getElementById("city"); //将广州添加到city下 city.appendChild(li); }); //将"广州"节点插入到#bj前面 myClick("btn02",function(){ //创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); //获取id为bj的节点 var bj = document.getElementById("bj"); //获取city var city = document.getElementById("city"); /* * insertBefore() * - 可以在指定的子节点前插入新的子节点 * - 语法: * 父节点.insertBefore(新节点,旧节点); */ city.insertBefore(li , bj); }); //使用"广州"节点替换#bj节点 myClick("btn03",function(){ //创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); //获取id为bj的节点 var bj = document.getElementById("bj"); //获取city var city = document.getElementById("city"); /* * replaceChild() * - 可以使用指定的子节点替换已有的子节点 * - 语法:父节点.replaceChild(新节点,旧节点); */ city.replaceChild(li , bj); }); //删除#bj节点 myClick("btn04",function(){ //获取id为bj的节点 var bj = document.getElementById("bj"); //获取city var city = document.getElementById("city"); /* * removeChild() * - 可以删除一个子节点 * - 语法:父节点.removeChild(子节点); * * 子节点.parentNode.removeChild(子节点); */ //city.removeChild(bj); bj.parentNode.removeChild(bj); }); //读取#city内的HTML代码 myClick("btn05",function(){ //获取city var city = document.getElementById("city"); alert(city.innerHTML); }); //设置#bj内的HTML代码 myClick("btn06" , function(){ //获取bj var bj = document.getElementById("bj"); bj.innerHTML = "昌平"; }); myClick("btn07",function(){ //向city中添加广州 var city = document.getElementById("city"); /* * 使用innerHTML也可以完成DOM的增删改的相关操作 * 一般我们会两种方式结合使用 */ //city.innerHTML += "<li>广州</li>"; //创建一个li var li = document.createElement("li"); //向li中设置文本 li.innerHTML = "广州"; //将li添加到city中 city.appendChild(li); }); }; function myClick(idStr, fun) { var btn = document.getElementById(idStr); btn.onclick = fun; }
实例2
增删改查
function removeTr(){ var trNode = this.parentNode.parentNode; var tds = trNode.getElementsByTagName("td"); var nameStr = tds[0].firstChild.nodeValue; var flag = confirm("真的要删除" + nameStr + "的信息吗?"); if(flag){ trNode.parentNode.removeChild(trNode); } return false; } window.onload = function(){ //目标1:点击Delete删除记录 var aEles = document.getElementsByTagName("a"); for(var i = 0;i < aEles.length;i++){ aEles[i].onclick = removeTr; } //目标2:点击Submit增加记录 var subBtn = document.getElementById("addEmpButton"); subBtn.onclick = function(){ var nameText = trim(document.getElementById("empName").value); var emailText = trim(document.getElementById("email").value); var salaryText = trim(document.getElementById("salary").value); document.getElementById("empName").value = nameText; document.getElementById("email").value = emailText; document.getElementById("salary").value = salaryText; if(nameText == "" || emailText == "" || salaryText == ""){ alert("您输入的内容不完整"); return ; } //组装节点 var nameTd = document.createElement("td"); nameTd.appendChild(document.createTextNode(nameText)); var emailTd = document.createElement("td"); emailTd.appendChild(document.createTextNode(emailText)); var salaryTd = document.createElement("td"); salaryTd.appendChild(document.createTextNode(salaryText)); var aTd = document.createElement("td"); var aNewEle = document.createElement("a"); aNewEle.href = "deleteEmp?id=XXX"; aNewEle.appendChild(document.createTextNode("Delete")); aNewEle.onclick = removeTr; aTd.appendChild(aNewEle); var trNode = document.createElement("tr"); trNode.appendChild(nameTd); trNode.appendChild(emailTd); trNode.appendChild(salaryTd); trNode.appendChild(aTd); var empTable = document.getElementById("employeeTable"); empTable.appendChild(trNode); } function trim(str){ var reg = /^s*|s*$/g; return str.replace(reg,""); } }
var trNode = this.parentNode.parentNode;
用this而不用allA[i]。因为for循环会先执行完,当响应函数执行时,for循环早已执行完毕,i会是length-1,取不到东西,用this指当前的超链接。
for(var i=0;i<allA.length;i++){ allA[i].onclick = function(){ var trNode = this.parentNode.parentNode; var tds = trNode.getElementsByTagName("td"); var nameStr = tds[0].firstChild.nodeValue; var flag = confirm("真的要删除" + nameStr + "的信息吗?"); if(flag){ trNode.parentNode.removeChild(trNode); }
切换图片练习
全局变量的生命周期:
从程序开始执行创建,到整个页面关闭时,变量收回。
局部变量的生命周期:
从函数开始调用开始,一直到函数调用结束。但有的时候我们需要让局部变量的生命周期长一点,这个时候在js当中就有了闭包,他能够很好的解决这个问题。
window.onload = function(){ var prev = document.getElementById("prev"); var next = document.getElementById("next"); var img = document.getElementById("img")[0]; var imgArr = ["img/0.jpg", "img/1.jpg", "img/2.jpg"]; var index = 0; var ingfo = document.getElementById("info"); info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"; prev.onclick = function(){ alert("上一张"); index--; if(index<0){ index = imgArr.length-1; } img.src = imgArr[index]; //每点击一次按钮重新设置信息 info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"; }; next.onclick = function(){ alert("下一张"); index++; if(index>imgArr.length-1){ index = 0; } img.src = imgArr[index]; info.innerHTML = "一共"+imgArr.length+"张图片,当前第"+(index+1)+"张"; }; }
全选练习
window.onload = function(){ //获取四个多选框items var items = document.getElementsByName("items"); //获取全选/全不选的多选框 var checkedAllBox = document.getElementById("checkedAllBox"); /* * 全选按钮 * - 点击按钮以后,四个多选框全都被选中 */ //1.#checkedAllBtn //为id为checkedAllBtn的按钮绑定一个单击响应函数 var checkedAllBtn = document.getElementById("checkedAllBtn"); checkedAllBtn.onclick = function(){ //遍历items for(var i=0 ; i<items.length ; i++){ //通过多选框的checked属性可以来获取或设置多选框的选中状态 //alert(items[i].checked); //设置四个多选框变成选中状态 items[i].checked = true; } //将全选/全不选设置为选中 checkedAllBox.checked = true; }; /* * 全不选按钮 * - 点击按钮以后,四个多选框都变成没选中的状态 */ //2.#checkedNoBtn //为id为checkedNoBtn的按钮绑定一个单击响应函数 var checkedNoBtn = document.getElementById("checkedNoBtn"); checkedNoBtn.onclick = function(){ for(var i=0; i<items.length ; i++){ //将四个多选框设置为没选中的状态 items[i].checked = false; } //将全选/全不选设置为不选中 checkedAllBox.checked = false; }; /* * 反选按钮 * - 点击按钮以后,选中的变成没选中,没选中的变成选中 */ //3.#checkedRevBtn var checkedRevBtn = document.getElementById("checkedRevBtn"); checkedRevBtn.onclick = function(){ //将checkedAllBox设置为选中状态 checkedAllBox.checked = true; for(var i=0; i<items.length ; i++){ //判断多选框状态 /*if(items[i].checked){ //证明多选框已选中,则设置为没选中状态 items[i].checked = false; }else{ //证明多选框没选中,则设置为选中状态 items[i].checked = true; }*/ items[i].checked = !items[i].checked; //判断四个多选框是否全选 //只要有一个没选中则就不是全选 if(!items[i].checked){ //一旦进入判断,则证明不是全选状态 //将checkedAllBox设置为没选中状态 checkedAllBox.checked = false; } } //在反选时也需要判断四个多选框是否全都选中 }; /* * 提交按钮: * - 点击按钮以后,将所有选中的多选框的value属性值弹出 */ //4.#sendBtn //为sendBtn绑定单击响应函数 var sendBtn = document.getElementById("sendBtn"); sendBtn.onclick = function(){ //遍历items for(var i=0 ; i<items.length ; i++){ //判断多选框是否选中 if(items[i].checked){ alert(items[i].value); } } }; //5.#checkedAllBox /* * 全选/全不选 多选框 * - 当它选中时,其余的也选中,当它取消时其余的也取消 * * 在事件的响应函数中,响应函数是给谁绑定的this就是谁 */ //为checkedAllBox绑定单击响应函数 checkedAllBox.onclick = function(){ //alert(this === checkedAllBox); //设置多选框的选中状态 for(var i=0; i <items.length ; i++){ items[i].checked = this.checked; } }; //6.items /* * 如果四个多选框全都选中,则checkedAllBox也应该选中 * 如果四个多选框没都选中,则checkedAllBox也不应该选中 */ //为四个多选框分别绑定点击响应函数 for(var i=0 ; i<items.length ; i++){ items[i].onclick = function(){ //将checkedAllBox设置为选中状态 checkedAllBox.checked = true; for(var j=0 ; j<items.length ; j++){ //判断四个多选框是否全选 //只要有一个没选中则就不是全选 if(!items[j].checked){ //一旦进入判断,则证明不是全选状态 //将checkedAllBox设置为没选中状态 checkedAllBox.checked = false; //一旦进入判断,则已经得出结果,不用再继续执行循环 break; } } }; } };
六、事件对象
当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标 键盘哪个按键被按下 鼠标滚轮滚动的方向。
window.onload = function(){ /* * 当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标 */ //获取两个div var areaDiv = document.getElementById("areaDiv"); var showMsg = document.getElementById("showMsg"); /* * onmousemove * - 该事件将会在鼠标在元素中移动时被触发 * * 事件对象 * - 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响 应函数,在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标 键盘哪个按键被按下 鼠标滚轮滚动的方向。。。 */ areaDiv.onmousemove = function(event){ /* * 在IE8中,响应函数被处罚时,浏览器不会传递事件对象, * 在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的 */ /*if(!event){ event = window.event; }*/ //解决事件对象的兼容性问题 event = event || window.event; /* * clientX可以获取鼠标指针的水平坐标 * cilentY可以获取鼠标指针的垂直坐标 */ var x = event.clientX; var y = event.clientY; //alert("x = "+x + " , y = "+y); //在showMsg中显示鼠标的坐标 showMsg.innerHTML = "x = "+x + " , y = "+y; }; };
div跟随鼠标移动练习
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> #box1{ 100px; height: 100px; background-color: red; /** * 想移动不要忘记开启绝对位置 */ position: absolute; } </style> <script type="application/javascript"> window.onload = function(){ var div = document.getElementById("box1"); div.onmousemove = function(event){ var event = event || window.event; //获取鼠标坐标 var left = event.clientX; var top = event.clientY; //设置div的偏移量 div.style.left = left+"px"; div.style.top = top+"px"; }; //给div绑定是不对的,只有鼠标在div中才能产生移动效果 //绑定到document上 document.onmousemove = function(event){ var event = event || window.event; //获取鼠标坐标 var left = event.clientX; var top = event.clientY; //设置div的偏移量 div.style.left = left+"px"; div.style.top = top+"px"; }; } </script> </head> <body> <div id="box1"></div> </body> </html>
考虑滚动条
clientX和clientY用于获取鼠标在当前可见窗口的坐标
div的偏移量是相对整个页面的
pageX和pageY可以获取鼠标相对当前页面的坐标,但在IE8中不支持
var left = event.pageX; var top = event.pageY;
可用下面方法
window.onload = function(){ var div = document.getElementById("box1"); div.onmousemove = function(event){ var event = event || window.event; //获取滚动条滚动的距离 /** * chrome认为浏览器的滚动条是body,可以通过 *body.scrollTop来获取 * 火狐等浏览器认为滚动条是html的 */ var st = document.body.scrollTop || document.documentElement.scrollTop; var st = document.body.scrollLeft || document.documentElement.scrollLeft; //获取鼠标坐标 var left = event.clientX; var top = event.clientY; //设置div的偏移量 div.style.left = left+"px"; div.style.top = top+st+"px"; }; //给div绑定是不对的,只有鼠标在div中才能产生移动效果 //绑定到document上 document.onmousemove = function(event){ var event = event || window.event; //获取鼠标坐标 var left = event.clientX; var top = event.clientY; //设置div的偏移量 div.style.left = left+"px"; div.style.top = top+"px"; }; }
冒泡
<div id="box1">
我是box1
<span id="s1">我是span</span>
</div>
点击span会发现,div和body同时也发信息。
window.onload = function(){ /* * 事件的冒泡(Bubble) * - 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发 * - 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡 * */ //为s1绑定一个单击响应函数 var s1 = document.getElementById("s1"); s1.onclick = function(event){ event = event || window.event; alert("我是span的单击响应函数"); //取消冒泡 //可以将事件对象的cancelBubble设置为true,即可取消冒泡 event.cancelBubble = true; }; //为box1绑定一个单击响应函数 var box1 = document.getElementById("box1"); box1.onclick = function(event){ event = event || window.event; alert("我是div的单击响应函数"); event.cancelBubble = true; }; //为body绑定一个单击响应函数 document.body.onclick = function(){ alert("我是body的单击响应函数"); }; };
事件委派
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> window.onload = function(){ var u1 = document.getElementById("u1"); //点击按钮以后添加超链接 var btn01 = document.getElementById("btn01"); btn01.onclick = function(){ //创建一个li var li = document.createElement("li"); li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>"; //将li添加到ul中 u1.appendChild(li); }; /* * 为每一个超链接都绑定一个单击响应函数 * 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦, * 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定 */ //获取所有的a var allA = document.getElementsByTagName("a"); //遍历 /*for(var i=0 ; i<allA.length ; i++){ allA[i].onclick = function(){ alert("我是a的单击响应函数!!!"); }; }*/ /* * 我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的 * 我们可以尝试将其绑定给元素的共同的祖先元素 * * 事件的委派 * - 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素 * 从而通过祖先元素的响应函数来处理事件。 * - 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能 */ //为ul绑定一个单击响应函数 u1.onclick = function(event){ event = event || window.event; /* * target * - event中的target表示的触发事件的对象 */ //alert(event.target); //如果触发事件的对象是我们期望的元素,则执行否则不执行 if(event.target.className == "link"){ alert("我是ul的单击响应函数"); } }; }; </script> </head> <body> <button id="btn01">添加超链接</button> <ul id="u1" style="background-color: #bfa;"> <li> <p>我是p元素</p> </li> <li><a href="javascript:;" class="link">超链接一</a></li> <li><a href="javascript:;" class="link">超链接二</a></li> <li><a href="javascript:;" class="link">超链接三</a></li> </ul> </body> </html>
事件的绑定
window.onload = function(){ /* * 点击按钮以后弹出一个内容 */ //获取按钮对象 var btn01 = document.getElementById("btn01"); /* * 使用 对象.事件 = 函数 的形式绑定响应函数, * 它只能同时为一个元素的一个事件绑定一个响应函数, * 不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的 */ //为btn01绑定一个单击响应函数 /*btn01.onclick = function(){ alert(1); };*/ //为btn01绑定第二个响应函数 会覆盖前面的 /*btn01.onclick = function(){ alert(2); };*/ /* * addEventListener() * - 通过这个方法也可以为元素绑定响应函数 * - 参数: * 1.事件的字符串,不要on * 2.回调函数,当事件触发时该函数会被调用 * 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false * * 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数, * 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行 * * 这个方法不支持IE8及以下的浏览器 */ /*btn01.addEventListener("click",function(){ alert(1); },false); btn01.addEventListener("click",function(){ alert(2); },false); btn01.addEventListener("click",function(){ alert(3); },false);*/ /* * attachEvent() * - 在IE8中可以使用attachEvent()来绑定事件 * - 参数: * 1.事件的字符串,要on * 2.回调函数 * * - 这个方法也可以同时为一个事件绑定多个处理函数, * 不同的是它是后绑定先执行,执行顺序和addEventListener()相反 */ /*btn01.attachEvent("onclick",function(){ alert(1); }); btn01.attachEvent("onclick",function(){ alert(2); }); btn01.attachEvent("onclick",function(){ alert(3); });*/ /*btn01.addEventListener("click",function(){ alert(this); },false);*/ /*btn01.attachEvent("onclick",function(){ alert(this); });*/ bind(btn01 , "click" , function(){ alert(this); }); }; //定义一个函数,用来为指定元素绑定响应函数 /* * addEventListener()中的this,是绑定事件的对象 * attachEvent()中的this,是window * 需要统一两个方法this */ /* * 参数: * obj 要绑定事件的对象 * eventStr 事件的字符串(不要on) * callback 回调函数 */ function bind(obj , eventStr , callback){ if(obj.addEventListener){ //大部分浏览器兼容的方式 obj.addEventListener(eventStr , callback , false); }else{ /* * this是谁由调用方式决定 * callback.call(obj) */ //IE8及以下 obj.attachEvent("on"+eventStr , function(){ //在匿名函数中调用回调函数 callback.call(obj); }); } }
事件的传播
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box1{ 300px; height: 300px; background-color: yellowgreen; } #box2{ 200px; height: 200px; background-color: yellow; } #box3{ 150px; height: 150px; background-color: skyblue; } </style> <script type="text/javascript"> window.onload = function(){ /* * 分别为三个div绑定单击响应函数 */ var box1 = document.getElementById("box1"); var box2 = document.getElementById("box2"); var box3 = document.getElementById("box3"); /* * 事件的传播 - 关于事件的传播网景公司和微软公司有不同的理解 - 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的 事件, 然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。 - 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元 素的最外层的祖先元素的事件, 然后在向内传播给后代元素 - W3C综合了两个公司的方案,将事件传播分成了三个阶段 1.捕获阶段 - 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时 不会触发事件 2.目标阶段 - 事件捕获到目标元素,捕获结束开始在目标元素上触发事件 3.冒泡阶段 - 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件 * - 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false * * - IE8及以下的浏览器中没有捕获阶段 */ bind(box1,"click",function(){ alert("我是box1的响应函数") }); bind(box2,"click",function(){ alert("我是box2的响应函数") }); bind(box3,"click",function(){ alert("我是box3的响应函数") }); }; function bind(obj , eventStr , callback){ if(obj.addEventListener){ //大部分浏览器兼容的方式 obj.addEventListener(eventStr , callback , true); }else{ /* * this是谁由调用方式决定 * callback.call(obj) */ //IE8及以下 obj.attachEvent("on"+eventStr , function(){ //在匿名函数中调用回调函数 callback.call(obj); }); } } </script> </head> <body> <div id="box1"> <div id="box2"> <div id="box3"></div> </div> </div> </body> </html>
拖拽练习
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box1{ 100px; height: 100px; background-color: red; position: absolute; } #box2{ 100px; height: 100px; background-color: yellow; position: absolute; left: 200px; top: 200px; } </style> <script type="text/javascript"> window.onload = function(){ /* * 拖拽box1元素 * - 拖拽的流程 1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown 2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove 3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup */ //获取box1 var box1 = document.getElementById("box1"); //为box1绑定一个鼠标按下事件 //当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown box1.onmousedown = function(event){ event = event || window.event; //div的偏移量 鼠标.clentX - 元素.offsetLeft //div的偏移量 鼠标.clentY - 元素.offsetTop var ol = event.clientX - box1.offsetLeft; var ot = event.clientY - box1.offsetTop; //为document绑定一个onmousemove事件 document.onmousemove = function(event){ event = event || window.event; //当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove //获取鼠标的坐标 var left = event.clientX - ol; var top = event.clientY - ot; //修改box1的位置 box1.style.left = left+"px"; box1.style.top = top+"px"; }; //为document绑定一个鼠标松开事件 document.onmouseup = function(){ //当鼠标松开时,被拖拽元素固定在当前位置 onmouseup //取消document的onmousemove事件 document.onmousemove = null; //取消document的onmouseup事件 document.onmouseup = null; }; }; }; </script> </head> <body> <div id="box1"></div> <div id="box2"></div> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box1{ 100px; height: 100px; background-color: red; position: absolute; } #box2{ 100px; height: 100px; background-color: yellow; position: absolute; left: 200px; top: 200px; } </style> <script type="text/javascript"> window.onload = function(){ /* * 拖拽box1元素 * - 拖拽的流程 1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown 2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove 3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup */ //获取box1 var box1 = document.getElementById("box1"); var box2 = document.getElementById("box2"); //为box1绑定一个鼠标按下事件 //当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown box1.onmousedown = function(event){ //设置box1捕获所有鼠标按下的事件 /* * setCapture() * - 只有IE支持,但是在火狐中调用时不会报错, * 而如果使用chrome调用,会报错 */ /*if(box1.setCapture){ box1.setCapture(); }*/ box1.setCapture && box1.setCapture(); event = event || window.event; //div的偏移量 鼠标.clentX - 元素.offsetLeft //div的偏移量 鼠标.clentY - 元素.offsetTop var ol = event.clientX - box1.offsetLeft; var ot = event.clientY - box1.offsetTop; //为document绑定一个onmousemove事件 document.onmousemove = function(event){ event = event || window.event; //当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove //获取鼠标的坐标 var left = event.clientX - ol; var top = event.clientY - ot; //修改box1的位置 box1.style.left = left+"px"; box1.style.top = top+"px"; }; //为document绑定一个鼠标松开事件 document.onmouseup = function() //不能给box绑定,只能给document绑定 //当鼠标松开时,被拖拽元素固定在当前位置 onmouseup //取消document的onmousemove事件 document.onmousemove = null; //取消document的onmouseup事件 document.onmouseup = null; //当鼠标松开时,取消对事件的捕获 box1.releaseCapture && box1.releaseCapture(); }; /* * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容, * 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为, * 如果不希望发生这个行为,则可以通过return false来取消默认行为 * * 但是这招对IE8不起作用 */ return false; }; }; </script> </head> <body> 我是一段文字 <div id="box1"></div> <div id="box2"></div> </body> </html>
滚轮事件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box1{ 100px; height: 100px; background-color: red; } </style> <script type="text/javascript"> window.onload = function(){ //获取id为box1的div var box1 = document.getElementById("box1"); //为box1绑定一个鼠标滚轮滚动的事件 /* * onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发, * 但是火狐不支持该属性 * * 在火狐中需要使用 DOMMouseScroll 来绑定滚动事件 * 注意该事件需要通过addEventListener()函数来绑定 */ box1.onmousewheel = function(event){ event = event || window.event; //event.wheelDelta 可以获取鼠标滚轮滚动的方向 //向上滚 120 向下滚 -120 //wheelDelta这个值我们不看大小,只看正负 //alert(event.wheelDelta); //wheelDelta这个属性火狐中不支持 //在火狐中使用event.detail来获取滚动的方向 //向上滚 -3 向下滚 3 //alert(event.detail); /* * 当鼠标滚轮向下滚动时,box1变长 * 当滚轮向上滚动时,box1变短 */ //判断鼠标滚轮滚动的方向 if(event.wheelDelta > 0 || event.detail < 0){ //向上滚,box1变短 box1.style.height = box1.clientHeight - 10 + "px"; }else{ //向下滚,box1变长 box1.style.height = box1.clientHeight + 10 + "px"; } /* * 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false * 需要使用event来取消默认行为event.preventDefault(); * 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错 */ event.preventDefault && event.preventDefault(); /* * 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动, * 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为 */ return false; }; //为火狐绑定滚轮事件 bind(box1,"DOMMouseScroll",box1.onmousewheel); }; function bind(obj , eventStr , callback){ if(obj.addEventListener){ //大部分浏览器兼容的方式 obj.addEventListener(eventStr , callback , false); }else{ /* * this是谁由调用方式决定 * callback.call(obj) */ //IE8及以下 obj.attachEvent("on"+eventStr , function(){ //在匿名函数中调用回调函数 callback.call(obj); }); } } </script> </head> <body style="height: 2000px;"> <div id="box1"></div> </body> </html>
键盘事件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> window.onload = function(){ /* * 键盘事件: * onkeydown * - 按键被按下 * - 对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发 * - 当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快 * 这种设计是为了防止误操作的发生。 * onkeyup * - 按键被松开 * * 键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document */ document.onkeydown = function(event){ event = event || window.event; /* * 可以通过keyCode来获取按键的编码 * 通过它可以判断哪个按键被按下 * 除了keyCode,事件对象中还提供了几个属性 * altKey * ctrlKey * shiftKey * - 这个三个用来判断alt ctrl 和 shift是否被按下 * 如果按下则返回true,否则返回false */ //console.log(event.keyCode); //判断一个y是否被按下 //判断y和ctrl是否同时被按下 if(event.keyCode === 89 && event.ctrlKey){ console.log("ctrl和y都被按下了"); } }; /*document.onkeyup = function(){ console.log("按键松开了"); };*/ //获取input var input = document.getElementsByTagName("input")[0]; input.onkeydown = function(event){ event = event || window.event; //console.log(event.keyCode); //数字 48 - 57 //使文本框中不能输入数字 if(event.keyCode >= 48 && event.keyCode <= 57){ //在文本框中输入内容,属于onkeydown的默认行为 //如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中 return false; } }; }; </script> </head> <body> <input type="text" /> </body> </html>
七、BOM
浏览器对象模型
BOM可以使我们同JS操作浏览器
BOM对象
Window
代表整个浏览器的窗口,同时也是网页中中的全局对象。
Navigator
代表当前浏览器的信息,通过该对象可识别不同的浏览器。
Location
代表浏览器的地址栏信息,通过该对象可以获取地址栏信息,或者操作浏览器操作页面。
History
代表当前浏览器的历史记录,可以通过该对象操作浏览器历史记录,由于隐私原因,该对象不能获取到具体的历史记录,只能操作向前或向后翻页,且只在当次打开浏览器时有效。
Screen
代表用户的屏幕信息,通过该对象可以获取到用户的显示器的相关信息。
这些 BOM对象在浏览器中都是作为window对象的属性保存的。可以通过window对象来使用,也可以直接使用Navigator代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器。由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了,一般我们只会使用userAgent来判断浏览器的信息,userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的。
userAgent
火狐的userAgent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0 Chrome的userAgent Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 IE8 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) IE9 Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) IE10 Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) IE11 Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko - 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
实例
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> /* * BOM * - 浏览器对象模型 * - BOM可以使我们通过JS来操作浏览器 * - 在BOM中为我们提供了一组对象,用来完成对浏览器的操作 * - BOM对象 * Window * - 代表的是整个浏览器的窗口,同时window也是网页中的全局对象 * Navigator * - 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器 * Location * - 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面 * History * - 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录 * 由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页 * 而且该操作只在当次访问时有效 * Screen * - 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息 * * * 这些BOM对象在浏览器中都是作为window对象的属性保存的, * 可以通过window对象来使用,也可以直接使用 * * */ //console.log(navigator); //console.log(location); //console.log(history); /* * Navigator * - 代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器 * - 由于历史原因,Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了 * - 一般我们只会使用userAgent来判断浏览器的信息, * userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容, * 不同的浏览器会有不同的userAgent * * 火狐的userAgent * Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0 * * Chrome的userAgent * Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 * * IE8 * Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) * * IE9 * Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) * * IE10 * Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E) * * IE11 * Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko * - 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了 */ //alert(navigator.appName); var ua = navigator.userAgent; console.log(ua); if(/firefox/i.test(ua)){ alert("你是火狐!!!"); }else if(/chrome/i.test(ua)){ alert("你是Chrome"); }else if(/msie/i.test(ua)){ alert("你是IE浏览器~~~"); }else if("ActiveXObject" in window){ alert("你是IE11,枪毙了你~~~"); } /* * 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息 * 比如:ActiveXObject */ /*if("ActiveXObject" in window){ alert("你是IE,我已经抓住你了~~~"); }else{ alert("你不是IE~~~"); }*/ /*alert("ActiveXObject" in window);*/ </script> </head> <body> </body> </html>
<script type="text/javascript"> window.onload = function(){ //获取count var count = document.getElementById("count"); //使count中的内容,自动切换 /* * JS的程序的执行速度是非常非常快的 * 如果希望一段程序,可以每间隔一段时间执行一次,可以使用定时调用 */ /*for(var i=0 ; i<10000 ; i++){ count.innerHTML = i; alert("hello"); }*/ /* * setInterval() * - 定时调用 * - 可以将一个函数,每隔一段时间执行一次 * - 参数: * 1.回调函数,该函数会每隔一段时间被调用一次 * 2.每次调用间隔的时间,单位是毫秒 * * - 返回值: * 返回一个Number类型的数据 * 这个数字用来作为定时器的唯一标识 */ var num = 1; var timer = setInterval(function(){ count.innerHTML = num++; if(num == 11){ //关闭定时器 clearInterval(timer); } },1000); //console.log(timer); //clearInterval()可以用来关闭一个定时器 //方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器 //clearInterval(timer); }; </script> </head> <body> <h1 id="count"></h1> </body>
定时器
<html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } #box1{ 100px; height: 100px; background-color: red; position: absolute; left: 0; //后面要用到该属性,显示指定,否则ie8可能是auto } </style> <script type="text/javascript"> window.onload = function(){ //获取box1 var box1 = document.getElementById("box1"); //获取btn01 var btn01 = document.getElementById("btn01"); //定义一个变量,用来保存定时器的标识 var timer; //点击按钮以后,使box1向右移动(left值增大) btn01.onclick = function(){ //关闭上一个定时器 clearInterval(timer); //开启一个定时器,用来执行动画效果 timer = setInterval(function(){ //获取box1的原来的left值 var oldValue = parseInt(getStyle(box1,"left")); //后面有px, //要转为数字,用parseInt() //在旧值的基础上增加 var newValue = oldValue + 1; //判断newValue是否大于800 //如果不是加1,很有可能不断增加后,不会等于800,也就没法停止 if(newValue > 800){ newValue = 800; } //将新值设置给box1 box1.style.left = newValue + "px"; //当元素移动到800px时,使其停止执行动画 if(newValue == 800){ //达到目标,关闭定时器 clearInterval(timer); } },30); }; }; /* * 定义一个函数,用来获取指定元素的当前的样式 * 参数: * obj 要获取样式的元素 * name 要获取的样式名 */ function getStyle(obj , name){ if(window.getComputedStyle){ //正常浏览器的方式,具有getComputedStyle()方法 return getComputedStyle(obj , null)[name]; }else{ //IE8的方式,没有getComputedStyle()方法 return obj.currentStyle[name]; } } </script> </head> <body> <button id="btn01">点击按钮以后box1向右移动</button> <br /><br /> <div id="box1"></div> <div style=" 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div> </body> </html>
定时器2
<html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } #box1{ 100px; height: 100px; background-color: red; position: absolute; left: 0; } </style> <script type="text/javascript"> window.onload = function(){ //获取box1 var box1 = document.getElementById("box1"); //获取btn01 var btn01 = document.getElementById("btn01"); //获取btn02 var btn02 = document.getElementById("btn02"); //点击按钮以后,使box1向右移动(left值增大) btn01.onclick = function(){ move(box1 , 800 , 10); }; //点击按钮以后,使box1向左移动(left值减小) btn02.onclick = function(){ move(box1 , 0 , 10); }; }; //定义一个变量,用来保存定时器的标识 var timer; //尝试创建一个可以执行简单动画的函数 /* * 参数: * obj:要执行动画的对象 * target:执行动画的目标位置 * speed:移动的速度(正数向右移动,负数向左移动) */ function move(obj , target ,speed){ //关闭上一个定时器 clearInterval(timer); //获取元素目前的位置 var current = parseInt(getStyle(obj,"left")); //判断速度的正负值 //如果从0 向 800移动,则speed为正 //如果从800向0移动,则speed为负 if(current > target){ //此时速度应为负值 speed = -speed; } //开启一个定时器,用来执行动画效果 timer = setInterval(function(){ //获取box1的原来的left值 var oldValue = parseInt(getStyle(obj,"left")); //在旧值的基础上增加 var newValue = oldValue + speed; //判断newValue是否大于800 //从800 向 0移动 //向左移动时,需要判断newValue是否小于target //向右移动时,需要判断newValue是否大于target if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){ newValue = target; } //将新值设置给box1 obj.style.left = newValue + "px"; //当元素移动到0px时,使其停止执行动画 if(newValue == target){ //达到目标,关闭定时器 clearInterval(timer); } },30); } /* * 定义一个函数,用来获取指定元素的当前的样式 * 参数: * obj 要获取样式的元素 * name 要获取的样式名 */ function getStyle(obj , name){ if(window.getComputedStyle){ //正常浏览器的方式,具有getComputedStyle()方法 return getComputedStyle(obj , null)[name]; }else{ //IE8的方式,没有getComputedStyle()方法 return obj.currentStyle[name]; } } </script> </head> <body> <button id="btn01">点击按钮以后box1向右移动</button> <button id="btn02">点击按钮以后box1向左移动</button> <br /><br /> <div id="box1"></div> <div style=" 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div> </body> </html>
定时器3
<html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } #box1{ 100px; height: 100px; background-color: red; position: absolute; left: 0; } #box2{ 100px; height: 100px; background-color: yellow; position: absolute; left: 0; top: 200px; } </style> <script type="text/javascript" src="js/tools.js"></script> <script type="text/javascript"> window.onload = function(){ //获取box1 var box1 = document.getElementById("box1"); //获取btn01 var btn01 = document.getElementById("btn01"); //获取btn02 var btn02 = document.getElementById("btn02"); //点击按钮以后,使box1向右移动(left值增大) btn01.onclick = function(){ move(box1 ,"left", 800 , 20); }; //点击按钮以后,使box1向左移动(left值减小) btn02.onclick = function(){ move(box1 ,"left", 0 , 10); }; //获取btn03 var btn03 = document.getElementById("btn03"); btn03.onclick = function(){ move(box2 , "left",800 , 10); }; //测试按钮 var btn04 = document.getElementById("btn04"); btn04.onclick = function(){ //move(box2 ,"width", 800 , 10); //move(box2 ,"top", 800 , 10); //move(box2 ,"height", 800 , 10); move(box2 , "width" , 800 , 10 , function(){ move(box2 , "height" , 400 , 10 , function(){ move(box2 , "top" , 0 , 10 , function(){ move(box2 , "width" , 100 , 10 , function(){ }); }); }); }); }; }; //定义一个变量,用来保存定时器的标识 /* * 目前我们的定时器的标识由全局变量timer保存, * 所有的执行正在执行的定时器都在这个变量中保存 */ //var timer; </script> </head> <body> <button id="btn01">点击按钮以后box1向右移动</button> <button id="btn02">点击按钮以后box1向左移动</button> <button id="btn03">点击按钮以后box2向右移动</button> <button id="btn04">测试按钮</button> <br /><br /> <div id="box1"></div> <div id="box2"></div> <div style=" 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div> </body> </html>
//尝试创建一个可以执行简单动画的函数 /* * 参数: * obj:要执行动画的对象 * attr:要执行动画的样式,比如:left top width height * target:执行动画的目标位置 * speed:移动的速度(正数向右移动,负数向左移动) * callback:回调函数,这个函数将会在动画执行完毕以后执行 */ function move(obj, attr, target, speed, callback) { //关闭上一个定时器 clearInterval(obj.timer); //获取元素目前的位置 var current = parseInt(getStyle(obj, attr)); //判断速度的正负值 //如果从0 向 800移动,则speed为正 //如果从800向0移动,则speed为负 if(current > target) { //此时速度应为负值 speed = -speed; } //开启一个定时器,用来执行动画效果 //向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识 obj.timer = setInterval(function() { //获取box1的原来的left值 var oldValue = parseInt(getStyle(obj, attr)); //在旧值的基础上增加 var newValue = oldValue + speed; //判断newValue是否大于800 //从800 向 0移动 //向左移动时,需要判断newValue是否小于target //向右移动时,需要判断newValue是否大于target if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) { newValue = target; } //将新值设置给box1 obj.style[attr] = newValue + "px"; //当元素移动到0px时,使其停止执行动画 if(newValue == target) { //达到目标,关闭定时器 clearInterval(obj.timer); //动画执行完毕,调用回调函数 callback && callback(); } }, 30); } /* * 定义一个函数,用来获取指定元素的当前的样式 * 参数: * obj 要获取样式的元素 * name 要获取的样式名 */ function getStyle(obj, name) { if(window.getComputedStyle) { //正常浏览器的方式,具有getComputedStyle()方法 return getComputedStyle(obj, null)[name]; } else { //IE8的方式,没有getComputedStyle()方法 return obj.currentStyle[name]; } }
轮播图
<html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } /* * 设置outer的样式 */ #outer{ /*设置宽和高*/ 520px; height: 333px; /*居中*/ margin: 50px auto; /*设置背景颜色*/ background-color: greenyellow; /*设置padding*/ padding: 10px 0; /*开启相对定位*/ position: relative; /*裁剪溢出的内容*/ overflow: hidden; } /*设置imgList*/ #imgList{ /*去除项目符号*/ list-style: none; /*设置ul的宽度*/ /* 2600px;*/ /*开启绝对定位*/ position: absolute; /*设置偏移量*/ /* * 每向左移动520px,就会显示到下一张图片 */ left: 0px; } /*设置图片中的li*/ #imgList li{ /*设置浮动*/ float: left; /*设置左右外边距*/ margin: 0 10px; } /*设置导航按钮*/ #navDiv{ /*开启绝对定位*/ position: absolute; /*设置位置*/ bottom: 15px; /*设置left值 outer宽度 520 navDiv宽度 25*5 = 125 520 - 125 = 395/2 = 197.5 * */ /*left: 197px;*/ } #navDiv a{ /*设置超链接浮动*/ float: left; /*设置超链接的宽和高*/ 15px; height: 15px; /*设置背景颜色*/ background-color: red; /*设置左右外边距*/ margin: 0 5px; /*设置透明*/ opacity: 0.5; /*兼容IE8透明*/ filter: alpha(opacity=50); } /*设置鼠标移入的效果*/ #navDiv a:hover{ background-color: black; } </style> <!--引用工具--> <script type="text/javascript" src="js/tools.js"></script> <script type="text/javascript"> window.onload = function(){ //获取imgList var imgList = document.getElementById("imgList"); //获取页面中所有的img标签 var imgArr = document.getElementsByTagName("img"); //设置imgList的宽度 imgList.style.width = 520*imgArr.length+"px"; /*设置导航按钮居中*/ //获取navDiv var navDiv = document.getElementById("navDiv"); //获取outer var outer = document.getElementById("outer"); //设置navDiv的left值 navDiv.style.left = (outer.offsetWidth - navDiv.offsetWidth)/2 + "px"; //默认显示图片的索引 var index = 0; //获取所有的a var allA = document.getElementsByTagName("a"); //设置默认选中的效果 allA[index].style.backgroundColor = "black"; /* 点击超链接切换到指定的图片 点击第一个超链接,显示第一个图片 点击第二个超链接,显示第二个图片 * */ //为所有的超链接都绑定单击响应函数 for(var i=0; i<allA.length ; i++){ //为每一个超链接都添加一个num属性 allA[i].num = i; //为超链接绑定单击响应函数 allA[i].onclick = function(){ //获取点击超链接的索引,并将其设置为index index = this.num; //切换图片 /* * 第一张 0 0 * 第二张 1 -520 * 第三张 2 -1040 */ //imgList.style.left = -520*index + "px"; //设置选中的a setA(); //使用move函数来切换图片 move(imgList , "left" , -520*index , 20 , function(){ }); }; } //创建一个方法用来设置选中的a function setA(){ //遍历所有a,并将它们的背景颜色设置为红色 for(var i=0 ; i<allA.length ; i++){ // 空,就使用css中设定的默认样式 allA[i].style.backgroundColor = ""; } //将选中的a设置为黑色 allA[index].style.backgroundColor = "black"; }; }; </script> </head> <body> <!-- 创建一个外部的div,来作为大的容器 --> <div id="outer"> <!-- 创建一个ul,用于放置图片 --> <ul id="imgList"> <li><img src="img/1.jpg"/></li> <li><img src="img/2.jpg"/></li> <li><img src="img/3.jpg"/></li> <li><img src="img/4.jpg"/></li> <li><img src="img/5.jpg"/></li> </ul> <!--创建导航按钮--> <div id="navDiv"> <a href="javascript:;"></a> <a href="javascript:;"></a> <a href="javascript:;"></a> <a href="javascript:;"></a> <a href="javascript:;"></a> </div> </div> </body> </html>