嵌套对象里怎么访问外层属性
重构 caperjs 时绕过 this 链问题的一个记录。
发布 2017年8月09日 标签
#javascript
#scope
~/posts/this-chained $ cat post.md
问题
重构 caperjs 时遇到下面这种结构:
let a = {
b: 1,
c: {
d: function () {
return this;
},
e: function () {
console.log(b);
},
},
};
希望 a.c.d().e() 能拿到 b 的值。d 的 this 是 c,而 c 和 b 是同级的——要拿到 b,需要先定位到 a。如果 this 能继续追溯一层,那从 c 再 this 一次回到 a、再 .b(也就是 this.this.b),e 里就能取到值了。
但 this.this 在 JS 里和 Swift 的 self.self 不一样——它实际等价于 this['this'],而 c 里根本没有 'this' 这个属性。
尝试:用闭包
把 c 换成函数,在内部把 this 存到一个变量里给子方法用:
let a = {
b: 1,
c: function () {
let that = this;
return {
d: function () {
return this;
},
e: function () {
console.log(that.b);
},
};
},
};
但这样调用方就变成了 a.c().d().e()——多了一对括号,和原本的 a.c.d().e() 不一样。
现在再看
问题其实不在 this,而在 e 里引用的 b——它根本不在作用域里,必然报 ReferenceError。给它一个能找到的名字就行:
let a = {
b: 1,
c: {
d() {
return this;
},
e() {
console.log(a.b);
},
},
};
a.c.d().e(); // 1
e 是后面被调用的,那时 a 已经绑定完成,直接按名字引用就好。整件事不需要 this 链,也不必把 c 变成函数——只要把对外层的依赖明写出来。