zoukankan      html  css  js  c++  java
  • JavaScript严格模式

    介绍

    ECMAscript 5添加了“严格模式”,会使得Javascript在更严格的条件下运行,设立"严格模式"的目的,主要有以下几个:

    • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
    • 消除代码运行的一些不安全之处,保证代码运行的安全;
    • 提高编译器效率,增加运行速度;
    • 为未来新版本的Javascript做好铺垫。

    说明
    此文参考了阮一峰的Javascript 严格模式详解,做个总结笔记。对于原文中的例子我都一一测试了,但有个别测试结果是不一样的,后面已做说明。那些我也是比较迷惑的,如果有错误,希望指出。

     

    开始

    启用严格模式很简单,只需要一个字符串

    "use strict";

    但是这个字符串的位置不是随意放的,有两种:

    • 全局严格模式,放在脚本文件的第一行
    • 局部严格模式,放在函数内第一行(推荐)

    为什么推荐使用在函数内的严格模式呢?

    因为全局严格模式不利于代码的合并,团队多人开发时,合并代码可能会使别人某些代码失效。

    所以更好的做法是,借用局部严格模式方法,将整个脚本文件放在一个立即执行的匿名函数之中:

    (function (){
    
      "use strict";
      // some code here
    
    })();

    思考

    为什么是一个字符串启用严格模式?是为了兼容老旧的浏览器,一行字符串不会对不兼容严格模式的浏览器产生影响。

    改变

    严格模式带来了很多语法的改变。

    变量赋值前必须声明

    通常我们可以直接对一个变量赋值而不需要提前var声明,此时这个变量就是全局变量。严格模式禁止这种用法,全局变量必须显式声明。

    "use strict"
    
    a = 2;   //报错

    因此,严格模式下,变量都必须先用var命令声明,然后再使用。

    禁止使用with

    正常模式下,我们可以使用with来改变作用域链,如:

    var obj = {
       num:1
    }
    function test(){
       var num = 2;
       with(obj){
        console.log(num);
       }
    }
    test();  //1

    但是在严格模式下,禁用了with,报错:

    "use strict";
    
    test();
    //Strict mode code may not include a with statement

    创建eval作用域

    正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。

    正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。

    "use strict";
    
    var x = 5;
    
    console.log(eval('var x = 10;console.log(x)')); //10
    
    console.log(x);  //5

    局部this必须赋值

    正常模式下,函数编译时,内部this指向的是全局window对象,但是严格模式时,this不再指向window,而是undefined。你需要自己手动赋值,赋值是什么,this就是什么。

    "use strict";
    
    console.log('window: ',this);  //window
    
    function test(){
        console.log('test: ',this);  //undefined
    }
    
    test();

    因此,使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错。

    function fn(){
      "use strict";
      this.a = 1;
    };
    fn(); // 报错

    arguments对象的限制

    arguments是函数的参数对象,严格模式对它的使用做了限制。

    不允许对arguments赋值

    "use strict";
    
    var arguments = 5;  //报错
    
    function arguments(){   //报错
        //some code
    }

    arguments不再追踪参数的变化

    //正常模式
    function test(a){
        a = 5;
        console.log([a,arguments[0]])
    }
    
    test(2);  //[5,5]
    
    
    
    //严格模式
    
    "use strict";
    
    function test(a){
        a = 5;
        console.log([a,arguments[0]])
    }
    
    test(2);  //[5,2]

    禁止使用arguments.callee

    arguments.callee可以返回正被执行的函数对象

    //正常模式
    function test(){
        console.log(arguments.callee);
    }
    
    test();
    // test(){
    //    console.log(arguments.callee);
    //}

    严格模式不允许再使用arguments.callee

    禁止使用caller

    正常模式下,可以使用caller返回一个函数对象,这个函数调用了当前函数:

    function test(){
        demo();
    }
    
    function demo(){
        console.log(demo.caller);
    }
    
    test();  
    // test(){
    //    demo();
    //}

    严格模式禁止再使用caller。所以两个长得很像的callee和caller在严格模式下都不能再使用。

    函数必须声明在顶层

    什么意思呢?

    我们都只到es6引入了块级作用域,为了与新版本接轨,严格模式只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数。

    //正常模式
    
    if(true){
        function fn(){
            console.log('fn');
        }
    
        fn();   // fn
    }
    
    fn();   // fn
    "use strict";
    
    if(true){
        function fn(){
            console.log('fn');
        }
    
        fn();   // fn
    }
    
    fn();  // 报错  fn is not defined

    重名错误

    对象不能有重名属性

    按照 阮一峰的文章,在严格模式下,对象是不准有重名属性的,会报错。但实际测试中(谷歌浏览器),严格模式下,对象属性重名并不会报错,而是像正常模式一样,后面的覆盖前面的。

    "use strict";
    
    var obj = {
       a:1,
       a:2
    }
    
    console.log(obj.a);  //2

    后来了解到,ES6中的严格模式已经允许对象有重名的属性。如果有了解的,可以告诉我下。

    函数不能有重名的参数

    正常模式下,参数重名,后面的覆盖前面的:

    function test(a,a,b){
        console.log(a,a,b);
    }
    
    test(1,2,3); // 2 2 3

    但在严格模式下,会报错:

    "use strict";
    
    function test(a,a,b){
        console.log(a,a,b);
    }
    
    test(1,2,3);
    // 报错 Duplicate parameter name not allowed in this context

    禁止删除变量

    按照 阮一峰的文章,严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。

    但是即使在正常模式下,用var声明的变量也是无法删除的,不管是全局声明还是局部声明,不过可以删除对象属性:

    var obj = {
        a:2
    }
    
    delete obj.a;   //true
    
    obj //{}

    在严格模式下,用var声明的变量也是无法删除的,但对象的属性也是可以删除的:

    "use strict";
    
    var obj = {
        a:2
    }
    
    delete obj.a;   //true
    
    obj //{}

    需要注意的是,在正常模式下,即使变量不可以删除,你也可以写入 delete,不会报错,但是严格模式下,删除不了的变量不可以用delete

    "use strict";
    
    var a = 2;
    
    var obj = {
        b:3
    }
    
    delete a;  //报错,不可删除就不能使用delete

    禁止八进制表示法

    正常模式下,整数的第一位如果是0,表示这是八进制数,比如0100等于十进制的64。严格模式禁止这种表示法,整数第一位为0,将报错。

    "use strict";
    var num = 0100;
    console.log(num);  // 报错

    但是es6提供了一种八进制数的新表示法,就是在数值前加上0o(第一个是数字0,第二个是字母o)

    "use strict";
    var num = 0o100;
    console.log(num);

    保留字

    为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

    使用这些词作为变量名将会报错。

    "use strict";
    
    var let;  //报错

    说到保留字let,我们知道es6已经加入了letconstconst不管是在正常模式还是严格模式下都不可作为变量名。因为各大浏览器自行增加的const保留字,所以不能作为变量名的。

  • 相关阅读:
    <a>标签实现锚点跳跃,<a>标签实现href不跳跃另外加事件(ref传参)
    ThinkPHP实现事务回滚示例代码(附加:PDO的事务处理)
    python 命令执行文件传递参数
    python os.walk()
    python sys.stdin、sys.stdout和sys.stderr
    Python 为什么sys.stdout.write 输出时后面总跟一个数字
    python 不同集合上元素的迭代 chain()
    Python zip() 处理多于两个序列的参数, 存储结对的值
    Python 成对处理数据 zip()
    python 同时迭代多个序列
  • 原文地址:https://www.cnblogs.com/wjaaron/p/8280373.html
Copyright © 2011-2022 走看看