JavaScript 中目前比较少见的表达式

2021-06-07  本文已影响0人  ByePast

??空值合并运算符es2020

??是一个逻辑操作符,当左侧的操作数为 null或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

与逻辑或操作符||不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。
比如为假值(例如,''0)时。见下面的例子:

const foo = null ?? 'default string'
console.log(foo) // "default string"

const baz = 0 ?? 42
console.log(baz) // 0

const bar = false ?? true
console.log(bar) // false

注意??不能与 &&|| 操作符共用

null || undefined ?? "foo" // 抛出 SyntaxError
true || undefined ?? "foo" // 抛出 SyntaxError

但是,如果使用括号来显式表明运算优先级,是没有问题的:

(null || undefined ) ?? "foo" // 返回 "foo"

?.可选链操作符es2020

可选链操作符?.允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。
?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空值要么是 null要么是 undefined的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined

const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah'
  }
}

const dogName = adventurer.dog?.name
console.log(dogName) // undefined

console.log(adventurer.someNonExistentMethod?.()) // undefined

console.log(adventurer.list?.forEach(() => {})) // undefined

对比一下代码

const obj = {}
let nestedProp = obj.first?.second

这等价于以下表达式,但实际上没有创建临时变量:

const obj = {}
let temp = obj.first
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second)

可选链与函数调用
当尝试调用一个可能不存在的方法时也可以使用可选链。

const someInterface = {}
let result = someInterface.customMethod?.()

可选链和表达式
当使用方括号与属性名的形式来访问属性时,你也可以使用可选链操作符:

let list = null
console.log(list?.[1]) // undefined

注意

const someInterface = {
   customMethod: 'Not Method'
}

let result = someInterface.customMethod?.();
// Uncaught TypeError: someInterface.customMethod is not a function
let someInterface = null
someInterface?.customMethod?.() // undefined

逗号运算符间接函数调用

先介绍一下逗号运算符
逗号运算符

对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

let x = 1
x = (x++, x)
console.log(x) // 2

x = (2, 3)
console.log(x) // 3

(0, alert)('ByePast')逗号运算符衍生出来的间接函数调用

使用间接函数调用可以把该作用域内倍的this指向全局对象中的this

在调用函数的上下文中,对操作数的评估只会得到一个值,而不是引用,这会导致this被调用函数内部的值指向全局对象(或者它将undefined处于新的 ECMAScript 5 严格模式)例如:

var foo = 'global.foo'

var obj = {
  foo: 'obj.foo',
  method: function () {
    return this.foo
  }
};

obj.method() // 'obj.foo'
(1, obj.method)() // 'global.foo'

如您所见,第一次调用,即直接调用,this内部的值method将正确引用obj(返回'obj.foo'),第二次调用,逗号运算符所做的评估将使this值指向全局对象(产生'global.foo')。

这种模式很流行,要间接调用eval,这在 ES5 严格模式下很有用,例如,获取对全局对象的引用(假设您在非浏览器环境中,window不是可用的)

(function () {
  'use strict';
  var global = (function () { return this || (1, eval)('this') })();
})();

在上面的代码中,内部匿名函数将在严格模式代码单元内执行,这将导致this值为undefined

||运营商现在就第二个操作数的eval调用,这是一个间接调用,它将评估对全球词法和环境变量的代码。

但就我个人而言,在这种情况下,在严格模式下,我更喜欢使用Function构造函数来获取全局对象:

(function () {
  'use strict'
  var global = Function('return this')()
})()

使用Function构造函数创建的函数只有在以 use strict 指令开头时才是严格的,它们不像函数声明或函数表达式那样“继承”当前上下文的严格性

上一篇下一篇

猜你喜欢

热点阅读