• JavaScript严格模式


    严格模式使代码隐式地脱离"马虎模式/稀松模式/懒散模式"(sloppy)模式, 将语法限制在原来语法的子集中.

    特性

    • 通过抛出错误来消除了一些原有静默错误
    • 修复了一些导致 JavaScript引擎难以执行优化的缺陷:有时候, 相同的代码, 严格模式可以比非严格模式下运行得更快
    • 严格模式禁用了在ECMAScript的未来版本中可能会定义的一些语法

    开启严格模式:

    • 在全局或函数首行加入'use strict';
    • 严格模式下函数内部不能使用剩余操作符、解构操作符和默认参数等
    • 类中的代码默认都在严格模式下执行
    • ES6模块默认都在严格模式下执行

    将过错失误转为异常

    • 禁止意外的创建全局变量

      'use strict';
      
      demo1 = 1; // ✖: 意外创建的
      var demo2 = 1; // ✔: 不是意外创建的
      
      (() => {
        demo3 = 1; // ✖: 意外创建的
        var demo4 = 1; // ✔: 不是全局变量
        global.demo5 = 1; // ✔: 不是意外创建的
      })();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • 禁止引起静默失败(不报错也没有任何效果)的赋值操作. 包括

      • 为不可写属性赋值

        'use strict';
        
        // 不可写属性赋值-1
        
        NaN = 1; // ✖: 在非严格模式下不报错但无效果, 在严格模式下直接报错
        console.log(NaN);
        
        // 不可写属性赋值-2
        
        let obj1 = {};
        // 定义不可写属性x(顺便了解一下defineProperty的参数)
        Object.defineProperty(obj1, 'x', {
          configurable: true, // 能否通过delete删除属性从而重新定义属性, 能否修改属性的特性, 能否把属性修改为访问器属性[默认true]
          enumerable: true, // 能否通过for-in返回属性(默认true)
          writable: false, // 能否修改属性值(默认true)
          value: 123,
          // get(){}  // 我们不用这个属性
          // set(){}  // 我们不用这个属性
        });
        
        obj1.x = 1; // ✖: x属性是不可写的, 在非严格模式下不报错但无效果, 在严格模式下直接报错
        
        // ✔: 由于configurable=true, 可以重新定义, 严格模式也不报错
        Object.defineProperty(obj1, 'x', {
          value: 12,
        });
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
      • 为只读属性赋值

        'use strict';
        
        // 给只读属性赋值
        
        let obj2 = {
          x: 1,
          get x() {
            // 一旦用了get, 如果不写set, 那么无法设置x(相当于上面x属性直接无效, 因为set x()和x一起存在要爆栈赋值)
            return 2;
          },
        };
        
        obj2.x = 3; // ✖: 没有set, 在非严格模式下不报错但无效果, 在严格模式下直接报错
        console.log(obj2.x);
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      • 为不可扩展对象扩展

        'use strict';
        
        // 给不可扩展对象的新属性赋值
        
        var fixed = {};
        Object.preventExtensions(fixed);
        fixed.newProp = 'ohai'; // ✖: 在非严格模式下不报错但无效果, 在严格模式下直接报错
        console.log(fixed);
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
    • 禁止删除不可删除属性

      'use strict';
      
      const obj = {};
      Object.defineProperty(obj, 'x', {
        configurable: false,
        value: 1,
      });
      // delete obj.x; // ✖: 不可删除
      console.log(obj.x); // 1
      
      function foo() {}
      delete foo.prototype; // ✖: 不可删除
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 对象内的所有属性名在对象内必须唯一(该规则在ES6被取消)

      'use strict';
      
      const obj1 = { a: 1, b: 2 };
      const obj2 = { a: 3, b: 4 };
      const obj3 = { ...obj1, ...obj2 }; // ✔: 在ES6不报错
      console.log(obj3);
      
      const obj4 = { a: 1, b: 2, a: 3, b: 4 };  // ✔: 在ES6不报错
      console.log(obj4);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • 函数参数名必须唯一. 在非严格模式下, 重名参数名会发生覆盖, 但是仍然可以在arguments中读取到原值

      // 单独执行这一部分不报错
      
      function sloppy(a, a, c) {
        console.log([a, a, c]); // [2,2,3]
        console.log(arguments); // [Arguments] { '0': 1, '1': 2, '2': 3 }
        return a + a + c;
      }
      sloppy(1, 2, 3);
      
      // 单独执行这一部分, **即使不调用函数都报错**, 在语法检查的时候就炸了
      
      function strict(a, a, c) {
        'use strict';
        console.log([a, a, c]);
        console.log(arguments);
        return a + a + c;
      }
      strict(1, 2, 3);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • 禁止使用加前导0的方式表示八进制数, 在ES6中允许使用0o做前导表示八进制

      'use strict';
      
      const a = 010;  // ✖: 非严格模式: 8, 严格模式: Error
      console.log(a);
      const b = 0o10; // ✔: 8
      console.log(b);
      const c = '010'; // ✔: 10(可不是8)
      console.log(+c);
      const d = '0o10'; // ✔: 8(ES6支持)
      console.log(+d);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • 禁止为基本类型(String, Number, Boolean, Null, Undefined, BitInt, Symbol)设置属性

      'use strict';
      
      const a = 123;
      a.demo = 1; // ✖: 禁止设置属性
      console.log(a, a.demo); // 123 undefined
      
      • 1
      • 2
      • 3
      • 4
      • 5

    简化变量的使用

    • 禁用with, 在运行之前无法获知with中变量的指向, 这回拖慢代码执行速度

    • 禁止eval为外层作用域set/引入变量

      var k = 10;
      
      var x = 17;
      var evalX = eval("'use strict'; var x = k; x"); // 严格模式下不会污染外层x
      console.log(x); // 17
      console.log(evalX); // 10
      
      var y = 17;
      var evalY = eval('var y = k; y'); // 非严格模式下会污染外层y
      console.log(y); // 10
      console.log(evalY); // 10
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 禁止delete变量

      'use strict';
      
      let obj1 = { a: 1 }; 
      console.log(obj1); // { a: 1 }
      delete obj1.a; // ✔: 允许删除属性
      console.log(obj1); // {}
      
      let obj2 = { a: 1 };
      console.log(obj2); // { a: 1 }
      delete obj2; // ✖: 不允许删除属性
      console.log(obj2); 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    简化evalarguments的怪异行为

    • 禁止evalarguments被绑定或赋值

      "use strict";
      eval = 17;
      arguments++;
      ++eval;
      var obj = { set p(arguments) { } };
      var eval;
      try { } catch (arguments) { }
      function x(eval) { }
      function arguments() { }
      var y = function eval() { };
      var f = new Function("arguments", "'use strict'; return 17;");
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 严格模式中arguments中的值(指针)不会随arguments中对象的变化而变化, 非严格模式中arguments会随对象的变化而变化

      function demo1(a, b, c) {
        a = 2;
        b.a = 2;
        c = { b: 2 };
        return [a, b, c, arguments];
        // [2, { a: 2 }, { b: 2 }, [Arguments] { '0': 2, '1': { a: 2 }, '2': { b: 2 } }]
      }
      
      console.log(demo1(1, { a: 1 }, { a: 1 }));
      
      function demo2(a, b, c) {
        'use strict';
        a = 2;
        b.a = 2;
        c = { b: 2 };
        return [a, b, c, arguments];
        // [ 2, { a: 2 }, { b: 2 }, [Arguments] { '0': 1, '1': { a: 2 }, '2': { a: 1 } }]
        // 注意, 他做不了深层检测
      }
      
      console.log(demo2(1, { a: 1 }, { a: 1 }));
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 严格模式不允许使用arguments.callee获得正在执行的函数

      function demo1() {
        console.log(arguments.callee === demo1);
      }
      
      function demo2() {
        'use strict';
        console.log(arguments.callee === demo2); // ✖
      }
      
      demo1();
      demo2();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    提升安全性

    • 严格模式下通过this传递给一个函数的值不会被强制转换为一个对象. 对一个普通的函数来说, this总会是一个对象:不管调用时this它本来就是一个对象.还是用布尔值, 字符串或者数字调用函数时函数里面被封装成对象的this.还是使用undefined或者null调用函数式this代表的全局对象(使用call, apply或者bind方法来指定一个确定的this). 这种自动转化为对象的过程不仅是一种性能上的损耗, 同时在浏览器中暴露出全局对象也会成为安全隐患, 因为全局对象提供了访问那些所谓安全的JavaScript环境必须限制的功能的途径. 所以对于一个开启严格模式的函数, 指定的this不再被封装为对象, 而且如果没有指定this的话它值是undefined:

      function demo1() {
        return this;
      }
      console.log(demo1()); // <ref *1> Object [global]
      console.log(demo1.call(2)); // [Number: 2] <- 是一个Number对象!
      console.log(demo1.apply(null)); // <ref *1> Object [global]
      console.log(demo1.call(undefined)); // <ref *1> Object [global]
      console.log(demo1.bind(true)()); // [Boolean: true]
      
      function demo2() {
        'use strict';
        return this;
      }
      console.log(demo2()); // undefined
      console.log(demo2.call(2)); // 2
      console.log(demo2.apply(null)); // null
      console.log(demo2.call(undefined)); // undefined
      console.log(demo2.bind(true)()); // true
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • 禁用function.caller/function.caller以阻止程序"游走于"JS调用栈

      'use strict';
      
      function fun(a, b) {
        // 非严格模式: true
        // 严格模式  : TypeError
        console.log(fun.caller === prefun);
        // 非严格模式: [Arguments] { '0': 1, '1': 2 }
        // 严格模式  : TypeError
        console.log(fun.arguments);
      }
      
      function prefun(a, b) {
        fun(a, b);
      }
      
      prefun(1, 2);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    • 禁止读取arguments.caller(这个属性同function.caller)出于优化原因, 浏览器并没有实现这个属性, 无论是否使用严格模式都会返回undefined

    为未来ES铺路

    • 增加保留字implements, interface, let, package, private, protected, public, static, yield

    • 禁止在非全局/函数中声明函数

      "use strict";
      if (true) {
        function f() { } // ✖
        f();
      }
      
      for (var i = 0; i < 5; i++) {
        function f2() { } // ✖
        f2();
      }
      
      function baz() { // ✔
        function eit() { } // ✔
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
  • 相关阅读:
    AI网络爬虫:对网页指定区域批量截图
    机器学习10—多元线性回归模型
    不会有人运营独立站还不知道聊天机器人吧?五分钟带你深入了解AI聊天机器人!
    [iOS]LLDB调试
    【实践】随机森林算法参数解释及调优(含Python代码)
    分享一份适合练手的软件测试实战项目
    防蓝光护眼台灯什么牌子好用?内含高赞收藏护眼台灯推荐
    【自学记录】【Pytorch2.0深度学习从零开始学 王晓华】第二章 深度学习环境搭建
    【linux】[OOM]now anon-rss:0kB, file-rss:0kB, shmem-rss:280kB
    GIF图像动态生成-JAVA后台生成
  • 原文地址:https://blog.csdn.net/Liukairui/article/details/125496292