什么是严格模式?
严格模式是ECMAScript5的新特性,它是采用具有限制性JavaScript变体的一种方式,从而使代码隐式地脱离“马虎模式/稀松模式/懒散模式”(sloppy)模式。
它允许你把整个程序,或者某个函数,放置在"严格"的操作语境中。这种严格的语境会防止某些特定的操作并抛出更多的异常。
虽然ECMAScript 5 对ECMAScript 3是向下兼容的,但是在严格模式下,所有在ECMAScript 3 中不赞成使用的特性都被禁用(或抛出错误)而不是兼容。
启动严格模式有以下好处:
捕获一些编程器错误,并抛出异常
阻止进行一些相对“不安全”的操作(例如访问全局变量),抛出异常。
禁用一些让人迷惑的操作。
如何启用严格模式
在程序的开头添上这条语句即可对整段脚本启用严格模式:
'use strict'
也可以只在函数内部启用严格模式,这样就不会影响到外部
function useStrict(){
'use strict';
//internal code
}
启用严格模式的语句只是一段普通的字符串“use strict”,没有任何新语法。这意味着不会对就旧式浏览器造成任何负面影响。
严格模式下的脚本变化
变量和属性
1、对未定义变量的赋值将会失败,而不是把这个变量作为全局变量。
2、严格模式下:写入一个可写特性为false的属性,删除一个可配置特性为false的属性,或者添加一个可扩展性为false的属性,都会导致错误。
不在严格模式下的话,这些操作不会抛出异常,仅仅是静默失败。
//对变量、函数或者函数参数执行delete操作会导致错误
var x = 'test';
function test(arg){
delete arg; //Error
}
delete x; //Error
delete test; //Error

eval
任何对“eval”这个名字的使用(主要意图是把eval函数指向一个变量或者是对象的属性)都是禁止的

另外,通过eval声明新变量也会无效;
'use strict'
eval("var a = false");
console.log(typeof a); //undefined
如果去掉严格模式
eval("var a = false");
console.log(typeof a); //Boolean
什么是eval?
eval()函数会将传入的字符串当做JavaScript代码进行执行。
参数:String
返回值:返回字符串中代码的返回值。如果返回值为空,则返回undefined。

那为什么使用let或者const会报错呢?
var 声明的变量和使用 function 声明的函数会修改全局作用域,里面使用 let 和 const 声明的变量不会修改全局作用域,但是会在全局环境创建新的词法作用域。(作用域的问题)

这样写就不存在作用域问题。
eval的缺点:
eval() 中执行的代码只能调用 JS 解释器(Interpreter)来解释执行,无法被即时编译器(JIT Compiler)优化,eval() 中的执行的代码可能会导致 JS 引擎在已经生成的机器代码中进行变量查找和赋值,带来性能问题。(无法优化,性能问题)
eval() 使用不当可能会导致里面执行的字符串容易遭受恶意修改,带来安全问题(比如 XSS 攻击)。(安全问题)
使用 eval() 会干扰代码压缩工具的行为。代码压缩工具一般会将局部变量名重命名为更短的变量名(如 a 和 b 等),以便减小代码体积。当使用了 eval() 时,由于外部的局部变量可能会被 eval() 访问到,代码压缩工具便不会对可能会被 eval() 访问到的局部变量名进行压缩,会降低代码压缩率。 (降低代码压缩率)
函数
重写arguments对象会导致报错
arguments=[]

同名参数会导致报错
(function(foo,foo){}) //Error
// 非严格模式
(function () {
function fn(a ,a, b){
console.log(a,b);
}
fn(1,2,3)
})(); // 结果: 2 3
// 严格模式
(function () {
"use strict";
function fn(a ,a, b){
console.log(a,b);
}
fn(1,2,3)
})(); // 报错:SyntaxError: Duplicate parameter name not allowed in this context
实参形参和arguments的分离
// 非严格模式
// arguments 会受到 形参赋值的影响;
(function(){
function fn(a,b){
a = 20;
console.log(a,b); // 20 2
console.log(arguments[0],arguments[1]); // 20 2
}
fn(1,2)
})();
// 严格模式
(function(){
"use strict";
// 形参 和 arguments 之间的区别;
// 形参是变量可以随意赋值;
// arguments 就是对应实参的关键字获取所有的实参,进行使用,不会被改变;
function fn(a,b){
a = 20;
console.log(a,b); // 20, 2
console.log(arguments[0],arguments[1]); // 1, 2
}
fn(1,2)
})();
arguments 的严格使用,部分功能禁用了
淘汰了 arguments.callee(引用函数本身) 和 arguments.caller(引用调用函数)。
在非严格模式下,这两个属性一个是引用函数本身,一个是引用调用函数。而在严格模式下,这两个属性都被禁用了。
(function(){
function fn(){
// arguments.callee 指向了当前的函数本身;
console.log(arguments.callee);
}
fn()
})(); // 结果: ƒ foo(){console.log(arguments.callee);}
(function(){
"use strict";
function fn(){
// 禁用掉了大部分arguments的属性;
console.log(arguments.callee)
}
fn()
})(); // 报错:TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments
未声明变量辅助
如果给一个没有声明的变量赋值,那代码在执行的时候就会抛出错误

当使用null或者undefined作为Function.prototype.call或Function.prototype.apply方法的第一个参数时,函数内部的this将会指向全局对象。而严格模式将会阻止其执行并抛出异常:
(function(){ ... }).call(null); // Exception
this指向
在非严格模式下,null 或 undefined 值会被转换为全局对象 window。
在严格模式下,函数的 this 值始终是指定的值,无论指定的是什么值。
(function(){
function fn(){
// this 指向 window;
console.log(this);
}
fn()
})(); // 结果:Window
(function(){
"use strict";
function fn(){
// 禁用指向了 window 的 this,让 this 指向 undefined
console.log(this);
}
fn()
})(); // 结果:undefined
with(){}
在严格模式下,with完全不能使用
(function(){
with(Math){
// 可以省略对象前置;
console.log(random()); // => Math.random()
console.log(PI); // => Math.PI
}
})();
// 严格模式之下禁用 with(){}
(function(){
"use strict";
with(Math){
console.log(random());
console.log(PI);
}
})(); // 报错:Uncaught SyntaxError: Strict mode code may not include a with statement
在非严格模式下,with可以改变作用域链,他可以让他里面的代码的作用域链的最顶端变成 with 括号里面的这个对象。但是会消耗大量的效率,故而ES5为了提高效率,禁用了with语句。