JavaScript笔记
- 【视频链接】【尚硅谷】JavaScript基础&实战丨JS入门到精通全套完整版
- 【转载】课件、源码和笔记
JS书写位置
- 内部:可以将JS代码编写到onclick属性中,当我们点击按钮时,JS代码才会执行;将JS代码写在超链接的href属性中,这样当点击超链接时,会执行JS代码。虽然可以写在标签的属性中,但是它们属于结构与行为耦合,不方便维护,不推荐使用
- 外部:可以将JS文件编写到外部JS文件中,然后通过script标签引入。写到外部文件中可以在不同的页面同时应用,也可以利用到浏览器的缓存机制
- script标签一旦用于引入外部文件了,就不能再编写代码了,即使编写了浏览器也会忽略,如果需要则可以再创建一个新的script标签用于编写内部代码
JS基本语法
- JS注释
- 多行注释
/**/
- 单行注释
//
- 多行注释
- 每一条语句以分号结尾,如果不写分号,浏览器会自动添加,但是会消耗一些系统资源。而且有些时候,浏览器会加错分号
- 字面量和变量
- 字面量:不可改变的值,常量,比如1, 2, ‘hello’,字面量可以直接使用。但是一般不会直接使用字面量
- 变量:可以用来保存字面量,值可以任意改变,更加方便我们使用,在开发中都是通过变量去保存一个字面量,而很少直接使用字面量
- 声明变量:
var a;
var a = 1; alert(a);
- 标识符
- 在JS中所有可以有我们自主命名的都可以称为是标识符,例如变量名、函数名、属性名
- 在命名时遵守的规则
- 可以含有字母、数字、_、$,如
var a = a_1_$ = 123;
- 标识符不能以数字开头
- 不能是ES中的关键字或保留字
- 标识符一般采用驼峰命名法
- 可以含有字母、数字、_、$,如
- JS底层保存标识符时,采用的是Unicode编码,所以理论上讲所有的utf-8字符都可以作为标识符
数据类型
- 在JS中一共有6种数据类型,可以使用
typeof
来检查一个变量的类型- String 字符串
- 使用引号引起来,
var str = 'hello';
- 使用双引号或者单引号都可以,但是不要混着用
- 使用
\
作为转义字符,如\"
表示一个双引号,\'
表示单引号,\n
表示换行,\t
表示制表符,\\
表示\
- 使用引号引起来,
- Number 数值
- 所有数值都是Number类型
- 可以表示的数字的最大值
Number.MAX_VALUE = 1.7976931348623157e+308
,超过则为Infinity
,表示正无穷。使用typeof
检查typeof Infinity
也返回Number
,但是typeof "Infinity"
返回String NaN
是一个特殊的数字,表示Not A Number,typeof(NaN)
同样会返回Number- 可以表示的最小正数为
5e-324
- 使用JS进行浮点运算可能得到一个不精确的结果,所以千万不要使用JS进行对精确度要求高的浮点计算
- Boolean 布尔值
true
和false
- Null 空值
- 只有一个值
null
,表示一个空的对象
- 只有一个值
- Undefined 未定义
- 只有一个值
undefined
,当声明一个变量,但是并不给变量赋值时,它的值就是undefined
- 只有一个值
- Object 对象
- String 字符串
- 强制类型转换
- 将其他的数据类型转换为String
- 方式一:调用被转换数据类型的
toString()
方法var a = 123; a.toString();
- 该方法不会影响到原变量,它会将转换的结果返回
null
和undefined
这两个值没有toString()
方法,如果调用它们的这个方法会报错,因此只适用于数值和Boolean
- 方式二:调用String函数
- 该函数对
null
和undefined
等都适用 - 对于Number和Boolean实际上就是使用的
toString()
方法
- 该函数对
- 方式一:调用被转换数据类型的
- 将其他数据类型转换为Number
- 方式一:使用
Number()
函数- 对于字符串转数字,如果是纯数字的字符串,则直接将其转换为数字;如果字符串中有非数字的内容,则转换为NaN;如果字符串是一个空串或者是一个全是空格的字符串则返回0
- 对于布尔值,true转成1,false转成0
- Null转成数字结果为0
- Undefined转成数字是NaN
- 方式二:这种专门用来对付字符串
parseInt()
:把一个字符串转换成一个整数。- 可以把字符串中的有效整数内容提取出来,然后转换成Number
parseInt(123px)
返回123,parseInt(123p456px)
返回123- 可以利用这个函数取整
parseFloat()
:把一个字符串转换成一个小数parseFloat(123.456.789px)
返回123.456
- 如果对非String使用
parseInt
或者parseFloat
都返回NaN
- 方式一:使用
- 其他进制的数字
- 16进制:
0x123
(0x开头) - 8进制:
070
(0开头)- 像
"070"
这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析 - 在使用
parseInt()
时可以传递第二个参数表示进制,如parseInt('070', 8)
- 像
- 2进制:
0b101
(0b开头,浏览器不兼容)
- 16进制:
- 其他类型转换为Boolean
Boolean()
函数- 数字转布尔:除了0和NaN是false以外,其余都是true
- 字符串转布尔:除了空串,其余都是true
- null和undefined都会转换为false
- 整理:转换为false的情况:0, NaN, 空串, null, undefined, object
- 隐式转换:连续取两次反
- 将其他的数据类型转换为String
运算符
+, -, *, /, %
- 当对非number类型的值进行运算时,会先转换为number类型然后再进行运算。字符串加法除外
- 两个字符串相加直接拼接,任何值和字符串做加法运算,都会先转换为字符串然后再拼串。
- 可以利用这个特点将任意类型的数据类型转换为String,即:为任意的数据类型+一个空船即可转换为String,这是一个隐式的类型转换,由浏览器自动完成,实际上它是调用String函数完成的
- 同样可以利用“任何值和数值进行
-, *, /
运算都是先转换为数值类型”将该类型转换为数值类型,如var a = '123'; a = a - 0;
或者var a = '123'; a = a / 1;
- 任何数和NaN运算都是NaN
- 一元运算符
+, -
:正负号var a = 123; a = +a; a = -a;
- 对于非Number类型的值,会先转换成Number类型然后再进行运算
- 自增/自减:
++a, a++, --a, a--
- 逻辑运算符:
!, &&, ||
&&, ||
与非布尔值的运算- 对于与非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且返回原值
- 与运算
- 如果第一个值为treu,则必然返回第二个值
- 如果第一个值为false,则必然返回第一个值
- 或运算
- 如果第一个值为true,则直接返回第一个值
- 如果第一个值为false,则返回第二个值
- 赋值运算符:
=, +=, -=, *=, /=, %=
- 关系运算符:
>, <, >=, <=
- 对于非数值进行比较时,会将其转换为数字然后再进行比较
- 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而是分别比较Unicode编码
1 > true // false 1 >= true // true 1 > '0' // true 10 > null // true // 任何值和NaN做任何比较都是false 10 <= 'hello' // false '1' < '5' // true '11' < '5' // true -> 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而是分别比较Unicode编码 // 比较字符编码时,是一位一位进行比较,可以借用它来对英文进行排序 'abc' < 'b' // true // 注意:在比较两个字符串型的数字时,一定要注意转型 '11' < '5' // true '11' < +'5' // false
- 补充:Unicode编码
console.log('\uxxxx')
输出Unicode编码xxxx对应的字符- 在网页中使用Unicode编码:
&#编码
,这里的编码需要的是10进制
- 相等运算符:
==, !=
- 如果值的类型不同,会自动进行类型转换,然后再进行比较
null == 0
返回false- undefined衍生自null,所以这两个值做相等判断时,会返回true
- NaN不和任何值相等,包括本身
- 判断一个值是否是NaN:
isNaN()
函数var a = NaN; console.log(isNaN(a));
- 判断一个值是否是NaN:
===, !==
:全等,和相等类似,但是会首先判断类型是否相等,不会进行自动类型转换
- 条件运算符:三元运算符
- 条件表达式 ? 语句1 : 语句2;
- 逗号运算符
- 使用
,
可以分解多个语句,一般在声明多个变量时使用 var a, b, c; var a = 1, b = 2, c = 3;
- 使用
- 运算符优先级
- 举例:
var result = 1 || 2 && 3
- 如果或的优先级高,则返回3
- 如果与的优先级高,则返回1
- 参考运算符优先级表
- 如果遇到优先级不清楚的,使用括号改变优先级
- 举例:
语句和流程控制
- 几个常用语句
alert('hello'); console.log('hello'); document.write('hello');
- 代码块
- 一个
{}
中的语句称为代码块,要么都执行,要么都不执行,代码块后面不写;
- 代码块只具有分组的作用,没有其他的用途,内部的内容在外部是完全可见的
- 一个
- 条件判断语句
if
// 语法一 if(条件表达式) 语句; // 语法二 if(条件表达式) 语句1; else 语句2; // 语法三 if(条件表达式){ 语句1; }else if(条件表达式){ 语句2; }else if(条件表达式){ 语句; }
- 条件分支语句-switch
switch(条件表达式){ case 表达式: 语句... break; case 表达式: 语句... break; default: 语句... break; }
- 循环语句
- while循环
// while while(条件表达式){ 语句... } // do-while do { 语句... }while(条件表达式);
- for 循环
for(初始表达式; 条件表达式; 更新表达式){ 语句... } for(var i = 0; i < 10; i++){ alert(i); } for(;;){ alert('这是一个死循环); }
- while循环
对象
- 来源
- 如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体:
var name = '小明'; var gender = '男'; var age = 18;
- 对象属于一种复合的数据类型,在对象中可以保存多个不同的数据类型的属性
- 如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体:
- 分类
- 内建对象:ES标准定义的对象,在任何ES实现中都可以使用
Math String Number Boolean Function Object
等
- 宿主对象:由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,比如BOM, DOM
console, document
- 自定义对象:由开发人员自己创建的对象
- 内建对象:ES标准定义的对象,在任何ES实现中都可以使用
- 创建对象
- 使用
new
关键字调用的函数,是构造函数。构造函数是专门用来创建对象的函数var obj = new Object();
- 使用对象字面量,即使用
{}
来创建var obj = {};
- 使用对象字面量来创建对象时,可以直接指定对象中的属性,多个名值对之间用
,
隔开:var obj = { name:'小明', age: 18, in_obj: {score: 20} };
- 对象字面量的属性名可以加引号也可以不加,建议不加,如果要使用一些特殊的名字,则必须加引号
- 使用
- 向对象添加属性
对象.属性名 = 属性值
obj.name = '小明'; obj.gender = '男'; obj.age = 18; // 读取属性值 console.log(obj.name); // 如果读取随想没有的属性,不会报错而是会返回undefined console.log(obj.hello); // 修改属性值 obj.age = 20; // 删除对象属性 delete obj.age;// 或者delete(obj.age);
- 对象的属性名不强制要求遵守标识符规范,什么乱七八糟的名字都可以使用,但是使用时还是尽量按照标识符的规范去做。如果要使用特殊的属性名,不能采用.的方式来操作,而是使用
对象['属性名'] = 属性值
的方式
- 存储
- 基本数据类型保存在栈内存中,值与值之间是独立存在的,修修改一个变量不会影响其他的变量
- 对象是保存在堆内存中,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象的引用,当通过一个变量修改属性值时,另一个也会受到影响
- 当比较两个基本数据类型的值时就是比较值;当比较两个应用数据类型时,它是比较的对象的内存地址;如果两个对象是一模一样的,但是地址不同,在判断是否相等时也会返回false
函数
- 函数也是一个对象,同样具有所有普通对象的功能,包括属性等
- 创建函数对象
// 1 var fun = Function(); console.log(fun) // 2 var fun = new Function("console.log('这是我的第一个函数')"); // 封装到函数的代码不会立即执行,函数中的代码会在函数调用的时候执行 fun();
- 在实际开发中很少使用构造函数来创建一个函数
function 函数名([形参1, 形参2, ..., 形参N]){ // 中括号表示可选 语句... } function fun2(){ console.log('这是我的第二个函数'); } fun2(); // 使用函数表达式来创建一个函数 var 函数名 = function([形参1, 形参2, ..., 形参N]){ 语句... }
- 在实际开发中很少使用构造函数来创建一个函数
- 函数的参数
- 调用函数时解析器不会检查实参的类型,因此要注意是否有可能接收到非法的参数
- 解析器也不会检查实参的数量,多余实参不会被赋值;如果实参数量少于形参的数量,则没有对应实参的形参将是undefined
- 返回值
function sum(a, b, c){ return a + b + c; } var result = sum(1, 2, 3);
- 立即执行函数
- 函数定义完立即被调用
- 立即执行函数往往只会被执行一次
(function (){ alert('这是一个匿名函数'); })(); // 参数 (function(a, b){ console.log('a = ' + a); console.log('b = ' + b); })(123, 456);
- 方法
- 对象的属性值可以是任何的数据类型,也可以是个函数。如果一个函数作为对象的属性保存,那么这个函数是对象的方法,调用函数就说调用对象的方法
- 枚举对象的属性
for(var 变量 in 对象){ } // var obj = { name: '孙悟空', age: 18, gender: '男' }; // 对象有几个属性,循环体就会执行几次,每次执行时,会将对象中的一个属性的名字赋值给变量 for(var n in obj){ console.log(n); // 注意:用.的方式不能使用变量,但是用中括号可以使用变量作为属性 console.log(obj[n]); console.log(obj['n']); }
- 全局作用域
- 直接编写在
script
标签中的JS代码,都在全局作用域 - 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象
window
,它代表的是一个浏览器窗口,由浏览器创建,我们可以直接使用console.log(window)
- 在全局作用域中创建的对象都会作为
window
的属性保存,创建的函数都会作为window
的方法保存->所谓函数都是window的方法
- 变量的声明提前
- 使用
var
关键字声明的变量会在所有的代码执行之前被声明(但是不会赋值) - 但是如果声明变量时不使用
var
,则变量不会被提前声明// 返回a = undefined console.log('a = ' + a); var a; // 返回a = undefined,只提前声明,单步提前赋值 console.log('a = ' + a); var a = 123; // 报错 console.log('a = ' + a); a = 123;
- 使用
- 函数的声明提前
- 使用功能函数声明形式创建的函数
function(){}
,会在所有代码执行之间就创建 - 使用函数表达式创建的函数不会被提前创建
// 正常执行 fun(); // 报错, undefined fun2(); function(){ console.log('我是fun函数'); } var fun2 = function(){ console.log('我是fun2函数'); }
- 使用功能函数声明形式创建的函数
- 全局作用域中的变量都是全局变量,在任意的地方都可以访问到
- 直接编写在
- 函数作用域
- 调用函数时创建函数作用域,函数执行完毕后,函数作用于销毁
- 每调用一次函数就会创建一个新的函数作用域,它们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量,在全局作用域中不可以访问到函数作用域的变量
- 当在函数作用域中操作一个变量时,会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域依然没有找到,则会报错
ReferenceError
- 在函数中要访问全局变量可以使用
window
对象 - 在函数作用域中也有声明提前的特性,使用
var
关键字声明的变量会在函数中所有的代码被执行之前被声明 - 在函数中不使用
var
声明的变量都会成为全局变量
this
- 解析器在调用函数的时候每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是
this
this
指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式不同,this会指向不同的对象- 以函数的形式调用时,this永远都是window
- 以方法的形式调用时,this是调用方法的对象
- 以构造函数的形式调用时,this就是新创建的对象
- 解析器在调用函数的时候每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是
- 使用工厂方法创建对象
- 通过该方法可以大批量创建对象
function createPerson(name, age, gender){ // 创建一个新的对象 var obj = new Object(); // 向对象中添加属性 obj.name = name; obj.age = age; obj.gender = gender; obj.sayName = function(){ alert(this.name); } return obj; } var obj2 = createPerson('孙悟空', 19, '男'); var obj3 = createPerson('猪八戒', 29, '男'); var obj4 = createPerson('白骨精', 30, '女');
- 通过该方法可以大批量创建对象
- 构造函数
- 使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,导致我们无法区分出不同类型的对象
- 构造函数就是一个普通函数,差创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写
- 构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用
- 构造函数的执行流程
- 调用构造函数(使用new),立刻创建一个新的对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值
function Person(name, age, gender){ this.name = name; this.agge = age; this.gender = gender; this.sayName = function(){ alert(this.name); } } var per2 = new Person('孙悟空', 19, '男'); var per23 = new Person('猪八戒', 29, '男'); var per24 = new Person('白骨精', 30, '女'); // 使用instanceof可以检查一个对象是否是一个类的实例 console.log(per2 instanceof Person)
- 使用同一个构造函数创建的对象称为一类对象
- 使用instanceof可以检查一个对象是否是一个类的实例
- 所有的对象都是Object的后代,因此任何对象和Object做instanceof运算都会返回true
- 构造函数的修改:在Person构造函数中,为每一个对象都添加了一个sayName方法,构造函数没执行一次就会创建一个新的sayName方法,也就是所有实例的sayName都是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的,这是完全没有必要的,完全可以使所有的对象共享同一个方法
function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; this.sayName = fun; } // 将sayName方法在全局作用域中定义 funtion fun(){ alert('Hello大家好,我是' + this.name); } // 创建一个Person的实例 var per2 = new Person('孙悟空', 19, '男'); var per23 = new Person('猪八戒', 29, '男');
- 原型对象
-
将函数定义在全局作用域中,污染了全局作用域的命名空间,而且定义在在全局作用域中很不安全
-
原型prototype
-
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是原型
-
如果函数作为普通函数调用,prototype没有任何作用;当函数以构造函数形式调用时,它所创建的对象中都会有一个隐含的对象指向该构造函数的原型对象,我们可以通过
__proto__
来访问该属性 -
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
function MyClass(){ } // 向MyClass的原型中国添加属性a MyClass.prototype.a = 123; var mc = new MyClass();var mc2 = new MyClass(); console.log(MyClass.prototype); console.log(mc2.__proto__ == MyClass.prototype); // 当我们访问对象的一个属性或方法时,会现在自身中寻找,如果有则直接使用;如果没有,则去对应的原型对象中找,如果找到则直接使用 console.log(mc.a); mc.a = '我是mc中的a' console.log(mc.a); console.log(mc2.a); // 向MyClass中添加sayHello方法 MyClass.prototype.sayHello = function(){ alert('Hello'); }
-
将对象共有的属性和方法,统一添加到构造函数的原型对象中,这样就不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; } // 使用Person原型对象定义公共方法 Person.prototype.sayName = function(){ alert('Hello大家好,我是' + this.name); } // 创建一个Person的实例 var per2 = new Person('孙悟空', 19, '男'); var per23 = new Person('猪八戒', 29, '男');
-
使用
in
检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true -
可以使用对象的
hasOwnProperty()
方法来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true(注:hasOwnProperty
方法不在自身方法中)console.log(mc.hasOwnProperty("hasOwnProperty")) // 返回false console.log(mc.__proto__.hasOwnProperty("hasOwnProperty")) // 返回false
-
当我们使用一个对象的属性或方法时,会先在自身中寻找,自身中如果有,则直接使用,如果没有则去原型对象中去寻找,如果原型对象中有,这是一共,如果没有则去原型的原型中寻找,直到找到Object对象的原型,如果在Object原型中依然没有找到,则返回undefined
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")) // 返回true console.log(mc.__proto__.__proto__.__proto__) // 返回null
-
toString()
方法- 当我们在页面中打印一个对象时,实际上是输出对象的
toString()
方法的返回值 - 如果我们希望在输出对象时,不输出
[object Object]
,可以为对象添加一个toString()
方法var per = new Person('孙悟空', 18, '男'); var per2 = new Person('猪八戒', 28, '男'); console.log(per); // 返回[onject Object] console.log(per.toString()); // 返回[onject Object] console.log(per.__proto__.__proto__.hasOwnProperty("toString")); // 返回true // 重构toString方法 per.toString = function(){ return "我是新的toString"; } console.log(per); // 返回我是新的toString per.toString = function(){ return "Person[name=" + this.name + ", age=" + this.age + ", gender=" + this.gender; } console.log(per); // 返回Person[name="孙悟空", age=18, gender="男"] console.log(per2) // 返回[object Object] // 这种方法对其他对象不能成立,如果想要对所有该类的对象都成立,则需要对原型对象的toString方法重新编写 Person.prototype.toString = function(){ return "Person[name=" + this.name + ", age=" + this.age + ", gender=" + this.gender; } console.log(per2); // 返回Person[name="猪八戒", age=28, gender="男"]
- 当我们在页面中打印一个对象时,实际上是输出对象的
- 垃圾回收
- 什么是垃圾:当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量内存空间,导致程序运行变慢,所以这种垃圾必须进行清理
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行回收的操作
- 我们需要做的只是要将不再使用的对象设置为
null
数组
- 数组简介
- 普通对象使用字符串作为属性名,而数组使用数字作为索引来操作元素
- 数组的存储性能比普通对象好
// 创建数组对象 var arr = new Array(); console.log(arr) // 返回"" console.log(typeof(arr)) // 返回Object // 向数组中添加元素,从0开始 arr[0] = 10; arr[1] = 33; console.log(arr) // 返回10,33 // 读取一样,数组[索引],如果读取不存在的索引,不会报错,而是返回undefined // 获取数组长度,使用length属性(对于连续数组),对于非连续数组,length属性返回最大索引+1(尽量不要创建非连续数组) console.log(arr.length) // 修改length,如果修改的length大运原长度,则多余部分会空出来,如果修改的length小于原长度,则会删除多余的元素 arr.length = 5; console.log(arr.length); // 返回5 console.log(arr); // 返回10,33,,, // 向数组最后一个位置添加元素 arr[arr.length] = 70;
- 创建数组
// 使用字面量创建数组 var arr = []; // 可以在创建时就指定数组中的元素 var arr = [1, 2, 3, 4, 5]; // 使用构造函数创建也可以同时添加元素 var arr = new Array(1, 2, 3, 4, 5); console.log(arr.length); // 返回5 // 只传一个整数时指定的是数组长度,不足则用空串补足 arr = new Array(10); console.log(arr.length); // 返回10 // 数组中的元素可以是任意的数据类型,可以是字符串,也可以是对象,函数
- 数组增删元素
push()
:可以向数组的末尾添加一个或多个元素,并返回数组的新长度。可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组末尾pop()
:该法可以删除数组的最后一个元素,并将被删除的元素返回unshift()
:向数组的开头添加一个或多个元素,并返回数组新长度。向前面插入元素以后,其他元素的索引会依次调整shift()
:删除前面的第一个元素,并将被删除的元素返回var arr = ['孙悟空', '猪八戒', '沙和尚']; // push() var result = arr.push('唐僧', '蜘蛛精', '白骨精'); // pop() arr.pop(); console.log(arr); // 后面少了蜘蛛精和白骨精 // unshift() arr.unshift('牛魔王', '二郎神'); console.log(arr); // 前面多了牛魔王和二郎神 // shift() arr.shift(); arr.shift(); console.log(arr); // 前面少了牛魔王和二郎神
- 数组遍历
- 使用
for
循环遍历for(var i = 0; i < arr.length; i++){ console.log(arr[i]); }
- 使用
forEach()
方法遍历(只支持IE8以上的浏览器,如果需要兼容IE8则不要使用forEach而是使用for循环来遍历)var arr = ['孙悟空', '猪八戒',' 沙和尚', '唐僧', '白骨精']; // forEach()方法需要一个函数作为参数 // 像这种函数,由我们创建但不由我们调用,称为回调函数 // 数组中有几个函数函数就会执行几次 // 每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以定义形参,来读取这些内容 // 浏览器会在回调函数中传递三个参数:第一个参数是当前正在遍历的元素,第二个参数是当前的索引,第三个参数是正在遍历的数组tion(a){ console.log('a = ' + a); })
- 使用
- 数组
slice
和splice
方法slice
方法:用来从数组中提取出指定范围的元素。该方法不会改变数组,而是将截取到的元素封装到一个新数组中返回splice
方法:删除数组中的指定元素,会将指定元素从原数组中删除,并将删除的元素作为返回值返回var arr = ['孙悟空', '猪八戒',' 沙和尚', '唐僧', '白骨精']; // arr.slice(start, end) var result = arr.slice(0, 2); console.log(result); // 返回孙悟空和猪八戒,注:不包括结束索引2 console.log(arr.slice(1)); // 第二个参数可以不写,此时会截取从开始索引往后的所有元素 console.log(arr.slice(1, -2)); // 索引可以传递一个负值,表示从后往前算 // arr.splice(start, length) console.log(arr.splice(0, 2)); // 0表示开始位置的索引,2表示删除的数量(删除2个) // 添加新元素,第三个及以后的参数:可以传递一些新的元素,这些元素将会自动插入到开始位置索引前面 console.log(arr.log(splice(0, 1, '牛魔王', '铁扇公主'))); //少两个,多两个
- 数组去重
var arr = [1, 2, 3, 2, 1, 3, 4, 2, 5]; for(var i = 0; i < arr.length; i++){ for(var j = i + 1; j < arr.length; j++){ if(arr[i] == arr[j]){ arr.splice(j--, 1); } } }
- 数组的其他方法
concat()
:连接两个或多个数组,并将新的数组返回,该方法不会对原数组产生影响join()
:将数组转换为一个字符串,该方法不会对原数组产生影响reverse()
:该方法用来反转数组,该方法会直接修改原数组sort()
:排序数组,对于默认按照Unicode编码顺序进行排序。即使对于纯数字的数组,使用sort()
排序时,也会按照Unicode编码来排序,所以对数字进行排序时,我们可以在sort()
添加一个回调函数,来指定排序规则,回调函数中需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数,使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前面。浏览器会根据回到偶函数的返回值来决定元素的顺序,如果返回一个大于0的值,则元素会交换位置;如果返回一个小于0的值则元素位置不变;如果返回0则认为两个元素相等,不交换位置var arr = ['孙悟空', '猪八戒',' 沙和尚']; var arr2 = ['唐僧', '白骨精']; // concat() arr.concat(arr2) // join() console.log(arr.join()); // 返回"孙悟空,猪八戒,沙和尚" // 在join中可以指定一个字符串作为参数,这个字符串会成为数组中的元素的连接符,如果不指定则默认使用','作为连接符 console.log(arr.join(-)); // 返回"孙悟空-猪八戒-沙和尚" // reverse() arr.reverse(); console.log(arr); //sort() arr = ['b', 'a', 'd', 'e', 'c']; arr.sort(); console.log(arr); // 返回a,b,c,d,e arr = [3, 4, 1, 2, 5]; arr.sort(); console.log(arr); // 返回1,2,3,4,5 arr = [3, 4, 11, 2, 5]; arr.sort(); console.log(arr); // 返回11,2,3,4,5 arr = [3, 4, 11, 2, 5]; arr.sort(function(a, b){ // console.log('a = ' + a); // console.log('b = ' + b); if(a > b) { return 1; } else if(a < b){ return -1; } else { return 0; } // 或者使用如下语句 return a - b; }) // 降序排序
- 函数对象的方法
call()
和apply()
:当对函数调用call()
和allpy()
都会到欧勇函数执行,在调用call()
和apply()
可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
call()
方法可以将实参在对象之后一次传递apply()
方法需要将实参封装到一个数组中统一传递function fun(){ alert('我是fun函数'); } fun.apply(); fun.call(); fun(); function fun(a, b){ console.log('a = ' + a); console.log('b = ' + b); } var obj = {}; fun.call(obj, 2, 3); fun.apply(obj, [2, 3]);
arguments
- 在调用函数时,浏览器每次都会传递两个隐含的采纳数,一个是函数的上下文对象
this
,另一个是封装实参的对象arguments
arguments
是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度- 在调用函数时,我们所传递的实参都会在
arguments
中保存 arguments.length
表示传递的实参数量arguments[0]
表示第一个实参,即使不定义形参也可以通过arguments
来使用实参,只不过比较麻烦arguments.callee
这个属性对应一个函数对象,即当前正在执行的函数对象
- 在调用函数时,浏览器每次都会传递两个隐含的采纳数,一个是函数的上下文对象
其他对象
- Date对象
var d = new Data(); console.log(d); // 创建一个指定的时间对象,在构造函数中传递字符串,注意格式 var d2 = new Date("12/03/2016 11:10:30"); // getDate(): 获取当前日期对象时几号 var date = d2.getDate(); // getMonth(): 几月(0表示1月) // getDay(): 星期几(0表示周日,1-6表示周一-周六) // getFullYear(): 年份 // getHours(), getMinutes(), getSeconds(): 时分秒 // getMilliseconds(): 毫秒 // getTime(): 1970年1月1日至今的毫秒数
- Math对象
console.log(Math.PI); // 圆周率 Math.abs(-1); Math.ceil(1.5); // 2,向上取整 Math.floor(1.6); // 1,向下取整 Math.round(1.5); // 2,四舍五入 Math.random(); // 产生0-1之间随机数 Math.random() * 10; //0-10之间随机数 Math.max(10, 20, 30); // 多个数最大值 Math.min(10, 20, 30); // 多个数最小值 Math.sqrt(10); // 开方 Math.pow(2, 3); // 2^3
- 包装类
- 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型转换为对象
String()
将基本数据类型字符串转换为String对象Number()
将基本数据类型的数字转换为Number对象Boolean()
将基本数据类型的布尔值转换为Boolean对象
var num = new Number(3); var str = new String("hello"); var bool = new Boolean(true);
- 在实际运用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
- 当我们对一些基本数据类型去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后再调用对象的属性和方法。调用完之后再将其转换为基本数据类型
- 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型转换为对象
String
类方法var str = "Hello AtGuigu"; // 在底层字符串是以字符数组的形式保存的 console.log(str.length); // 长度 console.log(str[5]); // " " // charAt()返回字符串中指定位置的字符 console.log(str.charAt(5)); // " " // charCodeAt()获取指定位置的字符Unicode编码 console.log(str.charCodeAt(6)); // fromCharCode()根据字符编码去获取字符,通过String调用 String.fromCharCode(72); // concat()连接两个或多个字符串 console.log(str.concat("你好", "再见")); console.log(str + "你好" + "再见"); // indexOf()检索一个字符串中是否含有指定内容,如果字符串中含有该内容则返回其第一次出现的索引,如果没有找到指定内容,则返回-1 console.log(str.indexOf("H")); // 返回0 console.log(str.indexOf("H", 1)); // 指定从索引1开始查找 // lastIndexOf(): 用法与indexOf()一样,但是是从后往前找 console.log(str.lastIndexOf("H")); // slice(): 从字符串中截取指定内容,两个参数为start何end,如果省略第二个参数则截取到后面所有的,也可以传递复数作为参数,表示从后面计算 str = "abcdefghijk"; result = str.slice(0, 2); console.log(result); console.log(str); // 不改变str // substring(): 可以用来截取字符串,和slice()类似,与之不同的是subString不能接收负值作为参数,如果传递了一个负值,则默认使用0,而且它还会自动调整参数位置 console.log(str.subString(1, 2)); console.log(str.subString(2, 1)); // substr()用来截取字符串,第一个参数是参数开始的位置,第二个是截取的长度,对原字符串没有影响 console.log(str.substr(2, 2)); // 返回cd // split()将字符串拆分为一个数组 str = "abc,bcd,efg,hij"; result = str.split(","); console.log(Array.isArray(result)); // true console.log(result); console.log(str.split("")) // 将每个字符都拆分为数组中的一个元素 // toLowerCase()把字符串转换为小写,不影响原字符串 // toUpperCase()把字符串转换为大写 str = "abcdefg"; console.log(str.toUpperCase()); console.log(str.toUpperCase().toLowerCase());
- 正则表达式
- 用于定义一些字符串的规则,计算机可以根据正则表达式来检查一个字符串是否符合规则,并将获取字符串中符合规则的内容提取出来
- 创建正则表达式的对象
// var 变量 = new RegExp("正则表达式", "匹配模式"); var reg = new RegExp("a");// 这个表达式可以用来检查一个字符串中是否含有a // 在构造中可以传递一个匹配模式作为第二个参数,可以是:i: 忽略大小写;g: 全局匹配模式
- 使用
test()
方法可以检查一个字符串是否符合正则表达式的规则,如果符合则返回truevar str = "Acdbs"; var result = reg.test(str);
- 使用字面量来创建正则表达式
// var 变量 = /正则表达式/匹配模式 // 两者等价,但是使用构造函数更加灵活 var reg = new RegExp("a", "i"); var reg = /a/i; // 检查一个字符串中是否有a或b-|表示或者 reg = /a|b/; console.log(reg.test("abcd")); // true // 检查一个字符串中是否有字母 reg = /a|b|c|d|...|z/; // 麻烦 // []里的内容也是或的关系 reg = /[abcdefg.....z]/;// 依然麻烦 reg = /[a-z]/; // 任意小写字母 reg = /[A-Z]/; // 任意大写字母 reg = /[A-z]/; // 任意字母 // 检查一个字符串中是否含有abc或adc或aec reg = /abc|adc|aec/; reg = /a[bde]c/; // [^ ]表示除了 reg = /[^ab]/; // 检查有没有除了ab以外的字符 // [0-9]表示任意数字 reg = /[0-9]/; reg = /[^0-9]/; // 除了数字
- 字符串和正则相关的方法
var str = "1a2b3c4d5e6f7g"; // split()把一个字符串拆分为数组 var result = str.split('c'); console.log(result); // 根据任意字母将字符串拆分,split方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串。这个方法即使不指定全局匹配也会全部拆分 var result = str.split(/[A-z]/); // search()可以搜索字符串中是否含有指定内容,如果搜索到指定内容则返回第一次出现的索引,如果没有搜索到返回-1 str = "hello abc hello abc"; result = str.search("abc"); // search()也可以接受一个正则表达式作为参数,然后根据正则表达式去检索字符串 // 搜索字符串中是否含有abc,adc 或aec result = str.search(/a[bef]c/); // search只会查找第一个,即使设置了全局匹配也没用 // match()可以根据正则表达式,从一个字符串中将符合条件的内容提取出来 str = "1a2b3c4d5e6f7g"; result = str.match(/[A-z]/); // 返回a,默认情况下match只会找到第一个符合要求的内容 // 设置正则表达式为全局匹配模式,这样就会匹配到所有的内容 result = str.match(/[a-z]/g); // 全局匹配 result = str.match(/[a-z]/gi); // 可以为一个正则表达式设置多个匹配模式,且顺序无所谓 console.log(Array.isArray(result)); // match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果 // repalce()可以将字符串中指定内容替换为新的内容 result = str.replace(被替换的内容, 新的内容); result = str.repalce("a", "@"); // 默认只会替换第一个,使用正则表达式即可全局匹配 result = str.repalce(/[A-z]/gi, ""); // 删除所有字母
- 正则表达式语法补充
// 通过量词可以设置一个内容出现的次数 var reg = /a{3}/; // 相当于/aaa/,表示a是否出现连续3次 reg = /ab{3}/; console.log(reg.test("ababab")); // false console.log(reg.test("abbb")); // true reg = /(ab){3}/; console.log(reg.test("ababab")); // true reg = /ab{3}c/; // 找是否有abbbc console.log(reg.test("abbbc")); // true // 出现次数在1-3次 reg = /ab{1,3}c/; console.log(reg.test("abbc")); // true console.log(reg.test("abbbbc")); // false reg = /ab{3,}c/;// 表示b出现3次以上 console.log(reg.test("abbbbc")); // true // 至少出现一次 reg = /ab+c/; // b至少出现一次 reg = /ab{1,}c/; // 等价写法 // 有没有都可以 reg = /ab*c/; // b出现0次会任意次 reg = /ab{0,}c/; // 等价写法 // 出现一次或者不出现 reg = /ab?c/; // b出现0次或者1次 reg = /ab{0,1}c/; // 等价写法 // 检查一个字符串是否以a开头,/^ /表示开头 reg = /^a/; // 匹配开头的a // 检查一个字符串是否以a结尾,/ $/表示结尾 reg = /a$/; // 匹配结尾的a reg = /^a$/; // 如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式 console.log(reg.test("aaa")); // false console.log(reg.test("a")); // true reg = /^a|a$/; //使用|来解决是否以a开头或结尾 console.log(reg.test("aaa")); // true
- 应用:创建一个正则表达式,用来检查一个字符串是否是一个手机号
var phoneStr = "13567894537"; // 手机号规则:11位 // 1.第一位以1开头,^1 // 2.第二位3-9,[3-9] // 3.三位以后任意数字9个,[0-9]{9}$ var phoneReg = /^1[3-9][0-9]{9}$/;
// 检查一个字符串中是否含有. // .表示任意字符 var reg = "."; console.log(reg.test("a")); // true // \.表示. reg = /\./; // 注:使用构造函数时,由于参数是字符串,而\是字符串转义字符,如果要使用\则需要使用\\来替代 // \\ 表示\ reg = /\\/; reg = /\w/; // \w表示任意字母、数字和下划线,相当于[A-z0-9] reg = /\W/; // \W表示除了字母、数字和下划线,相当于[^A-z0-9] reg = /\d/; // \d表示任意数字 reg = /\D/; // \D表示除了数字 reg = /\s/; // \s表示空格 reg = /\S/; // \S表示除了空格 reg = /\b/; // \b表示单词边界 reg = /child/; console.log(reg.test("hellochildren")); // 返回true reg = /\bchild\b/; // 检查单词child console.log(reg.test("hellochildren")); // 返回false console.log(reg.test("hello child ren")); // 返回true reg = /\B/; // \B表示除了单词边界
- 应用:去除字符串两边的空格
var str = prompt("请输入你的用户名:"); console.log(str);//在开头或结尾可能无意间多输入很多空格,需要删除两边的空格(中间不能删) str = str.repalce(/\s/g, ''); // 替换了所有的空格 str = str.repalce(/^\s*/, ""); // 取出开头的若干个空格 str = str.repalce(/\s*$/, ""); // 去除结尾的若干空格 str = str.repalce(/^\s*$/, ""); // 开头和结尾都是空格,中间需要用|分隔开 str = str.replace(/^\s*|\s*$/, ""); // 只去除了开头,因为没有全局匹配 str = str.replace(/^\s*|\s*$/g, ""); //
- 应用:电子邮件的正则
// hello.nihao@abc.com.cn // hello: 任意字母数字下划线,\w{3,} // .及其后面的字母数字下划线可有可无,(\.\w+)* // @固定符号,@ // abc: 任意字母数字,[A-z0-9]+ // .com.cn: .任意字母(2-5位).任意字母(2-5位) (\.[A-z]{2,5}){1,2} var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/; var email = "abc.ehllo@163.com" console.log(emailReg.test(email));
- 应用:创建一个正则表达式,用来检查一个字符串是否是一个手机号
DOM
- DOM简介
Document Object Module
(文档对象模型)- 文档:表示整个HTML网页文档
- 对象:表示将网页中的每一个部分都转换为了一个对象
- 模型:使用功能模型来表示对象之间的关系,这样方便获取对象
- JS中通过DOM来对HTML文档进行操作,只要理解了DOM就可以随心所欲地操作web页面
- 节点
- Node,是构成网页的最基本的组成部分,网页中的每一个部分都可以称为节点
- 分类
描述 nodeName nodeType nodeValue 文档节点 整个HTML文档 #document 9 null 元素节点 HTML文档中的HTML标签 标签名 1 null 属性节点 元素的属性 属性名 2 属性值 文本节点 标签中的内容 #text 3 文本内容 - 浏览器已经为我们提供了文档节点对象,这个对象时window属性,可以在页面中直接使用,代表的是整个网页
console.log(document); //html <button id="btn">我是一个按钮</button> // 获取到button对象 var btn = document.getElementById("btn"); // 修改按钮的文字 console.log(btn.innerHTML); btn.innerHTML = "I'n Button";
- 事件:文档或浏览器窗口发生的一些特定的交互瞬间,JS与HTML之间的交互是通过事件实现的,比如点击按钮、鼠标移动、关闭窗口
- 我们可以在事件对应的属性中设置一些JS代码,这样当事件被触发时,这些代码将会执行
- 这种写法结构和行为耦合,不方便维护,不推荐使用
- 可以为按钮对应事件绑定处理函数的形式来响应事件,当事件触发时,其对应的函数将被执行
// 获取按钮对象 var btn = document.getElementById("btn"); // 绑定一个单击事件 btn.onclick = function(){ alert("你点我干嘛~"); } // btn.onmousemove -> 鼠标移动到该处 // btn.ondbclick -> 鼠标双击
- 文档的加载
- 浏览器在加载页面时,是按照自上向下的顺序加载的,读取一行就运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载
- 将JS代码编写到页面下部就是为了可以在页面加载完毕以后再执行JS代码
onload
事件会在整个页面加载完成之后才触发,为window
绑定一个onload
事件。如果想把script代码写到head里面,可以将对应的响应函数写到window.onload = function(){}
里面,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了window.onload = function(){ var btn = document.getElementById("btn"); // 绑定一个单击事件 btn.onclick = function(){ alert("你点我干嘛~"); } alert("Hello!"); }
- 如果追求性能,希望先加载页面然后再执行,则放在body里面性能最高,但是实际上性能差异不大
- DOM查询
getElementById()
:通过id
属性获取一个元素对象getElementsByTagName()
:通过标签名获取一组元素节点对象,这个方法会返回一个类数组对象,所有查询到的元素都会封装到对象中。计时查询到的元素只有一个也会封装到数组中getElementsByName()
:通过name
属性获取一组元素节点对象。innerHTML
用于获取元素内部的HTML标签。对于自结束标签(如<input>, <img>
),这个属性没有意义- 如果需要读取一个元素节点的属性,直接使用
元素.属性名
,注:不能通过这种方式读取class
,因为class
是保留字,而读取class
应该用元素.className
childNodes
属性会获取包括文本节点在内的所有节点。根据DOM标签,标签间空白也会当成文本节点(注:在IE8及以下的浏览器中,不会将空白文本当成子节点)children
属性可以获取当前元素的所有子元素firstChild
属性表示当前节点的第一个子节点(包括空白文本节点)firstElementChild
属性获取当前元素的第一个子元素(不支持IE8及以下)lastChild
属性表示当前节点的最后一个子节点parentNode
属性返回当前节点的父节点previousSibling
属性返回当前节点的前一个兄弟节点,也可能获取到空白文本previousElementSibling
属性返回当前节点的前一个兄弟元素(IE8及以下不支持)nextSibling
属性返回当前节点的后一个兄弟节点innerText
属性可以获取元素内部的文本,与innerHTML
类似,但是会自动将html去除document.body
属性可以直接获取body
元素,等价于document.getElementsByTagName("body")[0]
document.documentElement
属性表示html
根标签document.all
表示页面中所有的元素,等价于document.getElementsByTagName("*")
document.getElementsByClassName()
可以根据class
属性获取一组元素节点对象,但是该方法不支持IE8及以下的浏览器dicument.querySelector()
需要一个选择器的字符串作为参数,可以根据CSS选择器来查询一个元素节点对象。虽然IE8中没有getElementsByClassName()
,但是可以使用querySelector()
代替。但是使用该方法总会返回唯一的一个元素,如果满足条件的元素有多个,那么它只会返回第一个document.querySelectorAll()
方法和querySelector()
用法类似,但是它会将符合条件的元素封装到一个数组中返回。计时符合条件的元素只有一个,也会返回数组
- DOM增删改
- 创建一个广州节点,添加到
#city
下// 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
前面// 创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); // 获取id为nj的节点 var bj = document.getElementById("bj"); // 获取city var city = document.getElementById("city"); // insertBefore()可以在指定的字节点前面插入新的子节点: 父节点.insertBefore(新节点, 旧节点); city.insertBefore(li, bj);
- 使用“广州”节点替换
#bj
节点// 创建一个广州 var li = document.createElement("li"); var gzText = document.createTextNode("广州"); li.appendChild(gzText); var bj = document.getElementById("bj"); var city = document.getElementById("city"); // replaceChild()可以使用指定的字节点提花已有的字节点:父节点.replaceChild(新节点, 旧节点) city.replaceChild(li, bj);
- 删除
#bj
节点var bj = document.getElementById("bj"); var city = document.getElementById("city"); // removeChild()可以删除子节点:父节点.removeChild(子节点) city.removeChild(bj); // 常用方法:不知道city的情况下进行删除。子节点.parentNode.removeChild(子节点) bj.parentNode.removeChild(bj);
- 读取
#city
内的代码var city = document.getElementById("city"); alert(city.innerHTML);
- 设置
#bj
内的HTML代码var bj = document.getElementById("bj"); bj.innerHTML = "昌平";
- 通过
innerHTML
添加广州节点到#city
下var city = document.getElementById("city"); city.innerHTML += "<li>广州</li>"; // 使用innerHTML也可以完成DOM的增删改相关操作,但是动作太大了,会对整个innerHTML进行修改。一般我们会两种方式结合使用 var li = document.createElement("li"); li.innerHTML = "广州"; // 将li添加到city city.appendChild(li);
- 应用:添加删除信息
- 点击超链接以后,超链接会跳转页面,这个是起链接的默认行为,但是此时我们不希望出现默认行为,可以通过在响应函数的最后
return false
来取消默认行为 - 或者在
a
标签的href
属性中修改为javascript:;
或者javascript:void(0);
void
关键字指定要计算或运行一个表达式,但是不返回值。<!-- void(0)计算为0,用户点击不会发生任何效果 --> <a href="javascript:void(0);">单击此处什么都不会发生</a> <!-- 执行 void() 操作符中的代码 --> <a href="javascript:void(alert('还真点啊你,真听话!'))">点我弹出警告框!!!</a>
a = void(b = 2); console.log('a => ' + a); // a => undefined console.log('b => ' + b); // b => 2
window
的confirm()
方法用于弹出一个带有确认和取消按钮的提示框,需要一个字符串作为参数,该字符串将会作为提示文字显示出来。如果用户点击确认,返回true
,如果用户点击取消,则返回false
var flag = confirm("确认删除吗?") if(flag){ ... }
- 点击超链接以后,超链接会跳转页面,这个是起链接的默认行为,但是此时我们不希望出现默认行为,可以通过在响应函数的最后
- 创建一个广州节点,添加到
- 操作CSS样式
- 操作内联样式
元素.style.样式名 = 样式值
// 注意样式值需要是字符串 box1.style.width = "300px";
- 如果CSS样式名中含有
-
,这种名称在JS中是不合法的,如background-color
,需要将这种样式名修改为驼峰命名法,去掉-
,然后将-
后面的字母大写box1.style.backgroundColor = "yellow";
- 通过
style
属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示。但是如果在样式中写了!important
,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加!important
- 获取元素的样式
alert(box.style.width)
: 通过style
属性设置和读取的样式都是内联样式,无法读取样式表中的样式- 获取元素当前显示的样式:
元素.currentStyle.样式名
用来读取当前元素正在显示的样式。如果当前元素没有设置样式值,则获取它的默认值。但是currentStyle
只有IE浏览器支持,其他浏览器都不支持 - 在其他浏览器中可以使用
getComputedStyle()
来获取元素当前的样式,这个方法是window
的方法,可以直接使用。// 第一个参数是要获取样式的元素,第二个参数可以传第一个伪元素,一般都传null // 该方法会返回一个对象,封装了当前元素对应的样式 obj = getComputedStyle(box1, null); alert(obj.width); // 合并写 getComputedStyle(box1, null).width; // 如果获取的样式没有设置,则会获取到真实的值,而不是默认值,比如:如果没有设置width,它不会获取到auto,而是一个长度
- 但是该方法不支持IE8及以下的浏览器
- 定义一个函数,用来获取指定元素的当前样式
// obj: 要获取样式的元素 // name: 要获取的样式名 function getStyle(obj, name){ // 添加window.使getComputed从变量变成属性,如果变量没有则会去全局寻找,依然没有则会报错,而属性没有则只会返回undefined if(window.getComputedStyle){ // 正常浏览器的方式 return getComputedStyle(obj, null)[name]; }else{ // IE8的方式 return obj.currentStyle[name]; } }
- 通过
currentStyle
和getComputedStyle()
读取到的样式都是只读的,不能修改,如果要修改必须通过style
属性
- 其他样式相关的属性
clientWidth
和clientHeight
属性可以获取元素的可见宽度和高度,这些属性都是不带px
的,可以直接进行计算。获取的宽度高度包括元素宽度、高度,包括内容区和内边距。这些属性都是只读的,不能修改。修改样式只能通过style
进行offsetWidth
和offsetHeight
获取元素的整个宽度,包括内容区、内边距和边框offsetParent
可以获取当前元素的定位父元素,会获取到离当前元素最近的开启了定位的祖先元素,如果所有的祖先元素都没有开启定位,则返回body
offsetLeft
当前元素相对于其定位父元素的水平偏移量offsetTop
当前元素相对于其定位父元素的垂直偏移量scrollHeight
和scrollWidth
可以获取元素整个滚动区域的高度和宽度scrollLeft
可以获取水平滚动条滚动的距离;scrollTop
可以获取垂直滚动条滚动的距离- 当满足
scrollHeight - scrollTop == clientHeight
时,说明垂直滚动条滚动到底;水平同理
unscroll
事件会在元素的滚动条滚动时触发
- 操作内联样式
- 事件对象
- 当事件的响应函数被触发时,浏览器每次都会将一个事件作为实参传递进响应函数
- 在事件对象中封装了当前事件相关的一切信息,比如鼠标的坐标、键盘的哪个按键被按下、鼠标滚轮的方向等
clientX
可以获取鼠标指针的水平坐标;clientY
可以获取鼠标指针的垂直坐标。注:这两个坐标都是可见窗口内的坐标,如果要获取真实的高度,可以使用pageX
和pageY
,这两个属性可以获取鼠标相对于当前页面的坐标,但是这两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用,而可以通过scrollTop
来获取,但是Chrome认为浏览器的滚动条是body
的,可以通过documentbody.scrollTop
来获取,而火狐等浏览器认为浏览器的滚动条是html
的,可以通过document.documentElement.scrollTop
来获取,考虑两者兼容的问题,采用或运算来获得最后的scrollTop
,即st = document.body.scrollTop || dicument.documentElement.scrollTop
,获得之后再加上clientX
即可获得液面高度。对于页面宽度的获取同理- 在IE8及以下的浏览器中,响应函数被触发时,浏览器不会传递事件对象,而是将事件对象作为
window
对象的属性保存的<script type="text/javascript"> window.onload = function(){ // 当鼠标在areaDiv中移动时,在showMsg中显示鼠标的坐标 var areaDiv = document.getElementById("areaDiv"); var showMsg = document.getElementById("showMsg"); // onmousemove事件会在鼠标在元素中移动时被触发 // 火狐中没有window.event属性 if(!event){ event = window.event; } // 或者采用这种兼容性写法 event = event || window.event; areaDiv.onmousemove = function(event){ // 在showMsg中显示鼠标坐标 var x = event.clientX; var y = event.clientY; // alert("x = " + x + ", y = " + y); showMsg.innerHTML = "x = " + x + ", y = " + y; } }; </script> <body> <div id="areaDiv" style="width:200px;height=50px;"></div> <div id="showMsg" style="width:200px;height=12px;"></div> </body>
- 冒泡
- 冒泡指事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
- 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡,可以将事件对象的
cancelBubble
设置为true
,即可取消冒泡event = event || window.event; event.cancelBubble = true;
- 冒泡的应用:事件的委派
<script type="text/javascript"> window.onload = function(){ // 点击按钮以后添加超链接 var btn01 = document.getElementById("btn01"); btn01.onclick = function(){ var ul = document.createElement("ul"); var li = document.createElement("li"); li.innerHTML = "<a href='javascript:;'>新建的超链接</a>"; ul.appendChild(li); } // 为每一个超链接都绑定一个单击响应函数 var allA = document.getElementById("allA"); for(var i = 0; i < allA.length; i++) { allA[i].onclick = function(){ alert("我是a的单击响应函数!"); } } // 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,而且这种操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定 // 我们希望,只绑定一次事件,即可引用到多个的元素上,即使元素是后添加的 // 可以尝试将其绑定给元素的共同祖先元素 // 为ul绑定一个单击响应函数 ul.onclick = function(){ alert("我是ul的单击响应函数!"); } // 事件的委派:将事件统一绑定给元素共同的祖先元素,当后代元素上的时间触发时,会一直冒泡到祖先元素从而通过祖先元素的响应函数来处理事件 // 事件委派是利用了冒泡,通过委派可以减少绑定的次数,提高程序的性能 // 上述代码发现点击ul所在区域都会触发事件,因此需要判断如果触发事件的对象是否是期望的元素 ul.onclick = function(event){ event = event || window.event; // event中的target表示出发事件的对象 // 如果触发时间的对象是我们期望的元素,则执行,否则不执行 if(event.target.className == "link"){ alert("我是ul的单击响应函数!"); } } }; </script> <body> <ul id="ul"> <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>
- 绑定多个事件
- 使用
对象.事件
的形式绑定响应函数,只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个,如果绑定了多个,则后边会覆盖掉前面的 addEventListener()
这个方法也可以为元素绑定响应函数。参数1:事件的字符串,参数2:回到函数,当事件触发时该函数会被调用;参数3:是否在捕获阶段触发事件,需要一个布尔值,一般都传false
- 使用
addEventListener()
可以同时为一个元素的相同事件绑定多个响应函数,这样当事件被触发时,响应函数将会按照函数的绑定顺序执行btn01.addEventListener("click",function(){ alert(1); }, false); btn02.addEventListener("click",function(){ alert(2); }, false);
- 这个方法不支持IE8以及下浏览器。在IE8中可以使用
attachEvent()
来绑定事件。参数1:事件的字符串,需要on
,参数2:回调函数。这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定的先执行,执行顺序和addEventListener()
相反。并且在Chrome等浏览器没有这个方法 - 定义一个函数,用来为指定元素绑定响应函数
// 参数: // obj: 要绑定事件的对象 // eventstr: 事件的字符串(不要on) // callback: 回调函数 // addEventListener()中的this是绑定事件的对象,而attachEvent()中的this是window,因此需要统一两个方法的this fucntion bind(obj, eventStr, callback){ if(obj.addEventListener){ // 大部分浏览器兼容的方式 obj.addEventListener(eventStr, callback, false); }else{ // IE8及以下 // obj.attachEvent(eventStr + "on", callback); // 上面没有处理this // this是谁由调用方式决定 // 通过callback.call(obj)可以修改 obj.attachEvent("on" = eventStr, function(){ // 在匿名函数中调用回调函数 callback.call(obj); }) } }
- 使用
- 事件的传播
- 关于事件的传播,网景公司和微软公司有不同的理解
- 微软认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就是说时间应该在冒泡阶段执行
- 网景公司认为时间应该由外向内传播的,也就是当事件触发时应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素
- W3C综合了两个公司的方案,将事件的传播分成了三个阶段
- 捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
- 目标阶段:事件捕获到目标元素,捕获结束开始在目标元素上触发事件
- 冒泡阶段:事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件
- 如果希望在捕获阶段就触发事件,可以将
addEventListener()
的第三个参数设置为true
,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
- IE8及以下的浏览器中没有捕获阶段
- 关于事件的传播,网景公司和微软公司有不同的理解
- 练习:拖拽
window.onload = function() { // 拖拽流程: // 1. 当鼠标在拖拽元素上按下时,开始拖动 onmousedown // 2. 当鼠标移动时拖拽元素跟随鼠标移动 onmousemove // 3. 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup // 获取box1 var box1 = document.getElementById("box1"); // 为box1绑定一个鼠标按下事件 // 当鼠标在拖拽元素上按下时,开始拖动 onmousedown box1.onmousedown = function(event){ // 设置box1捕获所有鼠标按下事件 // 当用一个元素的setCapture()方法设置后,这个元素会把下一次所有的鼠标按下事件都捕获到自身上 // setCapture()只有IE支持,但是在火狐中不会报错,而如果使用Chrome会报错 if(box1.setCapture){ box1.setCapture(); } // 或者采用这种写法 box1.setCapture && box1.setCapture(); // 保持鼠标和box顶点的相对位置不变,因此需要计算出相对距离,在后面鼠标移动时减去即可 // 横向偏移量 = 鼠标.clientX - 元素.offsetLeft // 纵向偏移量 = 鼠标.clientX - 元素.offsetTop event = event || window.event; 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"; }; // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup // 为document绑定一个鼠标松开事件 document.onmouseup = function(){ // 取消document的onmousemove事件 document.onmousemove = null; // 取消document的onmouseup事件 document.onmouseup = null; // 当鼠标松开时,取消对事件的捕获 // box1.releaseCapture(); box1.releaseCapture && box1.releaseCapture(); }; // 当拖拽网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常,这个是浏览器提供的默认行为 // 如果不希望发生这种行为,则可以通过return false来取消默认行为 return false; // 但是这招对IE8不起作用 }; };
- 提取一个专门用来设置拖拽的函数
window.onload = function(){ var box1 = document.getElementById("box1"); var box2 = document.getElementById("box2"); drag(box1); drag(box2); }; function drag(obj){ // 拖拽流程: // 1. 当鼠标在拖拽元素上按下时,开始拖动 onmousedown // 2. 当鼠标移动时拖拽元素跟随鼠标移动 onmousemove // 3. 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup obj.onmousedown = function(event){ // 设置obj捕获所有鼠标按下事件 // setCapture()只有IE支持,但是在火狐中不会报错,而如果使用Chrome会报错 if(obj.setCapture){ obj.setCapture(); } // 或者采用这种写法 obj.setCapture && obj.setCapture(); // 保持鼠标和box顶点的相对位置不变,因此需要计算出相对距离,在后面鼠标移动时减去即可 // 横向偏移量 = 鼠标.clientX - 元素.offsetLeft // 纵向偏移量 = 鼠标.clientX - 元素.offsetTop event = event || window.event; var ol = event.clientX - obj.offsetLeft; var ot = event.clientY - obj.offsetTop; // 为document绑定一个onmousemove事件 document.onmousemove = function(event){ event = event || window.event; // 当鼠标移动时拖拽元素跟随鼠标移动 onmousemove // 获取鼠标的坐标 var left = event.clientX - ol; var top = event.clientY - ot; // 修改obj的位置 obj.style.left = left + "px"; obj.style.top = top + "px"; }; // 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup // 为document绑定一个鼠标松开事件 document.onmouseup = function(){ // 取消document的onmousemove事件 document.onmousemove = null; // 取消document的onmouseup事件 document.onmouseup = null; // 当鼠标松开时,取消对事件的捕获 // obj.releaseCapture(); obj.releaseCapture && obj.releaseCapture(); }; // 当拖拽网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常,这个是浏览器提供的默认行为 // 如果不希望发生这种行为,则可以通过return false来取消默认行为 return false; // 但是这招对IE8不起作用 }; }
- 提取一个专门用来设置拖拽的函数
- 滚轮事件
onmousewheel
事件会在滚轮滚动时触发,但是火狐不支持该属性。在火狐中需要使用功能DOMMouseScroll
来绑定,该事件需要通过addEventListener()
函数来绑定// 需求: 当鼠标滚轮向下滚动时,box1变长,当滚轮向上滚动时,box1变短 window.onload = function() { var box1 = document.getElementById("box1"); // 为box1绑定一个鼠标滚动事件 box1.onmousewheel = function(event){ // 判断鼠标滚轮滚动的方向 event = event || window.event; // wheelDelta可以获取鼠标滚轮滚动的方向 // 向上滚是120,向下滚是-120,这个值我们不看大小,只看正负 // 这个属性火狐中不支持 // alert(event.wheelDelta); // 在火狐中使用event.detail来获取滚动的方向,向上是-3,向下是3 // alert(event.detail); 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来去消默认行为,可以使用下属方法取消。但是IE8不支持,如果直接调用会报错,需要先判断 event.preventDefault && event.preventDefault(); // 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,如果不希望发生,则可以取消默认行为 return false; }; // bind()函数定义见前文 bind(box1, "DOMMouseScroll", box1.onmousewheel); };
- 键盘事件
onkeydown
: 按键被按下。对于onkeydown
,如果一直按着某个按键不松手,则事件会一直触发。当onkeydown
连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常快,这种设计是为了防止误操作onkeyup
: 按键被松开。不会连续触发- 键盘事件一般都会绑定给一些可以获取到焦点的对象,如表单项或者是
documnet
- 可以通过
keyCode
来获取按键的Unicode编码 - 除了
keyCode
,事件对象中还提供了altKey
,ctrlKey
,shiftKey
几个属性document.onkeydown = function(event){ event = event || window.event; // 通过keyCode判断哪个按键被按下 // 判断y是否被按下 if(event.keyCode == 89){ console.log("y被按下了"); } // 判断y和Ctrl是否同时被按下 if(event.keyCode === 89 && event.ctrlKey){ console.log("y和ctrl都被按下了"); } // 获取input input = document.getElementsByTagName("input")[0]; input.onkeydown = function(event){ event = event || window.event; // console.log(event.keyCode); // 数字的keyCode是48-57 // 使文本框不能输入数字 if(event.keyCode >= 48 && event.keyCode <= 57){ // 在文本框中输入内容,属于onkeydown的默认行为,如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框内,因此若要输入不能输入return false return false; } } }; dcoument.onkeyup = function(){ console.log("按键被松开了"); };
BOM
- BOM简介
- 浏览器对象模型
- BOM可以使我们通过JS来操作浏览器
- 在BOM中为我们提供了一组对象,用来完成对浏览器的操作
- BOM对象
Window
: 代表的是整个浏览器的窗口,同时window
也是网页中的全局对象Navigator
: 代表的当前浏览器的信息,通过该对象可以用来识别不同的浏览器Location
: 代表当前浏览器的地址栏信息,通过Location
可以获取地址栏信息,或者操作页面History
: 代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录。由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或后退,而且该操作只在当次访问时有效Screen
: 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
- 这些BOM对象在浏览器中都是作为
window
对象的属性保存的,可以通过window
对象来使用,也可以直接使用(因为是全局的)
- Navigator
navigator.appName
返回浏览器名称。由于历史原因,Navigator
对象中的大部分属性都已经不能帮助我们识别浏览器了。- 一般只会使用
userAgent
来判断浏览器的信息,等价于浏览器。userAgent
是一个媳妇穿,包含有用来描述浏览器信息的内容,不同的浏览器有不同的userAgent
- 判断
userAgent
中有没有浏览器名称firefox
:ua = navigator.userAgent; alert(/firefox/i.test(ua));
ua = navigator.userAgent; if(/firefox/i.test(ua)){ alert("火狐"); }else if(/chrome/i.test(ua)){ alert("Chrome"); }else if(/msie/i.test(ua)){ alert("IE10-"); } // 在IE11中已经将微软和IE相关的标识都已经去除了,所以基本已经不能通过`userAgent`来是识别浏览器是否是IE了 // 如果通过userAgent不能判断,还可以通过一些浏览中特有的对象,来判断浏览器的信息 // 比如ActiveObject if("ActiveObject" in window){ alert("你是IE"); }else { alert("你不是IE"); }
- History
- 可以用来操作浏览器向前或者向后
history.length
可以获取到当次访问的链接数量history.back()
用来回退到上一个页面,作用和浏览器的回退按钮一样history.forward()
可以跳转到下一个页面,作用和浏览器的前进按钮一样history.go()
可以用来跳转到指定的页面,需要一个整数作为参数,1
表示向前跳转一个页面,2
表示向前跳转两个页面,-1
表示向后跳转一个页面,-2
表示向后跳转两个页面
- Location
- 该对象中封装了浏览器地址栏的信息
- 如果直接打印
location
,则可以获取到地址栏的信息(当前页面的完整路径) - 如果直接将
location
属性修改为一个完整的路径(location = "https://www.baidu.com"
)或相对路径(location="01.BOM.html"
),则会自动跳转到该路径,并且会生成相应的历史记录 location.assign()
用来跳转到其他的页面,作用和直接修改location
一样location.reload()
用于重新加载当前页面,作用和刷新按钮一样- 如果在
location.reload(true)
中传入true
作为参数,则会强制清空缓存然后再刷新页面 location.replace(url)
可以使用一个新的页面,调用完毕也会跳转页面,但是不会生成历史记录
- 定时器
- 定时调用
setInterval(callback, interval)
可以将一个函数callback
每隔一段时间interval
执行一次,间隔时间单位是毫秒clearInterval()
用来关闭定时器,需要一个定时器的标识作为参数,这样将关闭对应的定时器。clearInterval()
可以接收任意参数,如果参数是一个有效的定时器标识,则停止对应的定时器,如果参数不是一个有效的标识,则什么也不做var count = document.getElementById('count'); // 使count中的内容自动切换 // JS程序执行的速度非常快,如果希望每间隔一段时间执行一次,可以使用定时调用 for(var i = 0; i < 10000; i++){ count.innerHTML = i; // 只会显示9999 } var num = 0; var timer = setInterval(function(){ count.innerHTML = num++; if(num == 11){ // 关闭定时器 clearInterval(timer); } }, 1000); // 每一秒执行一次
- 切换图片练习
window.onload = function() { // 使图片可以自动切换 var img1 = document.getElementById("img1"); // 创建一个数组保存图片路径 var imgArr = ["img/1.jpg", "img/2.jpg", "img/3.jpg", "img/4.jpg", "img/5.jpg"]; // 创建一个变量用来保存当前图片的索引 var index = 0; // 开启一个定时器用来自动切换图片 setInterval(function(){ index = (index + 1) % imgArr.length; img1.src = imgArr[index]; }, 3000); };
- 延时调用
setTimeout(callback, timeout)
表示隔一定时间之后再之此两个,而且延时调用只会执行一次clearTimeout()
关闭延时调用- 延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择
- 定时调用
- 类的操作
box.style.width = "200px"; box.style.height = "200px"; box.style.backgroundColor = "yellow"; // 通过style属性来修改元素的样式,每修改一个样式,浏览器就需要重新渲染一次页面,这样的执行性能是比较差的,而且这种形式当我们要修改多个样式时呀不太方便。我们希望一行代码就能同时修改多个样式 box.className = "b2"; // 我们可以通过修改元素的class属性来间接修改样式,这样一来,我们只需要修改一次即可同时修改多个样式,浏览器只需要重新渲染页面一次,性能比较好,并且这种方式可以使表现和行为进一步分离 box.className += " b2";
- 定义一个函数,用来向一个元素中添加或删除指定的class属性值
function addClass(obj, className){ // 检查obj中是否含有className if(hasClass(obj, className)){ obj.className += " " + className; } } function hasClass(obj, className){ // 添加类 // 判断obj的class中有没有className // var reg = /\bb2\b/; var reg = new RegExp("\\b"+className+"\\b"); return re.test(obj, ) } function removeClass(obj, className){ // 删除类 // 创建一个正则表达式 var reg = new RegExp("\\b" + className + "\\b"); // 收纳出className obj.className = obj.className.replace(reg, ""); } function toggleClass(obj, className){ // 切换一个类,如果一个元素中具有该类则删除,如果没有则添加 if(hasClass(obj, className)){ removeClass(obj, className); }else{ addClass(obj, className); } }
- 定义一个函数,用来向一个元素中添加或删除指定的class属性值
JSON
- JS中的对象只有JS自己认识,其他的语言都不认识
- JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON在卡法中主要用来数据的交互
JavaScriot Object Notation
->JS对象表示法。JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号,其他的和JS语法一致- JSON分类
- 对象
{}
:'{"name": "孙悟空", "age": 18, "gender": "男"}'
- 数组
[]
:[1, 2, 3, "hello", true]
- 对象
- JSON中允许的值:字符串、数值、布尔值、null、普通对象(不能是函数对象)、数组
JSON
类:将JSON字符串转换为JS中的对象,也可以将JS对象转换为JSON。JSON.parse()
和JSON.stringify()
// JSON-->JS对象: JSON.parse() var json = '{"name": "孙悟空", "age": 18, "gender": "男"}'; var obj = JSON.parse(json); console.log(obj.name); // JS对象-->JSON var obj = {name: "猪八戒", age: 28, gender: "男"}; var str = JSON.stringify(obj);
- JSON对象在IE7及以下浏览器中不支持,在这些浏览器中定义时会报错。
eval()
函数可以用来执行一段字符串形式的JS代码,并将执行结果返回。如果eval()
执行的字符串中含有大括号,它会将大括号当成是代码块。但是在开发中尽量不要使用,首先它的执行性能比较差,然后它还具有安全隐患var str = '{"name": "孙悟空", "age": 18, "gender": "男"}'; var obj = eval("(" + str + ")");
- 如果需要兼容IE7及以下的JSOn操作,则可以通过引入一个外部的JS文件
json2.js
(里面创建了一个JSON对象和相应的方法)