JavaScript高级深入浅出:with-eval-strict

123 阅读4分钟

介绍

本文是 JavaScript 高级深入浅出系列的第九篇,将了解到 JS 的扩展知识evalwith严格模式

正文

在 ES5 之前,作用域只有两种:全局作用域函数作用域(函数作用域被嵌套在全局作用域或父作用域中)

1. with

var obj = {
  a: 1,
  b: 2,
  c: 3,
}

// 需要调用 3 次 obj
obj.a = 'a1'
obj.b = 'b1'
obj.c = 'c1'

with (obj) {
  a = 'a2'
  b = 'b2'
  c = 'c2'
}

console.log(obj)

with语句可以修改所有 obj 中的变量了。同时,with语句也不仅仅能做这些:

var message = 'global'

var obj = {
  message: 'obj',
}

function foo() {
  function bar() {
    console.log('bar running', message)
  }
  function baz() {
    // with 语句将 baz 内部的作用域修改为 obj 的 子作用域
    // 所以在找 message 的时候会优先从 obj 中找
    with (obj) {
      console.log('baz running', message)
    }
  }
  bar()  // global
  baz()  // obj
}

foo()

with语句看似非常方便,但是有一个非常严重的问题:with语句会创建一个独立的作用域,也就是我们所说的作用域欺骗,对于性能会造成一定影响。

  • with现在已经不建议使用!

2. eval

eval 是一个函数,可以将传入的字符串参数作用 JS 代码使用

eval('var message = "hello world";console.log(message)')
console.log(message) // hello world

也不建议在开发中使用eval

  • 可读性很差
  • eval 是一个字符串,那么在执行过程中就有可能会造成篡改,有安全问题
  • eval 会造成作用域欺骗
  • eval 的执行必须经过 JS 解释器,不能被 JS 引擎优化

3. 严格模式

在 ES5 模式下,JS 提出了严格模式的概念(Strict Mode)

  • 严格模式很好理解,是一种具有限制性的 JS 模式,从而使代码隐式的脱离了懒散模式(Sloopy Mode)
  • 支持严格模式的浏览器在检测代码中有严格模式时,会更加严格的对代码进行校验检测和执行

严格模式对于正常 JS 的语义有一定的限制:

  • 严格模式通过抛出错误来消除一些原有的静默(slient)错误
  • 严格模式让 JS 在执行代码时可以进行更多的优化
  • 严格模式下禁用了 ES 未来版本可能会定义的关键字

3.1 开启严格模式

// 1. 给 JS 文件开启严格模式
'use strict'
function foo() {
    
}
// ... other code
// 2. 给单个函数开启严格模式
function bar() {
    'use strict'
}

// other code

3.2 严格模式限制

这里只说几个严格模式下的语法限制:

无法意外的创建全局变量

'use strict'
function foo() {
  // 在松散模式下,这种代码相当于在全局创建变量
  // 在严格模式下,会报错
  age = 20
}
foo()

严格模式下会使引起静默失败(silently fail,指不报错也没有任何效果)的赋值操作抛出异常

'use strict'
true.foo = 'bar'  // 这种静默错误在严格模式下会报错
'use strict'
var obj = {}

Object.defineProperty(obj, 'name', {
  writable: false,
  value: 'alex',
})

console.log(obj.name) // 可读
// 松散模式下,这行代码不会报错,也属于一个静默错误
// 但是严格模式下会报错
obj.name = '123'

严格模式下无法删除不可删除的属性

'use strict'
var obj = {}

Object.defineProperty(obj, 'name', {
  configurable: false,
  writable: false,
  value: 'alex',
})

console.log(obj.name) // 可读
delete obj.name  // 严格模式下不允许删除不可删除的属性

严格模式下不允许函数参数有相同名称

'use strict'
// 不允许函数参数有相同的名称
function foo(a, b, a) {}

不允许 0 的八进制语法

'use strict'
var num = 0123  // 严格模式下不允许八进制语法
// ES6 之后
var num2 = 0o123  // 八进制
num2 = 0x123  // 十六进制
num2 = 0b123  // 二进制

不允许使用 with

上面已经说过,这里不再重复

eval 不再为上层引用变量

'use strict'
eval('var message = "hello";console.log(message)')
console.log(message)  // 松散模式下,这一行可以打印,但是严格模式下不可以

this 绑定不会默认转为对象

'use strict'
function foo() {
  console.log(this)
}
foo()  // 松散模式默认绑定指向 window,严格模式下指向 undefined,其他绑定规则不变

总结

本文中,你学到了 3 个知识点:

  • with 语句,以及缺点
  • eval 函数,以及缺点
  • 严格模式,以及严格模式的开启方法和严格模式下部分对于语法的限制