严格模式
严格模式是什么
严格模式是JavaScript中的一种限制性更强的变种方式。严格模式不是一个子集:它的语义上与正常代码有着明显的差异。
不支持严格模式的浏览器与支持严格模式的浏览器行为上也不一样,所以在未经严格模式特性测试情况下使用严格模式。
严格模式可以与严格模式共存,所以脚本可以逐渐的选择性加入严格模式。
严格模式的目的
首先,严格模式会将JavaScript陷阱直接变成明显的错误。
其次,严格模式修正了一些引擎难以优化的错误;同样的代码有些时候严格模式会比严格模式下更快
第三,严格模式禁用了一些有能在未来版本中定义的语法。
开启严格模式
全局开启严格模式
在JavaScript中想要开启严格模式,需要在所有代码之前,定义一个不会赋给任何变量的字符串
"use strict";//或者'use strict'
函数开启严格模式
也可以为某个指定的函数开启严格模式,
//函数外依旧是非严格模式
function doSomething(){
"use strict";//开启严格模式
//其他代码
}
在匿名函数中使用严格模式,相当于在全局开启严格模式的变通事项方式。
(function(){
"use strict";//开启严格模式
})();
代码:
// 开启严格模式 - 作用于全局作用域
// "use strict"
// 定义一个变量 - 不使用var关键字
a = 100;
console.log(a);
function fn(){
// 开启严格模式 - 作用于函数作用域
"use strict"
v = 200;
console.log(v);
}
fn();
效果:
变量
禁止意外创建变量
在严格模式下,不允许意外创建全局变量
-
如下代码是非严格模式下意外创建全局变量
//未声明变量 message = "this is message"
-
如下代码是严格模式下意外创建全局变量
"use strict";//开启严格模式 //严格模式下,意外创建全局变量,抛出ReferenceError
// 开启严格模式
"use strict";
v = 100;
console.log(v);
function fn(){
// 在非严格模式:在函数作用域中定义变量 - 不使用var关键字 -> 自动将其提升为全局变量
w = 200;
console.log(w);
}
fn();
console.log(w);
效果:
- 开启严格模式后,定义变量要带var,否则会报错
静默失败转为异常
所谓静默失败就是既不报错也没有任何效果,例如改变常量的值 。在严格模式下,静默失败会转换成抛出异常。
-
如下代码是非严格模式下的静默失败。
const PI = 3.14; PI = 1.14//静默失败 console.log(PI);//3.14
-
如下代码是严格模式下的静默失败。
"use strict";//开启严格模式 const PI = 3.14; PI = 3.14//抛出TypeError错误
代码:
// 开启严格模式
"use strict";
const v = 3.14;// 定义常量
v = 1.14;// 重新赋值
console.log(v);
效果:
禁用delete关键字
在严格模式下,不能对变量使用delete运算符。
-
如下代码是非严格模式下使用delete运算符,结果会静默失败
var color = "red"; delete color
-
如下代码是严格模式下使用delete运算符,结果会抛出异常。
"use strict";//开启严格模式 var color = "red"; delete color;//抛出ReferenceError错误
代码:
// 开启严格模式 "use strict"; // 严格模式下禁用delete关键字 -> 针对删除变量,而不是数组元素和对象属性 // var v = 100;// 定义一个全局变量 // console.log(v); // // delete v;// 删除全局变量v // console.log(v);// undefined // var arr = [1,2,3,4,5]; // delete arr[0]; // console.log(arr); var obj = { name : '肖德硕' } delete obj.name; console.log(obj.name);
对变量名的限制
在严格模式下,JavaScript对变量名的限制。特别不能使用如下内容作为变量名:
上述内容都是保留字,在ECMAScript的下一个版本中可能会用到他们。
在严格模式下,使用上述标识符作为变量名会导致语法错误
// 开启严格模式
"use strict";
var static = 100;
console.log(static);//SyntaxError: Unexpected strict mode reserved word
对象
不可删除属性
在严格模式下,不能使用delete运算符删除不可删除的属性。
-
如下代码是非严格模式下使用delete运算符删除不可删除的属性,结果会静默失败。
delete Object.prototype
-
如下代码是严格模式下使用delete运算符删除不可删除的属性,结果会抛出异常
"use strict";//开启严格模式 delete Object.prototype;//抛出TypeError错误
代码:
// 开启严格模式
"use strict";
// delete Object.prototype;
// console.log(Object.prototype);
delete Math.random;
console.log(Math.random);
// Math.random();
属性名必须唯一
在严格模式下,一个对象内的所有属性名在对象内必须唯一。
-
如下代码是非严格模式下重名是允许的,最后一个重名的属性决定其属性值。
var o = { p : 1, p : 2 };
-
如下代码是严格模式下重名属性被认为是语法错误
"use strict";//开启严格模式 var o = { p : 1, p : 2 };
代码:
// 开启严格模式
"use strict";
// 对象具有相同名称的属性时 - 编辑器报错(不是运行时报错)
var obj = {
name : '肖德硕',
name : '小肖'
}
console.log(obj.name);
效果:
只读属性的赋值
在严格模式下,不能为一个只读的属性进行重新赋值。
-
如下代码是非严格模式为只读属性重新赋值,结果会静默失败。
var obj1 = {}; Object.defineProperty(obj1,"x",{ value : 42, writable : false });//将属性设置为只读 obj1.x = 9;
-
如下代码是严格模式下为只读属性重新赋值,结果会抛出异常
"use strict";//开启严格模式 var obj1 = {}; Object.defineProperty(obj1,"x",{ value : 42, writable : false });//将属性设置为只读 obj1.x = 9;//抛出TypeError错误
代码:
// 开启严格模式
"use strict";
var obj = {
name : '肖德硕'
}
// 用于判断指定属性是否为只读属性
var result = Object.getOwnPropertyDescriptor(obj, 'name');
console.log(result);
// 定义对象obj的只读属性
Object.defineProperty(obj, 'age', {
value : 18
});
// 针对只读属性进行修改操作
// obj.age = 80;
// console.log(obj.age);
delete obj.age;
console.log(obj.age);
效果:
不可扩展的对象
在严格模式下,不能为不可扩展的对象添加新属性。
-
如下代码是非严格模式为不可扩展的对象添加新属性,结果会静默失败。
var obj = {}; Object.preventExtensions(obj);//将对象变的不可扩展 obj.newProp = 'ohai';
-
如下代码是严格模式不可扩展的对象添加新属性,结果会抛出异常。
"use strict";//开启严格模式 var obj = {}; Object.preventExtensions(obj);//将对象变的不可扩展 obj.newProp = 'ohai';//抛出TypeError错误
代码:
// 开启严格模式
"use strict";
var obj = {};
// 设置对象obj是一个不可扩展的对象
Object.preventExtensions(obj);
// 为对象obj新增属性
obj.name = '肖德硕';
console.log(obj);
效果:
函数
参数名必须唯一
在严格模式下,要求命名函数的参数必须唯一。
-
如下代码是非严格模式下最后一个重名参数会掩盖之前的重名参数,之前的参数仍然可以通过arguments[i]来访问
function sun(a,a,c){}
-
如下代码是严格模式下重名参数被认为是语法错误。
function sun(a,a,c){//!!!语法报错 "use strict"; return a + a + c;//代码运行到这里会出错 }
代码:
// 开启严格模式
"use strict";
function fn(a, a, b){
console.log(a + a + b);
}
fn(1,2,3);
效果;
arguments的不同
在严格模式下,arguments对象的行为也有所不同。
- 非严格模式下,修改命名参数的值也会反应到arguments对象中。
- 严格模式下,命名参数与arguments对象是完全独立的。
// 开启严格模式
"use strict";
function fn(value){
var value = '肖德硕';
console.log(value);// 肖德硕 -> 就近原则
/*
非严格模式下 - arguments对象获取参数的值与形参有关的
如果局部变量与形参名相同 - 根据就近原则进行获取
严格模式下 - arguments对象获取参数的值与形参无关的
*/
console.log(arguments[0]);// 非严格模式 -> 肖德硕 严格模式 -> 小肖
}
fn('小肖');
效果:
arguments对象的callee()方法
在严格模式下,不能使用arguments对象的callee()方法。
-
如下代码是非严格模式下使用arguments对象的callee()方法,表示调用函数本身。
var f = function(){ return arguments.callee; }; f();
-
如下代码是严格模式下使用arguments对象的callee()方法,结果会抛出异常。
"use strict";//开启严格模式 var f = function(){ return arguments.callee; }; f();//抛出TypeError错误
代码:
// 开启严格模式
"use strict";
// 在严格模式下,arguments对象无法调用callee()方法
function fn(){
console.log(arguments.length);
// return arguments.callee;//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
fn();
函数声明的限制
在严格模式下,只能在全局域和函数域中声明函数。
-
如下代码是非严格模式下在任何位置声明函数都是合法的
if(true){ function f(){} }
-
如下代码是严格模式下在除全局域和函数域中声明函数是语法错误。
"use strict";//开启严格模式 if(true){ function f(){}//!!!语法错误 }
代码:
// 开启严格模式
"use strict";
// 在全局作用域
function fn(){
// 在函数作用域
function n(){}
}
// 在严格模式下,函数的定义只能在全局作用域与函数作用域(不能在块级作用域定义函数)
for (var i=0; i<10; i++) {
// ECMAScript 6新增 - 存在着块级作用域
var v = 100;
function f(){
console.log('this is function');
}
}
console.log(v);
f();
效果:
增加eval作用域
在严格模式下,使用eval()函数创建的变量只能在eval()函数内部使用。
-
如下代码是非严格模式下eval()函数创建的变量在其他位置可以使用。
eval("var x = 42"); console.log(x);//42
-
如下代码是严格模式下eval()函数创建的变量只能在eval()函数内部使用。
"use strict";//开启严格模式 eval("var x = 42"); console.log(x);//抛出ReferenceError错误
代码:
// 开启严格模式
"use strict";
// 在严格模式下,增加eval作用域 - eval()函数定义的变量只能在当前eval()函数中使用
eval('var v = 100;');
// 在全局作用域中调用变量 - 报错
console.log(v);// 100
效果:
arguments和eval禁止作为标识
禁止读写
在严格模式下,arguments和eval()禁止作为标识符,也不允许读写他们的值
- 使用var声明
- 赋予另一个值
- 尝试修改包含的值
- 用作函数名
- 用作命名的函数的参数
- 在try……catch语句中用作例外名
在严格模式下,一下所有尝试将导致语法错误:
// 开启严格模式
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");
抑制this
- 在非严格模式下使用函数的apply()或call()方法时,null或undefined值会被转换为全局对象
- 在严格模式下,函数的this值始终是指定的值(无论什么值)。
// 开启严格模式
"use strict";
var v = 100;
function fn(){
console.log(this.v);
}
var obj = {
v : 200
}
fn.call(obj);// this指向全局对象