1.严格模式
1.什么是严格模式:在原有的js运行机制上增加了一系列约束,来约束原有js中包含的缺陷和功能。
2.启用严格模式:在但钱作用域的顶部添加:‘use strict’;
3.严格模式新增的约束:
①禁止给未声明的变量赋值;
原js中,给未声明的变量赋值,不会报错,会在全局中声明一个变量并强行赋值,会造成全局污染和内存泄漏;
在严格模式下,会报错,不会在全局中声明变量。
②静默失败升级为失败,会报错;
静默失败:执行不成功,也不会报错。容易产生歧义,干扰调试。
③普通函数调用和匿名函数自调中的this不再指向window,而是指向undefined。
避免了因为this引起的全局污染和内存泄漏
④禁用了arguments.callee
arguments.callee:专门在函数内部获得当前正在执行的函数自己,虽然arguments.callee可以实现递归算法的松耦合,但是,严格模式下不推荐使用递归算法,因为递归的运行效率极低(重复计算量极大)
原js中几乎所有递归调用都应该使用arguments.callee// 斐波那契数列 // 递归思路,原js使用arguments.callee获得当前正在执行的函数自己 function f(n) { if(n < 3) { return 1; } else { return arguments.callee(n - 1) + arguments.callee(n + 1); } } // 循环思路 function f(n) { if (n < 3) { return 1; } else { var f1 = 1, f2 = 1, fn; for (var i = 3; i <= n; i++ ) { fn = f1 + f2; f1 = f2; f2 = fn; } return fn; } }
2.保护对象
1.什么是保护对象:阻止程序对一个对象执行不合常理的修改。
原js,没有保护对象
①保护单个属性:阻止对对象中某个属性执行不合常理的修改;
②保护对象结构:阻止乱添加删除属性。ES5对对象的属性也进行了分类
(1)命名属性:所有可用 ‘.’ 访问的属性–需要保护,又进一步分为:①数据属性:实际存储属性值的属性;②访问器属性:自己不实际存储属性值,而是对另一个弱小的数据属性提供保护。
(2)内部属性:存在于对象中,但是不允许使用 ‘.’ 访问的属性–不需要保护。如何保护一般的数据属性
ES5中的每个数据属性都存在四个属性值,分别是:①value(存储属性值);②writable(属性值是否可修改:true/false);③enumerable(是否允许for in循环遍历到这个属性,半隐藏属性);④configurable(是否可以删除,同时控制着writable和enumerable属性值是否可以修改);
怎么修改数据属性的属性值?
①单个数据属性修改:Object.defineProperty(对象名, '属性名', { writable/enumerable/configurable: true/false, ... : ... } );
②同时修改多个数据属性的属性值:
Object.defineProperties(对象, { 属性名1:{ writable/enumerable/configurable: true/false , ... : ... }, { 属性名2:{ writable/enumerable/configurable: true/false }, {... : ...} } );
3.访问器属性
①访问器属性:自己不实际保存属性值,仅提供对另外一个数据属性的保护。
②使用访问器属性:使用访问器的属性跟使用普通属性的方法一样。
(1)获取访问器的属性值:对象名.属性名;
当外界想获取访问器属性的属性值时,js会自动调用访问器属性的get()方法,从实际保存数据的半隐藏的属性中,读取出现在的属性值,return给外部
(2)修改访问器的属性值: 对象名.属性名 = 新值;
当外界想修改访问器属性的属性值时,js会自动调用set()方法,把新值传给set()方法的形参,并在验证后保存或者报错var student = { sid: 101, sage: 18, grade: 1 } // 学生的年级(grade)可以修改,且范围只能在1-4 // ①创建一个半隐藏属性保存当前属性 Object.defineProperty(student, "_grade", { value: student.grade, writable: true, enumerable: false, // 半隐藏 configurable: false }); // ②设置该属性的get()和set()方法 Object.defineProperty(student, 'grade', { // 读取现在的属性值,返回到外部 get() { return this._grade; }, // 接受外部的新值(value),验证通过则保存,不通过则报错 set(value) { if (value >= 1 && value <= 4) { this.grade = value; } else { throw Erro("班级超出范围"); } }, // 因为访问器属性步存储实际的属性值,所以没有value和writable属性 enumerble: true, configurable: false });
4.保护对象的结构
禁止对对象添加新属性,删除现有属性;
①防扩展: Object.preventExtensions(对象);禁止对对象添加新属性。
原理:每个对象都有一个内部属性extensible,默认为true,调用Object.preventExtensions(对象)后会自动把extensible设为false,从而禁止添加新属性
②密封:Object.seal(对象);禁止对对象添加新属性和删除现有属性
原理:把对象的内部属性extensble(是否可以添加新属性)和configurable(是否可以删除现有属性)都设为false
③冻结: Object.freeze(对象);禁止对对象添加新属性和删除现有属性,还禁止修改对象的属性值
原理:把对象的内部属性extensble(是否可以添加新属性)和configurable(是否可以删除现有属性)都设为false, 并且把对象的writable(是否可以修改属性的属性值)设为false