美文网首页
Javascript学习笔记-Strict Mode

Javascript学习笔记-Strict Mode

作者: Patrick浩 | 来源:发表于2017-07-30 11:34 被阅读0次
    Strict Mode.png

    代码中经常看到使用这样的声明,却一直不知道有什么作用,直到有一天。。。

    1. 历史

    ES5开始使用Directive Prolog,并据说直到现在也只有'use strict'一个实现,至于引入Strict Mode的原因,总的来还是对JS兼容性对处理。
    第一,为了处理未来即将废弃或修改的JS方法,告诉大家别这样用了(直接抛出异常了)。
    第二,为了未来兼容的JS实现,告诉大家以后的JS这样做是这个效果。
    也就是为了JS更好的发展,作出的一些JS内容上的约束。

    2. 声明位置

    作为一个Directive Prolog,只需要使用'use strict'这样的语法,就可以声明为Strict Mode,主要影响范围会有两个:

    2.1 全局使用

    也就是全局都声明为Strict Mode了,一般不推荐,因为会对所有的Script引用脚本造成影响,破坏力不可言喻,所以尽量不要这样使用。

    2.2 方法中使用

    这是推荐的方法,只对局部代码作用,这样也不会对其他内容产生影响,于是就这样在方法内使用吧。

    function f(){
      'use strict'
      // 大括号内都有效了,不影响括号外内容
    }
    x = 1;
    f()
    

    当然这样也是可以的

    (function(){
        'use strict'
    })()
    

    3. 使用影响

    3.1 对变量的影响

    3.1.1 变量声明

    使用不声明的变量,会抛出异常,防止莫名其妙的引入全局变量

      'use strict'
      x = 1 // 愉快的抛出了异常 Uncaught ReferenceError: x is not defined
    
    3.1.2 变量命名

    使用关键字/保留字作为变量名,抛出异常,常用的关键字:private, package ,protected , interface , implements ,let , static , yield,当然不仅仅局限于这些,可以自行尝试

    function f(){
      'use strict'
      var private = 1 // 很友善的异常信息 Uncaught SyntaxError: Unexpected strict mode reserved word
    }
    f()
    
    3.1.3 变量赋值

    只读/只有get方法/不可扩展对象属性赋值,都没办法正常赋值,都会抛出异常

    function f(){
        'use strict'
        // 只读属性
        var obj = {};
        Object.defineProperty(obj, 'x', {value:1 , writable: false, configurable: true});
        obj.x = 2; // Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>'
        // 只有get方法
        var obj = {
            get x() {
               return 1;
            }
         }
         obj.x = 2; // Uncaught TypeError: Cannot set property x of #<Object> which has only a getter
        // 不可扩展对象
        var obj = {};
        Object.preventExtensions(obj);
        obj.x = 2; // Uncaught TypeError: Cannot add property x, object is not extensible
    }
    f()
    
    3.1.4 方法中形参命名

    不能使用相同的形参,想起来也合理,如果两个参数名一样,谁知道指代的哪一个

     (function(){
        'use strict'
        function f(a, a){} // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
      })()
    
    3.1.5 八进制

    阻止使用以0开始的八进制表达方式,可以使用0o的方式来定义八进制数据。当然避免010这样的数据产生莫名其妙的结果了(根本不会想到非Strict Mode下 010 === 8

    function f() {
        'use strict'
        var x = 010; // Uncaught SyntaxError: Octal literals are not allowed in strict mode.
        var x = 0o10 // 可以这样用,x === 8
    }
    
    3.1.6 禁止给基本类型扩展属性

    我想正常的我们都不会给一个布尔值,字符串,数字增加属性吧

    function f() {
        'use strict'
        false.x = 1; // Uncaught TypeError: Cannot create property 'x' on boolean 'false'
        'str'.x = 1; // Uncaught TypeError: Cannot create property 'x' on string 'str'
    }
    f()
    
    3.1.7 (超特殊) 对象属性

    对象中含有两个相同的属性名,根据官方文档时说要报错的,结果似乎被定义为bug了,目前并不会报错,只会覆盖了

    function f() {
      'use strict'
      var obj = {x: 1, x: 2} // 据说会报错,结果现在只是后定义的回覆盖前面的值
      console.log(obj.x);
    }
    f();
    

    3.2 function和arguments

    3.2.1 Function中this指代

    这里其实涉及到另一个知识点this的指代,Javascript中this指代会有一点麻烦,不过这里如果在函数通常调用情况下,非Strict Mode返回是window对象,而Strict Mode定义为undefined(原因其实就是方法调用的时候没有指向任何对象)

    function f() {
      'use strict'
      return this; // undefined 
    }
    f();
    window.f(); // 可以自行尝试,有很有意思的结果
    
    3.2.2 callee, caller, function.arguments

    在Strict Mode下使用function.callerfunction.argumentsarguments.calleearguments.caller,都会抛出异常,我想这么做是为了避免无缘无故就引入了循环引用导致堆栈溢出。

    3.2.3 arguments使用

    对于非箭头函数,方法中可以使用arguments来获取传递参数,严格模式下对参数不会改变aguments对于值的获取的值。

      (function(){
          'use strict'
          function f(a){
            a = 2;
            console.log(arguments[0]); // arguments[0] === 1
          }
          f(1);
      })()
    
    3.2.4 (特例)逻辑语句中定义方法

    官方似乎是会产生异常的,但是逻辑语句中是不能定义方法的,但是自己尝试了,似乎都是可以的,也许新版本定义这是可行的?

    3.3. eval函数

    3.2.1 作为变量名,方法名,自增数

    和关键字一样,不能用做以上内容,否则会抛出异常

    3.2.2 对全局变量的影响

    Strict Mode下不会对全局变量产生影响,声明的变量只在eval自身的作用域范围内有效

      'use strict'
      var a = 1;
      eval('var a = 2'); // 注意 eval('a = 2')是可以对a产生影响的
      console.log(a); // a === 1;
    
    3.2.3 直接使用和间接使用的区别

    对于间接使用的时候,不受到Strict Mode的限制

    'use strict'
    eval('var x = 1');
    console.log(x); // undefined
    // 间接调用1
    ('indirect', eval)('var y = 2;'); // indirect
    console.log(y); // 2
    // 间接调用2
    var ieval = eval;
    ieval('var z = 3');
    console.log(z);
    
    3.2.4 this.eval和eval的区别

    this又一次立功,这时候也是可以对全局变量产生影响的

      'use strict'
      var a = 1;
      this.eval('var a = 2');
      console.log(a); // a === 2;
    

    3.4. with函数

    Strict Mode下使用with函数会直接抛出异常

    (function(){
      // Uncaught SyntaxError: Strict mode code may not include a with statement
      'use strict'
      var obj = {x: 1};
      with(obj){
        console.log(x);
      }
    })()
    

    3.5 delete

    3.5.1 删除对象属性

    当对象属性设置为configurable: false的时候,如果删除对象属性会抛出异常,当然非Strict Mode也不能删掉,只是不会抛出异常

    (function(){
      'use strict'
      var obj = {};
      Object.defineProperty(obj, 'x', {value: 1, configurable: false});
      delete obj.x; // Uncaught TypeError: Cannot delete property 'x' of #<Object>
    })()
    
    3.5.2 删除变量

    变量是不能直接删除的,会抛出异常,同样非Strict Mode下虽然不会抛出异常,但是实际上不能删除的

    (function(){
      // Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
      'use strict'
      var a = 1;
      delete a;
    })()
    
    3.5.3 删除this指代的全局变量

    这是可以的,因为this又一次立功,变成了删除某个对象的值,所以是可以的

    (function(){
      'use strict'
      delete this.a;
      console.log(this);
    }).call({a: 1 , b: 2})
    

    4.参考

    所有以上内容都来自MDN,只是对结构按照自己理解做了一下调整和整合:
    MDN strict mode
    ECMA-262-5 in detail. Chapter 2. Strict Mode.
    MDN Function caller
    MDN arguments caller(已淘汰)
    MDN arguments callee

    5. 练习

    最后来一个练习吧,猜猜结果:

    (function(){
      'use strict'
      var a = b = 1;
      console.log(a);
      console.log(b);
    })()

    相关文章

      网友评论

          本文标题:Javascript学习笔记-Strict Mode

          本文链接:https://www.haomeiwen.com/subject/oujjkxtx.html