zoukankan      html  css  js  c++  java
  • 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版)》(周爱民/著)
  • 相关阅读:
    kafka 流式计算
    解决山地车令人讨厌的中轴异响及其他异响问题
    go语言通道详解
    使用Spring Cloud连接不同服务
    并发之痛 Thread,Goroutine,Actor
    用go语言实现线程池
    golang go语言通道类型的通道示例 通道的通道
    Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
    spring5 reactive
    Go 语言和 Scala 语言对比
  • 原文地址:https://www.cnblogs.com/hycstar/p/14591035.html
Copyright © 2011-2022 走看看