优秀的编程知识分享平台

网站首页 > 技术文章 正文

this全面解析(五)(this 5)

nanyue 2024-07-20 00:10:26 技术文章 4 ℃

绑定例外

规则总有例外,这里也一样。

在某些场景下 this 的绑定行为会出乎意料,你认为应当应用其他绑定规则时,实际上应用 的可能是默认绑定规则。

被忽略的this

如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值 在调用时会被忽略,实际应用的是默认绑定规则:

那么什么情况下你会传入 null 呢?

一种非常常见的做法是使用 apply(..) 来“展开”一个数组,并当作参数传入一个函数。 类似地,bind(..) 可以对参数进行柯里化(预先设置一些参数),这种方法有时非常有用:

这两种方法都需要传入一个参数当作 this 的绑定对象。如果函数并不关心 this 的话,你 仍然需要传入一个占位值,这时 null 可能是一个不错的选择,就像代码所示的那样。

在 ES6 中,可以用 ... 操作符代替 apply(..) 来“展 开”数组,foo(...[1,2]) 和 foo(1,2) 是一样的,这样可以避免不必要的 this 绑定。可惜,在 ES6 中没有柯里化的相关语法,因此还是需要使用 bind(..)。

然而,总是使用 null 来忽略 this 绑定可能产生一些副作用。如果某个函数确实使用了 this(比如第三方库中的一个函数),那默认绑定规则会把 this 绑定到全局对象(在浏览 器中这个对象是 window),这将导致不可预计的后果(比如修改全局对象)。

显而易见,这种方式可能会导致许多难以分析和追踪的 bug。

更安全的this

一种“更安全”的做法是传入一个特殊的对象,把 this 绑定到这个对象不会对你的程序 产生任何副作用。就像网络(以及军队)一样,我们可以创建一个“DMZ”(demilitarized zone,非军事区)对象——它就是一个空的非委托的对象,委托以后会说到

如果我们在忽略 this 绑定时总是传入一个 DMZ 对象,那就什么都不用担心了,因为任何 对于 this 的使用都会被限制在这个空对象中,不会对全局对象产生任何影响。

由于这个对象完全是一个空对象,可以随便起一个名字命名,无论你叫它什么,在 JavaScript 中创建一个空对象最简单的方法都是 Object.create(null) ,Object.create(null) 和 {} 很像,但是并不会创建 Object. prototype 这个委托,所以它比 {}“更空”:

使用变量名 ? 不仅让函数变得更加“安全”,而且可以提高代码的可读性,因为 ? 表示 “我希望 this 是空”,这比 null 的含义更清楚。不过再说一遍,你可以用任何喜欢的名字 来命名 DMZ 对象。

间接引用

另一个需要注意的是,你有可能(有意或者无意地)创建一个函数的“间接引用”,在这 种情况下,调用这个函数会应用默认绑定规则。

间接引用最容易在赋值时发生:

赋值表达式 p.foo = o.foo 的返回值是目标函数的引用,因此调用位置是 foo() 而不是 p.foo() 或者 o.foo()。根据我们之前说过的,这里会应用默认绑定。

注意:对于默认绑定来说,决定 this 绑定对象的并不是调用位置是否处于严格模式,而是 函数体是否处于严格模式。如果函数体处于严格模式,this 会被绑定到 undefined,否则 this 会被绑定到全局对象。

最近发表
标签列表