严格模式 "use strict"

904 阅读7分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

严格模式

1、概念:

严格模式是JavaScript中的一种限制性更轻的变种方式。严格模式不是一个子集:它在语义上与正常代码有着明显的差异。

不支持严格模式的浏览器与支持模式的浏览器行为也不一样,所以不要在未经严格模式特性测试情况下使用严格模式。

严格模式可以与非严格模式共存,所以脚本可以主键的选择性加入严格模式。

2、目的

首先,严格模式会将JavaScript陷阱直接变成明显的错误。

其次,严格模式修正了一些引擎难以优化的错误:同样的代码有些时候严格模式会比非严格模式下更快。

第三,严格模式禁用了一下有可能在未来版本中定义的语法。

3、开启严格模式

严格模式分为全局严格模式函数严格模式

在JavaScript中想要开启严格模式,需要在所有代码之前,定义一个不会赋给任何变量的字符串:

"use strict"; //或者 'use strict'

(1)全局开启严格模式

// 开启全局严格模式 --作用于全局
'use strict'
// 定义一个变量a,不使用关键字var
 a = 1;
console.log(a);//报错信息为:a is not defined

(2)函数开启严格模式

function fun(){
    'use strict'
    // var v = 200;严格模式下此句正确
    v = 200;
    console.log(v);
}
fun();//报错:v is not defined

一、严格模式下不同场景的区别(变量的区别)

1、禁止意外创建变量

在严格模式下不允许意外创建全局变量。

示例代码如下:

    // 全局开启严格模式,定义变量v和w的方式都是错误的
// 'use strict'
v = 100;
console.log(v);//100

function fn() {
    // 'use strict' 开启局部严格模式,定义变量w的方式是错误的
    // 定义局部变量w
    w = 200;
    console.log(w);//200
}
fn();
//在非严格模式下定义的局部变量,JavaScript会自动将其提升为全局变量。
//故此处打印输出w,结果为200
console.log(w);//200

2、静默失败转为异常

大概意思就是:将问题直接转化为错误(如语法错误或运行时错误)。

//开启严格模式,将问题直接转化为报错
'use strict'
const v = 100;//(定义常量)
v = 1.14;//重新赋值(为变量)

console.log(v);

3、禁用delete关键字

在严格模式下,不能对变量使用delete运算符。

(1)对变量使用delete关键字
// 开启严格模式
'use strict'

var v = 100;
delete v;//非严格模式下:此处为静默失败,既没有报错也没有删除变量v
console.log(v);//100
//开启严格模式后,改为报错Delete of an unqualified identifier in strict mode.
(2)对数组和对方法属性使用delete关键字

严格模式下对数组和对方法属性使用delete关键字,效果不变。

// 开启严格模式
'use strict'

// 1、严格模式下删除数组内容
var arr = [1,2,3,4]
delete arr[0];
console.log(arr);//[ <1 empty item>, 2, 3, 4 ]

// 2、严格模式下delete函数的属性
var obj  =  {
    name : '猪猪侠 '
}
delete obj.name;
console.log(obj.name)//undefined

4、对变量名的限制

在严格模式下,JavaScript对变量名也有限制。特别不能使用如下内容作为变量名: image-20201031183835973.png

示例代码如下:

// 开启严格模式
'use strict'
var static = 100;
console.log(static);//100
// 非严格模式下,static可以用作变量名,但在严格模式下不可以使用保留字

二、严格模式下不同场景的区别(对象的区别)

1、不可删除的属性

在严格模式下,不能使用delete运算符删除不可删除的属性。

// 开启严格模式
'use strict'
 delete Object.prototype; //不可删除Object的原有属性
console.log(Object.prototype);//非严格模式下,结果会静默失败,结果为:{}。
// 严格模式下delete会报错

// 严格模式并没有做到十全十美,一些JavaScript自带的属性也是可以删除的
delete Math.random;
console.log(Math.random);//严格模式下:undefined

2、属性名必须唯一

在严格模式下,一个对象内的所有属性名在对象内必须唯一。

示例代码如下:

// 开启严格模式
'use strict';

// 对象具有相同名称的属性时 - 编辑器报错
var obj = {
    name:'猪猪侠',
    name:'超人强'
}
console.log(obj.name);

注:编辑器报错,运行结果不报错。如下图所示:

image.png

3、只读属性的赋值

在严格模式下,不能为一个只读的属性进行重新赋值。

示例代码如下:

'use strict'
var obj = {
    name:'猪猪侠'
}
// 用于判断指定属性是否为只读属性
var result = Object.getOwnPropertyDescriptor(obj,'name');
console.log(result);//{ value: '猪猪侠', writable: true, enumerable: true, configurable: true }
// 定义对象obj的只读属性
Object.defineProperty(obj,'age',{
    value:18,writable:false //新增只读age属性。
});

// 针对只读属性进行修改操作
obj.age = 80;
console.log(obj.age);//非严格模式下,产生静默失败,结果为:18

// 使用try...catch语句进行捕捉提示
try{
obj.age = 80;
console.log(obj.age);//非严格模式下,产生静默失败,结果为:18
}catch (e) {
    console.log('此属性不可修改')
}

4、不可扩展的对象

在严格模式下,不可为不可扩展的对象添加新属性或新方法。

// 开启严格模式
'use strict'
var obj = function () {

};
// 设置对象 obj是一个不可扩展的对象
Object.preventExtensions(obj);
// 为对象新增属性和方法
// obj.name = '猪猪侠';
// obj.age = 19;
obj.prototype.age = 10; //可通过原型属性为其新增属性(对象为函数时)
console.log(obj.prototype);

三、严格模式下不同场景的区别(函数参数名的区别)

1、参数名必须唯一

在严格模式下,要求命名函数的参数必须唯一。严格模式下重命名参数被认为是语法错误。

示例代码如下:

// 开启严格模式
'use strict'
function fun(a,a,b) {
    console.log(a+a+b);
}
// 非严格模式下调用不会报错,但严格模式下会报错,参数名重复
fun(2,3,4);//10

2、arguments的不同

在严格模式下,arguments对象的行为也有所不同。

  • 非严格模式下,修改形参的值也会反映到arguments对象中。
  • 在严格模式下,形参与arguments对象是完全独立的。

示例代码如下:

// 开启严格模式
'use strict'
function fun(value) {
    var value = '猪猪侠';
    console.log(value);//猪猪侠 ->就近原则
    console.log(arguments[0]);
}
fun('超人强');//非严格模式下,arguments对象获取的值与形参有关。

3、arguments.callee()

在严格模式下,不能使用arguments对象的callee()方法。

  • 非严格模式下,使用arguments对象的callee()方法,表示调用函数本身。
  • 在严格模式下,使用arguments对象的callee()方法,结果抛出异常。

示例代码如下:

'use strict'
function fun() {
    console.log(arguments.length);//0
    // 在严格模式下无法调用arguments的callee方法
    console.log(arguments.callee);
}
fun()

4、函数声明的限制

在严格模式下,只能在全局域和函数域中声明函数。

  • 非严格模式下,任何位置声明函数都是合法的。
  • 在严格模式下,除在全局域和函数域中声明函数是错误语法。

示例代码如下:

// 开启严格模式
'use strict'

// 在全局作用域
function fn() {
    // 在函数作用域
    function n() {
    }
}
// 在严格模式下,函数的定义只能在全局作用域与函数作用域(不能在块级作用域定义函数 )
for (var i=0;i<10;i++){
    //ECMAScript 6新增 - 存在着块级作用域
    var v = 100;
    function f() {//非函数作用域声明函数,语法报错
        console.log('this is a function');
    }
}
console.log(v);
f();

增加eval作用域

在严格模式下,使用eval()函数创建的变量只能在eval()函数内部使用。

​ 示例代码如下:

'use strict'

eval('var x = 23');
console.log(x);//非严格模式下输出23,严格模式下报错

禁止读写

在严格模式下,禁止使用eval()和arguments作为标示符,也不允许读写它们的值。

  • 使用var声明
  • 赋予另一个值。
  • 尝试修改包含的值。
  • 用作函数名
  • 用作命名的函数的参数
  • 在try…catch语句中用作例外名。
"use strict"

eval = 19;
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')

抑制this

  • 在非严格模式下使用函数的apply()或call()方法时,null或 undefined值会被转换为全局对象。
  • 在严格模式下,函数的this值始终是指定的值(无论什么值)。
// 开启严格模式
'use strict'
var v =100;
function fun() {
    console.log(this.v);
}
var obj = {
    v : 200
}
// fun.call(null);//非严格模式下:100,严格模式下报错。
fun.call(obj)//200