资讯专栏INFORMATION COLUMN

JS专题之严格模式

baukh789 / 2736人阅读

摘要:整个脚本文件就会以严格模式执行。函数作用域范围将放在函数体的第一行,则整个函数以严格模式运行。严格模式下,必须指明的指向对象。禁止在非函数代码块声明函数的严格模式只允许在全局作用域或函数作用域声明函数。

ECMAScript 5 引入了 strict mode ,现在已经被大多浏览器实现(从IE10开始)

一、什么是严格模式

顾名思义,JavaScript 严格模式就是让 JS 代码以更严格的模式执行,不允许可能会引发错误的代码执行。在正常模式下静默失败的代码,严格模式下就会抛出错误。

二、为什么要过渡到严格模式

严格模式下的代码在运行的时候,更容易通过抛出的错误定位到问题所在的地方

严格模式能够帮助你编写更符合规范的代码

消除 JavaScript 语言上一些不合理,比较怪异的行为

为未来新版本的 JavaScript 做铺垫

有时候,严格模式下的 JavaScript 代码运行起来更快

三、如何使用

· 脚本文件范围

"use strict"; 放在脚本文件的第一行。整个脚本文件就会以“严格模式”执行。

· 函数作用域范围

"use strict"; 放在函数体的第一行,则整个函数以"严格模式"运行。

文件合并时,写在脚本文件第一行的 "use strict"; 来实现严格模式会失效,可以将脚本文件的代码放在一个立即执行表达式中。

(funciton() {
    "use strict";
    ...
})()
四、严格模式的具体定义

严格模式下无法再隐式创建全局变量

也就是,变量必须声明后才能使用,正常模式直接赋值给一个未定义的变量时,会将变量定义为全局变量。

"use strict";
var a = b = 3;  // Uncaught ReferenceError: b is not defined

以上代码等于:
var a;
b = 3;
a = b;

禁止 this 关键字指向全局对象

正常模式下,函数中如果没有指明 this 对象,JS 则会将 this 隐式指向为全局对象。如果绑定的值是非对象,将被自动转为对象再绑定上去,而 null 和 undefined 这两个无法转成对象的值,将被忽略。

严格模式下,必须指明 this 的指向对象。如果没有指明的话,this的值为 undefined

var name = "foo";
function func() {
    "use strict";
    this.name;  // Uncaught TypeError: Cannot read property "name" of undefined
}
func();  // 没有加 new 关键字
new func();

function func() {
    return this
}

func() // window
func.call(8) // Number {8}
func.call(true) // Boolean {true}
func.call("abcd")  // {"abcd"}
func.call(null) // window
func.call(undefined) // window

"use strict"
function func() {
    return this
}

func() // undefined
func.call(8) // 8
func.call(true) // true
func.call(null) //null
func.call(undefined) // undefined

不允许在函数内部遍历调用栈

禁止使用 arguments.callee、arguments.caller、fn.caller、fn.callee;
在严格模式下,arguments.callee 是一个不可删除属性,而且赋值和读取时都会抛出异常

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

禁止向对象的只读属性赋值,禁止删除对象的不可设置属性, 禁止向不可扩展的对象添加属性

无法删除 var 声明的变量。

在正常模式中,给对象的只读属性赋值, 删除对象的不可设置属性,添加不可扩展对象的新属性,会静默失败。

但是在严格模式中,会抛出错误。
另外,字符串的属性 length 也是只读属性,修改后会报错。

"use strict";
var str = "abc"
str.length = 8  // Uncaught TypeError: Cannot assign to read only property "length" of string "abc"

"use strict";
var obj = Object.defineProperty({}, "a", {
  value: 37,
  writable: false
});
obj.a = 123; // Uncaught TypeError: Cannot assign to read only property "a" of object "#

"use strict";
var obj = Object.defineProperty({}, "p", {
  value: 37,
  configurable: false
});
delete obj.p  // Uncaught TypeError: Cannot delete property "p" of #

var obj = {};
Object.preventExtensions(obj);
obj.title = "hello";  // Uncaught TypeError: Cannot add property title, object is not extensible

对象不允许有重名的属性,函数不允许有重名的参数

在正常模式中,对象的重名属性,位置靠后会覆盖位置靠前的重名属性。函数也是,函数体查找到的参数,靠后的重名参数会覆盖靠前的重名参数。

"use strict";
var o = { 
    p: 1,
    p: 2
   };
// IE报错:strict 模式下不允许一个属性有多个定义, 新版的 Chrome 和 firefox 并不会报错,会采用覆盖机制。

"use strict";
function func(a, a) {
    console.log(a)
}
func(1, 2) // IE报错: strict 模式下不允许正式参数名称重复。新版的 Chrome 和 firefox 并不会报错,会采用覆盖机制。

静态绑定

JavaScript 支持动态绑定,也就是 JavaScript 的属性和方法是在运行时确定,而不是在编译时确定。
于是,JavaScript 严格模式禁用了 with 语句, 因为使用了 with 语句,with 语句块中变量无法确定是外部全局变量还是传入的对象属性。

"use strict";
var x = 17;
with (obj) // !!! 语法错误
{
  // 如果没有开启严格模式,with 中的这个x会指向 with 上面的那个 x,还是obj.x?
  // 如果不运行代码,我们无法知道,因此,这种代码让引擎无法进行优化,速度也就会变慢。
  x; // Uncaught SyntaxError: Strict mode code may not include a with statement
}

eval 关键字不再会给上层函数(surrounding function)或者全局引入一个新的变量。在严格模式中,eval 语句会创建自己的一个作用域,eval 里的变量只能在 eval 内部使用。

arguments 的限定

严格模式规定名称为 eval 和 arguments 不能通过程序语法被绑定(be bound)或赋值
严格模式下,参数的值不会随 arguments 对象的值的改变而变化。

正常模式中,对参数重新赋值,会修改 arguments 类数组对象下的参数值。同时,修改 arguments 类数组对象的值,也会修改函数参数的值。

严格模式下,不仅参数的值不会随着 arguments 类数组对象的变化而变化,参数的变化也不会引起 arguments 对象的变化,arguments 对象会记住参数的传入初始值。

function func(a) {
"use strict"
  a = 8;
  // arguments[0] = 8
  return [a, arguments[0]]
}

func(3) // [8, 3]

function func(a) {
"use strict"
  arguments[0] = 8
  return [a, arguments[0]]
}

func(3) // [3, 8]

ES5禁止在非函数代码块声明函数

ES5 的严格模式只允许在全局作用域或函数作用域声明函数。也就是说,不允许在非函数的代码块内声明函数。

if (true) {
  function add() {
  }
}
add()

for (var i = 0; i < 5; i++){
  function f2() { } // !!! 语法错误
  f2();
}

以上代码在严格模式是禁止的,但是在 ES6 中,是允许在代码块中声明函数的。

保留关键字

严格模式中一部分字符变成了保留的关键字。这些字符包括implements, interface, let, package, private, protected, public, staticyield。在严格模式下,你不能再用这些名字作为变量名或者形参名

function private() {"use strict" }  //Uncaught SyntaxError: Unexpected strict mode reserved word

严格模式禁止八进制数字语法

五、向严格模式过渡

严格模式能够帮助我们写出更安全,更有规范的代码,则应该避免一些危险的写法,采用更好的写法:

变量先声明,再使用,

this 应该在指向自己创建的对象时使用。

arguments 应该在函数第一行就拷贝出来。

六、严格模式的缺点

现在的代码都会进行文件压缩和合并,此时严格模式就会失效。

总结

现在的 webpack 会在打包的时候默认是严格模式,所以现在不用再手动写 use strict了。严格模式能帮助我们以更规范的方式书写代码,但是无论是否严格模式,都应该注意代码的规范,避免隐式 bug 的出现。

2018/02/08  @Starbucks

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101568.html

相关文章

  • underscore 系列如何写自己的 underscore

    摘要:因为在微信小程序中,和都是,加上又强制使用严格模式,为,挂载就会发生错误,所以就有人又发了一个,代码变成了这就是现在的样子。 前言 在 《JavaScript 专题系列》 中,我们写了很多的功能函数,比如防抖、节流、去重、类型判断、扁平数组、深浅拷贝、查找数组元素、通用遍历、柯里化、函数组合、函数记忆、乱序等,可以我们该如何组织这些函数,形成自己的一个工具函数库呢?这个时候,我们就要借...

    Invoker 评论0 收藏0
  • [面试专题]ES6箭头函数详解

    摘要:使用或调用由于已经在词法层面完成了绑定,通过或方法调用一个函数时,只是传入了参数而已,对并没有什么影响箭头函数不会在其内部暴露出参数等等,都不会指向箭头函数的,而是指向了箭头函数所在作用域的一个名为的值如果有的话,否则,就是。 ES6之箭头函数 标签(空格分隔): 未分类 返回值 单行函数体默认返回改行计算结果, 多行需要指定返回值 let c = (a,b)=>a+b; conso...

    Caicloud 评论0 收藏0
  • [面试专题]ES6箭头函数详解

    摘要:使用或调用由于已经在词法层面完成了绑定,通过或方法调用一个函数时,只是传入了参数而已,对并没有什么影响箭头函数不会在其内部暴露出参数等等,都不会指向箭头函数的,而是指向了箭头函数所在作用域的一个名为的值如果有的话,否则,就是。 ES6之箭头函数 标签(空格分隔): 未分类 返回值 单行函数体默认返回改行计算结果, 多行需要指定返回值 let c = (a,b)=>a+b; conso...

    sevi_stuo 评论0 收藏0
  • [面试专题]ES6箭头函数详解

    摘要:使用或调用由于已经在词法层面完成了绑定,通过或方法调用一个函数时,只是传入了参数而已,对并没有什么影响箭头函数不会在其内部暴露出参数等等,都不会指向箭头函数的,而是指向了箭头函数所在作用域的一个名为的值如果有的话,否则,就是。 ES6之箭头函数 标签(空格分隔): 未分类 返回值 单行函数体默认返回改行计算结果, 多行需要指定返回值 let c = (a,b)=>a+b; conso...

    chenjiang3 评论0 收藏0

发表评论

0条评论

baukh789

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<