严格模式

描述

  • 严格模式可以分别作用在全局作用域中和函数作用域中
  • 严格模式是对JavaScript代码的一种限制方式

    • 严格模式可以将不明确显示的错误转变成明确显示
    • 严格模式可以修正一些解释器难以优化的错误

严格模式下的变量

禁止意外创建变量

  • 没有开启严格模式时

    • 在调用该变量时,不会报错
    • 解释器会自动补全 var关键字
  • 开启严格模式时

    • 在调用该变量时,会报错
    • 显示 ReferenceError: s is not defined
/* 开启严格模式 - 全局作用域 */
"use strict";

/* 定义一个变量 - 不使用 var关键字 */
s = 100;
/*
    没有开启严格模式时
     * 在调用该变量时,不会报错
     * 解释器会自动补全 var关键字
    开启严格模式时
     * 在调用该变量时,会报错
     * 显示 ReferenceError: s is not defined(该变量没有被定义)
 */
console.log( s );// 显示 100 - 开启严格模式后的显示 s is not defined(报错)

* 定义一个函数 */
function fun() {
    /* 定义一个变量 - 不使用var关键字 */
    s = 100;
    console.log( s );
}
/* 调用函数 */
fun();// 显示 100
/*
    在未开启严格模式的情况下
     * 在函数作用域中,不使用var关键字定义的变量,会自动从局部变量提升到全局变量
    在开启严格模式的情况下
     * 在函数作用域中,不使用var关键字定义的变量,会报错
 */
/* 在全局作用域访问函数作用域中的局部变量 */
console.log( s );// 显示 100 开启严格模式后的显示 ReferenceError: s is not defined(报错)

静默失败转为异常

  • 静默表示既不报错也不显示任何效果
  • 在严格模式下,静默失败会转为报错
/* 开启严格模式 */
"use strict";

/* 定义一个常量 */
const c = 100;
/* 对常量重新赋值 */
c = 200;

/* 开启严格模式后会将静默失败转成报错 */
console.log( c );// 显示 TypeError: Assignment to constant variable.

禁用delete关键字

  • 在非严格模式下,对变量使用delete 会静默失败
  • 在严格模式下,对变量使用delete 会报错
/* 开启严格模式 */
"use strict";

/* 定义一个变量 */
var s = 100;
/*
    对变量使用delete
     * 在非严格模式下delete 会无效
     * 在严格模式下会报错 SyntaxError: Delete of an unqualified identifier in strict mode.
 */
delete s;
/* 在调用该变量 */
console.log( s );// 显示 100 ,在严格模式下会报错 Delete of an unqualified identifier in strict mode.

对变量名的限制

  • 在非严格模式下,定义变量名时,使用保留字,会正常显示或静默失败
  • 在严格模式下,定义变量名是,使用保留字,会报错
/* 开启严格模式 */
"use strict";

/* 定义一个变量 - 使用保留字定义变量名 */
var let = 100;
console.log( let );
/*
    非严格模式 显示 100
    严格模式 显示 SyntaxError: Unexpected strict mode reserved word
 */

严格模式下的对象

不可删除的属性

  • 在非严格模式下,使用delete去删除不可删除的属性时,会静默失败
  • 在严格模式下,使用delete去删除不可删除的属性时,会报错
/* 开启严格模式 */
"use strict";

/* 使用delete 删除Object对象的原型属性 */
delete Object.prototype;
/* 在调用Object对象的原型属性 */
console.log( Object.prototype );
/*
    非严格模式下 显示 {}(正常显示一个空对象)
    严格模式下 显示 TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
 */

属性名必须唯一

  • 在非严格模式下,对象的属性名允许重复,会执行最后一次定义的内容
  • 在严格模式下,对象的属性名重复时,编辑器会报错,但是会正常运行最后一次定义的内容
/* 开启严格模式 */
"use strict";

/* 定义一个对象 */
var obj = {
    name : '融念冰',
    name : '唐三'
}
/* 调用对象的属性 */
console.log( obj.name );
/*
    非严格模式下 显示 唐三
    严格模式下 显示 唐三
 */

只读属性的赋值

  • 在非严格模式下,对只读属性进行从新赋值,会静默失败
  • 在严格模式下,对只读属性进行重新赋值,会报错
/* 开启严格模式 */
"use strict";

/* 定义一个对象 */
var obj = {
    name : '唐三'
};
/* 获取指定属性的属性描述符 - 将属性改为只读属性 */
Object.defineProperty( obj, 'name', {
    /* 通过属性描述符将指定属性改为只读 */
    writable : false
} );
/* 对指定属性进行修改 */
obj.name = '融念冰';
/* 调用属性 */
console.log( obj.name );
/*
    非严格模式下 显示 唐三(无法修改属性)
    严格模式下 显示 TypeError: Cannot assign to read only property 'name' of object '#<Object>'
 */

不可扩展的对象

  • 在非严格模式下,对不可扩展的对象添加新属性,会静默失败
  • 在严格模式下,对不可扩展的对象添加新属性,会报错
/* 开启严格模式 */
"use strict";

/* 定义一个空对象 */
var obj = {};
/* 将指定对象设置为不可扩展的对象 */
Object.preventExtensions( obj );
/* 为不可扩展的对象新增属性 */
obj.name = '唐三';
/* 调用对象 */
console.log( obj );
/*
    非严格模式下 显示 {}(空对象)
    严格模式下 显示 TypeError: Cannot add property name, object is not extensible
 */

严格模式下的函数

参数名必须唯一

  • 在非严格模式下,参数名允许重复,后面匹配的参数会覆盖之前匹配的参数
  • 在严格模式下,参数名重复时,编辑器会提示报错,运行时也会报错
/* 开启严格模式 */
"use strict";

/* 定义一个函数 */
function fun( a, a, b ) {
    console.log( a + a + b );
}
/* 调用函数并传递参数 */
fun( 1, 2, 3 );
/*
    非严格模式下 显示 7(2+2+3)
    严格模式下 显示 SyntaxError: Duplicate parameter name not allowed in this context
 */

arguments的不同

  • 在非严格模式下,arguments对象获取参数的值与形参有关
  • 严格模式下,arguments对象获取参数的值与形参无关
/* 开启严格模式 */
"use strict";

/* 定义一个函数 */
function fun( canshu ) {
    /* 定义局部变量 */
    var canshu = '唐三';
    /* 调用局部变量 */
    console.log( canshu );// 显示 唐三

    /* 通过arguments获取参数 */
    console.log( arguments[0] );
    /*
        非严格模式下 显示 唐三
         * 当局部变量与参数同名时,会根据就近原则进行获取
        严格模式下 显示 融念冰
         * 只会获取在调用函数时传递的实参
     */
}
/* 调用函数并传递参数 */
fun( '融念冰' );

arguments对象的callee()方法

  • 在非严格模式下,callee()方法表示当前调用的函数
  • 在严格模式下,arguments对象将无法调用callee()方法,会报错
/* 开启严格模式 */
"use strict";

/* 定义一个函数 */
function fun() {
    /* 将callee()方法返回 */
    return arguments.callee;
}
/* 调用函数 */
fun();
/*
    非严格模式下 显示 (由于示例代码的关系,所以没用显示)
    严格模式下 显示 TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
 */

函数声明的限制

  • 在非严格模式下,函数可以在任何作用域下进行定义
  • 在严格模式下,函数只能在全局作用域和函数作用域下进行定义
/* 开启严格模式 */
"use strict";

/* 在全局作用域定义函数 */
function fun() {
    /* 在函数作用域定义内部函数 */
    function fn() {

    }
}

/* 在 ES6 中新增了一个新的作用域 - 块级作用域 */
for ( var i = 0 ; i < 10; i++ ) {
    // 该语句块中就为块级作用域

    /* 在块级作用域中定义函数 */
    function f() {
        console.log( '三步白头' );
    }
}
/* 调用函数 f */
f();
/*
    非严格模式下 显示 三步白头
    严格模式下 显示 报错ReferenceError: f is not defined
 */

严格模式下的特殊值

增加eval作用域

  • 在非严格模式下,eval()函数创建的变量可以在其他位置进行调用
  • 在严格模式下,eval()函数创建的变量只能在当前eval()函数中使用,其他位置调用会报错
/* 开启严格模式 */
"use strict";

/* 定义eval()函数 */
eval( "var s = '三步白头'" );
/* 调用eval()函数中变量 */
console.log( s );
/*
    非严格模式下 显示 三步白头
    严格模式下 显示 报错ReferenceError: s is not defined
 */

禁止读写

  • 在非严格模式下,使用 eval 或 arguments 做为标识符(变量名、函数名、对象名)时,会静默失败
  • 在严格模式下,使用 eval 或 arguments 做为标识符(变量名、函数名、对象名)时,会报错
/* 开启严格模式 */
"use strict";

/* 使用 eval 或 arguments 做为标识符 */
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;");
/*
    非严格模式下 显示 没有显示
    严格模式下 显示 报错 SyntaxError: Unexpected eval or arguments in strict mode
 */

抑制this

  • 在非严格模式下,在函数使用apply()方法或call()方法来调用函数时,使用null或undefined来代替this的指向对象时,this会指向全局对象
  • 在严格模式下,在函数使用apply()方法或call()方法来调用函数时,使用null或undefined来代替this的指向对象时,会报错
/* 开启严格模式 */
"use strict";

/* 定义全局变量 */
var s = 100;
/* 定义函数 */
function fun() {
    console.log( this.s );
}
/* 使用appl()方法或call()方法来调用函数 */
fun.apply( null );
/*
    非严格模式下 显示 undefined(浏览器环境下 会指向全局变量 并显示变量值 100)
    严格模式下 显示 报错 TypeError: Cannot read property 's' of null
 */

蔡志远
9 声望5 粉丝