• js严格模式详解


    什么是严格模式

    严格模式"use strict";ES5新增的语法,在不支持严格模式的浏览器中,这行代码仅会被识别为一个“字面量表达式语句”,而在支持严格模式的浏览器中,这行代码表示在对应作用域内开启严格模式。

    为什么要使用严格模式

    启用严格模式后后,JavaScript引擎会对代码进行更加严格的评估,对之前较为宽松的、静默处理的、难以优化的代码进行语法检查,以便于开发人员在编写代码的过程中实时分析,并显示语法和代码的质量问题。

    在何处使用"use strict";

    在显式使用式"use strict";时,由于"use strict";可以作用到所以在位置的整个作用域,所以式"use strict";应用在某个作用域开始位置即可,即:

    1.全局代码的开始处加入
    2.在eval代码开始处加入
    3.在函数声明语句开始处加入
    4.在new Function()所传入的函数体开始处加入
    

    除此之外,还有一些情况下默认使用严格模式,如:

    1.ES6模块中
    2.ES6的类声明和类表达式的整个声明中(包含extends关键字后边的表达式)
    3.在引擎或宿主的运行参数中指定,如node --use_strict
    

    语法限制

    在严格模式中,有7种语法被禁用。

    在对象字面量声明中存在相同的属性名

    此语法限制是在ES5中规定的,但ES6就取消了,所以最后一个声明项总是有效的,只在不支持ES6的浏览器中会报错

    "use strict";
    
    var obj = {
        name: "Lily",
        name: "Wango"
    }
    // IE11中报错: strict 模式下不允许一个属性有多个定义
    

    在函数声明中,参数具有相同标识符

    在非严格模式中,总是后一个同名参数生效(前一个被覆盖)

    "use strict";
    
    function foo(a, a, b) {}
    // SyntaxError: Duplicate parameter name not allowed in this context
    
    // 非严格模式
    function foo(a, a, c, b, b, c) {
        console.log(a + c);
    }
    
    // 参数的个数不会因为重名而改变,写了多少就是多少
    console.log(foo.length);
    // 6
    
    // 重复变量都是最后一个声明生效,覆盖了前者
    foo(1, 2, 3, 4, 5, 6);
    // 8
    
    // 在这里传三个实参,第二个c的值为undefined,2 + undefined得到NaN
    foo(1, 2, 3);
    // NaN
    

    不能声明、重写或删除evalarguments

    "use strict";
    // 不能重新赋值,不能重新声明(变量声明和函数声明都不允许)
    eval = function() {};
    // SyntaxError: Unexpected eval or arguments in strict mode
    var arguments;
    // SyntaxError: Unexpected eval or arguments in strict mode
    function arguments(){}
    // SyntaxError: Unexpected eval or arguments in strict mode
    
    // 不能作为形参标识符
    function foo(eval) {}
    // SyntaxError: Unexpected eval or arguments in strict mode
    
    // 不能作为catch子句的异常对象名
    try{} catch(arguments) {}
    // SyntaxError: Unexpected eval or arguments in strict mode
    
    // 不能删除
    delete eval;
    // Delete of an unqualified identifier in strict mode.
    delete arguments;
    // Delete of an unqualified identifier in strict mode.
    

    而在非严格模式中以上语法都是有效的

    0前缀声明八进制字面量

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

    在非严格模式下以上代码输出10

    delete删除显式声明的标识符、名称或具名函数

    "use strict";
    
    var a;
    delete a;
    // Delete of an unqualified identifier in strict mode.
    
    function foo(){}
    delete foo;
    // Delete of an unqualified identifier in strict mode.
    
    function foo(a) {
        delete a;
        // Delete of an unqualified identifier in strict mode.
    }
    
    try{}catch(err){ delete err}
    // Delete of an unqualified identifier in strict mode.
    

    在非严格模式中,以上操作无效,但不会抛出错误

    使用保留字

    "use strict";
    
    function interface() {}
    // SyntaxError: Unexpected strict mode reserved word
    

    包含with语句

    在严格模式中,with直接被禁止了

    "use strict";
    
    with(window) {}
    // SyntaxError: Strict mode code may not include a with statement
    

    执行限制

    对未声明的标识符赋值

    在非严格模式中,对未声明的标识符赋值时,会在全局对象上创建该标识符并完成运算,而在严格模式下,这种行为将导致ReferenceError

    "use strict";
    
    a = 10;
    // ReferenceError: a is not defined
    
    // 非严格模式
    a = 10;
    console.log(window.a);
    // 10
    

    对不可操作的内容进行操作

    "use strict";
            
    var obj = {
        name: 'Wango'
    }
    
    Object.preventExtensions(obj);
    obj.age = 24;
    // TypeError: Cannot add property age, object is not extensible
    
    Object.seal(obj);
    delete obj.name;
    // TypeError: Cannot delete property 'name' of #<Object>
    
    delete Function.prototype;
    // TypeError: Cannot delete property 'prototype' of function Function() { [native code] }
    
    Object.defineProperty(obj, 'age', {
        writable: false,
        value: 24
    });
    
    obj.age = 25;
    // TypeError: Cannot assign to read only property 'age' of object '#<Object>'
    

    非严格模式下忽略、无效、静默处理

    访问arguments.callee或函数的caller属性

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

    造成这个问题的是.语法存取属性,而不是属性本身,所以以下代码在严格模式下也是能执行的:

    "use strict";
    
    function foo() {
        console.log('callee' in arguments);
        // true
        console.log('caller' in foo);
        // true
    }
    foo();
    

    arguments与参数的不同表现

    在非严格模式中,arguments的数据和参数的数据是相互绑定的,可以看作是指向同一片内存空间,一个改变,另一个会一起改变

    function foo(a, b) {
        console.log(a, b);
        // A B
        arguments[0] = 10;
        console.log(a, b);
        // 10 B
        b = 20;
        console.log(arguments);
        // [10, 20]
    }
    
    foo('A', 'B');
    

    而在严格模式中,arguments与参数的修改将不再相互影响

    "use strict";
    
    function foo(a, b) {
        console.log(a, b);
        // A B
        arguments[0] = 10;
        console.log(a, b);
        // A B
        b = 20;
        console.log(arguments);
        // [10, B]
    }
    
    foo('A', 'B');
    

    严格模式的范围

    除非在启动JavaScript引擎时将其设置为严格模式,或者通过ES6模块加载整个系统,否在指定一个有限的严格模式。

    "use strict";只能用于作用域的起始位置,在此代码前有任何代码都会导致严格模式失效,就算仅有一个;

    // 严格模式失效
    ;"use strict";
    
    var eval;
    

    在函数作用域中,严格模式能作用于函数中的代码,同样也能作用于函数本身

    function eval() {
        // SyntaxError: Unexpected eval or arguments in strict mode
        "use strict";
    }
    // 严格模式外的代码不受影响
    var arguments;
    

    参考资料:
    《JavaScript语言精髓与编程实践(第3版)》(周爱民/著)
  • 相关阅读:
    积水路面Wet Road Materials 2.3
    门控时钟问题
    饮料机问题
    Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
    Educational Codeforces Round 82 (Rated for Div. 2)部分题解
    Educational Codeforces Round 86 (Rated for Div. 2)部分题解
    Grakn Forces 2020部分题解
    2020 年百度之星·程序设计大赛
    POJ Nearest Common Ancestors (RMQ+树上dfs序求LCA)
    算法竞赛进阶指南 聚会 (LCA)
  • 原文地址:https://www.cnblogs.com/hycstar/p/14591035.html
Copyright © 2020-2023  润新知