天天看点

Javascript严格模式详解

一、概述

1、什么是严格模式?

除了正常模式意外,ES5(2009年发布)还添加了一种模式,即“严格模式”。这种模式使javascript在更加严格的条件下运行。

2、为什么使用严格模式?

  • 消除javascript语言中一些不合理、不严谨之处,减少怪异现象;
  • 消除代码运行的一些不安全的地方,保证代码运行的安全;
  • 提高编译器效率,提高运行速度;
  • 为未来新版本的javascript打好基础;

3、怎么使用严格模式?

(1)针对整个脚本调用:

<script>
        "use strict";

</script>
           

"use strict"

放在所有可运行代码之前,则整个脚本将在“严格模式”下运行。

这个写法不利于函数合并,更好的方法:

<script>
       (function(){
           "use strict";

       })();
 </script>
           

(2)针对单个函数:

function fn(){
"use strict";

}
           

"use strict";

放在函数体所有可运行代码之前则整个函数体将在“严格模式”下运行。

二、严格模式和普通模式的区别:

1、全局变量必须显示声明

"use strict";
a=;
console.log(a);//ReferenceError: a is not defined
           

2、静态绑定

javasript语言有一个特点,即允许动态绑定(某些属性和方法不是在编译时确定的,而是在运行时确定的)。

严格模式对动态绑定做出了一点限制。某些情况下,只允许静态绑定(属性和方法到底归属哪个对象,在编译阶段就应该确定)。优点:有利于编译效率的提高,也使代码更加容易阅读,更少出现意外。

(1)禁止使用with语句

"use strict";
var obj={
    name:'lwf',
    age:
}
with(obj){//SyntaxError: Strict mode code may not include a with statement
    var name1=name;
    var age1=age;
}
           

另外,由于使用with语句会导致性能下降,同时也会给调试代码带来困难,因此开发过程中,不建议使用with。

(2) 创建eval作用域

正常模式下有两种作用域,即全局作用域和函数作用域,eval的作用域取决于其处于全局作用域和函数作用域。

严格模式下,会增加eval作用域。eval内生成的变量只能在eval中访问。

正常模式下:

var a=;
var b=;
eval("console.log(a)");//1
eval("var b=3;console.log(a)");//1
eval("console.log(b)");//3
           

严格模式下:

"use strict";
var a=;
var b=;
eval("console.log(a)");//1
eval("var b=3;console.log(a)");//1
eval("console.log(b)");//2
           

3、增强安全措施

(1)禁止this关键字指向全局变量

function f1(){
    console.log(!this);//false,正常模式下,this指向全局变量
}
f1();
function f2(){
    "use strict";
    console.log(!this);//true,严格模式下,this指向undefined,所以!this为true
}
f2();
           

(2)禁止在函数内部遍历调用栈

function f3(){
    console.log(f3.arguments);//{ '0': 1, '1': 2, '2': 3 }
}
f3(,,);
function f4(){
    "use strict";
    console.log(f4.arguments);//TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.
}
f4(,,);
           

4、禁止删除变量

正常模式和严格模式下都禁止删除变量

正常模式:

var x=
delete x;//删除变量会直接忽略
console.log(x);//4
           

删除变量:

"use strict";
var y=;
delete y;//SyntaxError: Delete of an unqualified identifier in strict mode.
console.log(y);
           

5、显式报错

(1)正常模式下,对一个对象的只读属性赋值,不会报错,只会默默的失败;

严格模式下,将报错。

正常模式:

var obj3={};
 Object.defineProperty(obj3,'name',{value:,writable:false});
 obj3.name=;
 console.log(obj3.name);//1,没有报错
           

严格模式:

"use strict";
var obj4={};
Object.defineProperty(obj4,'name',{value:,writable:false});
obj4.name=;//TypeError: Cannot assign to read only property 'name' of object '#<Object>'
console.log(obj4.name);
           

(2)正常模式下,对一个使用getter方法读取的属性进行赋值,不会报错,只会默默的失败;

严格模式下,会报错

var o={
    get v(){return }
}
console.log(o.v);//1
o.v=;
console.log(o.v);//1
           
"use strict";
var o={
    get v(){return }
}
console.log(o.v);//1
o.v=;//TypeError: Cannot set property v of #<Object> which has only a getter
console.log(o.v);
           

(3)正常模式下,对禁止扩展的对象添加属性,不会报错,只会默默失败;

严格模式下,会报错

var o={};
Object.preventExtensions(o);
o.v=;
console.log(o.v);//undefined
           
"use strict";
var o={};
Object.preventExtensions(o);
o.v=;//TypeError: Cannot add property v, object is not extensible
console.log(o.v);
           

6、重名错误

(1)函数不能有重名的参数

正常模式下,如果函数有重名参数,可以使用arguments[i]读取;

严格模式下,会报错。

function fn(a,a,b){
    console.log(arguments[]);//1
    console.log(arguments[]);//2
    return a;
}
console.log(fn(,,));//2
           
"use strict";
function fn(a,a,b){//SyntaxError: Duplicate parameter name not allowed in this context
    console.log(arguments[]);
    console.log(arguments[]);
    return a;
}
console.log(fn(,,));
           

7、禁止八进制表示法

var n=;
console.log(n);//64
           
"use strict";
var n=;//SyntaxError: Octal literals are not allowed in strict mode.
console.log(n);
           

8、arguments对象的限制

(1)不允许对arguments对象进行赋值

function fn1(){
console.log(arguments++);//NaN
}
fn1(,);
           
"use strict";
function fn1(){
console.log(arguments++);//SyntaxError: Unexpected eval or arguments in strict mode
}
fn1(,);
           
"use strict";
var obj = { set p(arguments) { } }; // 语法错误
try { } catch (arguments) { } // 语法错误
function arguments() { } // 语法错误
var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误
           

(2)arguments不在追踪参数的变化

function fn1(a){
    a=;
    console.log(arguments[],a);//2,2
}
fn1();
           
"use strict";
function fn1(a){
    a=;
    console.log(arguments[],a);//1 2
}
fn1();
           

(3)禁止使用arguments.callee

这意味着无法在匿名函数里面调用自身

function fn1(){
   console.log(arguments.callee);//[Function:fn1]
}
fn1();
           
"use strict";
function fn1(){
   console.log(arguments.callee);//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
fn1();
           

9、函数声明必须在顶层

严格模式下,只允许在全局作用域或函数作用域的顶层声明函数。不允许在非函数的代码块中声明函数。

if(true){
    function fn(){
        console.log();
    }
}
fn();
           
"use strict";
if(true){
    function fn(){
        console.log();
    }
}
fn();//ReferenceError: fn is not defined
           

10、保留字

严格模式下新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield

使用这些词作为变量名将报错。

function fn1(){
    var let=;
    console.log(let);
}
fn1();//1
           
"use strict";
function fn1(){
    var let=;//SyntaxError: Unexpected strict mode reserved word
    console.log(let);
}
fn1();
           

此外,ECMAscript第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的。

参考:阮一峰的JavaScript严格模式详解

继续阅读