JS 基础篇(五):JS严格模式

2,114 阅读5分钟

一、严格模式介绍

除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode)。顾名思义,这种模式使得Javascript在更严格的条件下运行。

设立"严格模式"的目的,主要有以下几个:

  • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;

  • 消除代码运行的一些不安全之处,保证代码运行的安全;

  • 提高编译器效率,增加运行速度;

  • 为未来新版本的Javascript做好铺垫。

"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。

另一方面,同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。

二、严格模式使用

1、为整个脚本开启严格模式

为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)

// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi!  I'm a strict mode script!";

2、为函数开启严格模式

要给某个函数开启严格模式,得把 "use strict"; (或 'use strict'; )声明一字不漏地放在函数体所有语句之前。

function strict(){
  // 函数级别严格模式语法
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function notStrict() { return "I'm not strict."; }

三、严格模式的改变

1、普通变量

  • 严格模式下,变量都必须先用var命令声明,然后再使用。
  • 严格模式下对不可写属性赋值,将报错。
  • 严格模式下对只读属性赋值,将报错。
  • 严格模式下对禁止扩展的对象添加新属性,将报错。
  • 严格模式下删除一个不可删除的属性,将报错。
  • 严格模式下删除声明变量,将报错。
  • 严格模式下对八进制语法:var n = 023和var s = "\047"将报错。
//严格模式下,变量都必须先用var命令声明,然后再使用。
//在正常模式中,变量没有声明就赋值,默认是全局变量。
demo1 = "success";
console.log(demo1); // 报错

//严格模式下对不可写属性赋值,将报错。
var demo2 = {};
Object.defineProperty(demo2, "x", { value: 42, writable: false });
demo2.x = 9; //报错

//严格模式下对只读属性赋值,将报错。
var demo3 = { get x() { return 17; } };
demo3.x = 5;  //报错

//严格模式下对禁止扩展的对象添加新属性,将报错。
var demo4 = {};
Object.preventExtensions(demo4);
demo4.newProp = "ohai"; //报错

//严格模式下删除一个不可删除的属性,将报错。
delete Object.prototype; //报错

//严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。
var x;
delete x; // 报错

var demo5 = Object.create(null, {'x': {
    value: 1,
    configurable: true
}});
delete demo5.x; // 删除成功

//严格模式下对八进制语法:var n = 023和var s = "\047"将报错。
var n = 023; //报错

2、重名问题

严格模式下函数不能有重名的参数

//严格模式下函数不能有重名的参数
//正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。
function demo6(a,a,b){return ;} //报错

3、禁止this关键字指向全局对象

严格模式下,全局作用域的函数中的this不再指向全局而是undefined。
如果使用构造函数时,如果忘了加new,this不再指向全局对象,而是undefined报错。

function demo7_1(){
    console.log(this);
}
function demo7_2(){
    function demo7_3(){
    console.log(this);
    }
    demo7_3();
}
demo7_1(); //undefined
demo7_2(); //undefined

function demo7_4(){
   this.a = 1;
};
demo7_4();// 报错,使用构造函数时,如果忘了加new,this不再指向全局对象,而是undefined.a。

4、静态绑定

  • 禁止使用with语句
  • eval语句本身就是一个作用域,它所生成的变量只能用于eval内部。
//严格模式下禁用with
var demo8 = 1;
with (o){ // 报错 
  demo8 = 2;
}

//正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。
//严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
//严格模式下,eval语句内传入的字符串也是按照严格模式执行。
function demo9() {
    var x = 2;
    eval("var y = 1; console.log(y); "); //1
    eval("var x = 12");
    console.log(x); //2
    console.log(y); //报错:y is not defined
}
demo9();

5、arguments对象的限制

  • 不允许对arguments赋值
  • arguments不再追踪参数的变化
  • 禁止使用arguments.callee
//不允许对arguments赋值
arguments++; //报错

//arguments不再追踪参数的变化
//在非严格模式中,修改arguments对象中某个索引属性的值,和这个属性对应的形参变量的值也会同时变化,反之亦然。
//在严格模式中arguments 对象会以形参变量的拷贝的形式被创建和初始化,因此arguments对象的改变不会影响形参。
function demo10_1(a) {
    a = 2;
    return [a, arguments[0]];
}
console.log(demo10_1(1)); // 正常模式为[2,2]

function demo10_2(a) {
    "use strict"
    a = 2;
    return [a, arguments[0]];
}
console.log(demo10_2(1)); // 严格模式为[2,1]

//禁止使用arguments.callee
var demo11 = function() { return arguments.callee; };
demo11(); // 报错

6、禁止在函数内部遍历调用栈

function demo12(){
    demo12.caller; // 报错
    demo12.arguments; // 报错
}
demo12();

7、保留字

使用未来保留字(也许会在ECMAScript 6中使用):implements, interface, let, package, private, protected, public, static,和yield作为变量名或函数名会报错。