JavaScript的严格模式

7/18/2015

JavaScript在ES5版本中引入了一个新的模式'严格模式',这在javascript的各类源码中应用非常广泛。目的是帮助消除那些容易出错的语法和限制使用容易导致问题的编程方式。所以相当于一个Javascript的子集,因此用严格模式编写的javascript代码是可以在所有javascript的解释器中正常运行的。

如何使用严格模式

严格模式的使用方式很简单,只需要在代码的开始位置写上如下的代码即可

"use strict"

注意这里在使用时一定要加上引号,低版本的解释器会执行字符串,并不做任何处理,高版本(ES5)的则进行严格检查后面的代码.另外这一行代码必须放置于函数首行或者文件首行,分别代表该函数体或者文件处于严格模式下编写,解释器会进行相应的代码检查,位置如果不对的话不会进行任何操作。另外IE浏览器在版本IE10之前是不支持的。

比如现在有一个严格模式的开源代码:Angular-chart.js这段代码在首行是这样定义的:

(function (factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['angular', 'chart.js'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    module.exports = factory(require('angular'), require('chart.js'));
  } else {
    // Browser globals
    factory(angular, Chart);
  }
}
...

开源自己的代码,兼容性是很关键的问题,所以为了达到更好的兼容不同的环境,一定要在严格模式下编写代码并测试。另外这里使用立即执行代码(function(){}()),除了可以执行并获得相应的对象以外,还能保证其他使用者使用gulp脚本链接多个库文件的时候,不同文件之间不会相互污染严格模式,造成失效。就像下面的代码一样

//strict_example.js
"use strict"
function(){

}

//non-strict.js
function(){
}

当链接两个文件时,如果第二个文件在前则严格失效所以为了保证运行正常 需要将其放置到单独的作用域中执行,这样代码只会在自己的作用域解释并执行严格检查。

(function(){
      "use strict"
      function(){
          ...
      };
})();

如何编写严格模式的代码

1.变量限制

未定义限制

我们知道原生javascript对于变量声明是比较宽泛的 如果未定义一个变量则该变量自动变为一个全局变量,这很容易造成全局变量的污染。比如下面的语句,非严格模式下是不会报错的。

'use strict';
 hello=10;
//报错:ReferenceError: hello is not defined

名称限制

在定义名称的时候有两个名称是被被禁止使用的,分别是eval,和arguments两个参数

var arguments = 10;
var eval=10;
//SyntaxError: Unexpected eval or arguments in strict mode

另外对于将来保留字段的使用也做了限制 当定义变量名或者函数名为以下内容时:

implements
interface
package
private
protected
public
static
yield
//SyntaxError: Unexpected strict mode reserved word
2.自定义对象的限制

只读属性

一般情况下,我们是不需要自定义对象的属性的,但是如果我们分配了一个对象的内容为只读,当我们后面调用赋值语句时,非严格模式不会自动报错,但也不会执行赋值操作,所以下面的语句

var testObj = Object.defineProperties({}, {
    prop1: {
        value: 10,
        writable: false // by default
    },
    prop2: {
        get: function () {
        }
    }
});
testObj.prop1 = 20; 
testObj.prop2 = 30;

//非严格模式下testObj.prop1=10,保持原来的值但是不会报错提示。
//严格模式下:TypeError: Cannot assign to read only property 'prop1' of #<Object>

扩展属性

如果需要阻止对象扩展,按照如下的操作进行后,在非限制模式下不报错,但是输出为underfine

var testObj = new Object();
Object.preventExtensions(testObj);
testObj.name = "Bob";
console.log(testObj.name);
//非严格模式下:underfined,不报错
//严格模式下:TypeError: Can't add property name, object is not extensible

配置属性

当我们尝试去删除一个configurable: false的对象,不同模式下会产生什么样的情况呢?

var testObj = new Object();
Object.defineProperty(testObj, "testvar", {
    value: 10,
    configurable: false
    });
delete testObj.testvar;
//非严格模式下:不会删除testvar对象,也不会报错
//严格模式下:TypeError: Cannot delete property 'testvar' of #<Object>

重复属性

非严格模式下一个对象中如果包含有多个属性名重复时,则覆盖原有的操作所以

var testObj = {
    prop1: 10,
    prop2: 15,
    prop1: 20
};

console.log(testObj.prop1);  //20  非严格模式下
console.log(testObj.prop2);      //15  非严格模式下

//严格模式下:SyntaxError: Duplicate data property in object literal not allowed in strict mode
3.函数对象的严格模式

函数参数

之前我们已经提到过arguments是不能作为函数名定义的,另外一个限制是我们不能修改函数体内arguments的值,来传直接修改传递到函数的参数值。下面的例子中,严格模式下通过修改argument并不会对于参数argList产生影响,因为已经变成了一个copy而不是引用传递。

function test (argList) {
//    'use strict';
    arguments[0]=100;
    console.log(arguments);
    console.log(argList);
}
test(10);
//非严格模式下的输出 { '0': 100 }  100
//严格模式下的输出 { '0': 100 }  10  

参数参数调用callee

关于caller,callee的使用方法和场景在这里就不在赘述了,如果大家不了解的话可以参考一篇文章,写的还算是比较详细的介绍了arguments的这几个方法:Developer-Mozilla。只是这些方法的调用都已经被严格模式限制了,不能使用。

以下的例子代表了使用callee的典型应用,递归方法:

(function (testInt) {
    if (testInt-- == 0)
        return;
    else{
        console.log(testInt);
    }
    arguments.callee(testInt--);
})(10);
//输出内容:9,8,7,6,5,4,3,2,1,0
//严格模式下输出:TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
4.with的使用限制

with本身是个非常不高效的javascript用法,当然他的确可以简化内部调用的代码编写,但是如果with代码块中包含了非对象所有的函数或者对象属性,他也会在其中进行查找。除非你能确保的确不存在重名的属性。

var testObj={
    name:"mike",
    address:"Beijing"
}

var sayHello="hello my name is Z";
with(testObj){
    console.log(name);
    console.log(sayHello);  //hello my name is Z
}
testObj.sayHello=" Hello my name is Mike";

with(testObj){
    console.log(name);
    console.log(sayHello);  
   //Hello my name is Mike
}

上述中代码由于包含了一些重复名称的属性,可能是过程中修改了,添加了一些属性。导致在调用的时候无法真正的预测实际的输出是什么。

5.this限制

当在一个函数中未定义this对象时在非严格模式下 将会返回global对象,而在严格模式下则为underfined

如下代码

var fun=function(){
    return this;
}
console.log(fun());
//非严格模式:依据环境不同返回不同的全局变量
//严格模式下:underfined
6.eval执行限制

对于eval代码的执行,在严格模式下是无效的

eval("var a=10");
console.log(a);
//严格模式下未定义
//非严格模式下:10
7.语句块中定义函数
var arr = [1, 2, 3, 4, 5];
var index = null;
for (index in arr) {
    function myFunc() {console.log(10);};
    myFunc()
}
//非严格模式:10,10,10,10,10
//严格模式:SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function.

对于语句块中定义的函数在严格模式是被限制使用的,

以上基本上就是关于javascript严格模式的定义和编写中需要注意的事项了,本身我也是一个javascript的初学者,为了更好的理解和应用到自己的代码中,看来还需要多加练习才能慢慢掌握这些内容。学习编程真的是需要多读源码,多思考,多练习才行!


前端技术 Javascript 页面已被访问4545次

发表评论