JavaScript的bind方法在getter属性上不起作用。

18

试图做到这一点:

var c = {
  x: 'other context'
};

var o = {
  x: 'this context',
  get otherContext () {
    alert(this.x);
  }.bind(c)
};

o.otherContext;

但是我遇到了一个Syntax Error:

Uncaught SyntaxError: Unexpected token .

一个使用场景

你可能会问,为什么我想在getter上更改上下文。让我来说一下我在这里的应用场景:创建一个检索DOM属性的帮助对象。该助手对象在另一个对象内进行定义,该对象持有我需要属性的DOM元素的引用。所以,这个助手对象实际上只是一些DOM方法的代理,并且我会做一些类似这样的事情:

var ViewObject = function () {
  this.el = document.getElementById('id');
  
  var proxy = {
    ...
    get left() {
      return this.el.offsetLeft
    }.bind(this)
    ...
  };
};

在我看来,这是一个相当合理的用例。并且其中一个具有父对象“this”上下文将会很有用。(也许代理功能可能更适合?嗯...我没有考虑过。尽管获取器是ES5而代理是ES6,并且仅由evergreens和Edge 13+实现,但在ES5范围内,我认为这个问题仍然非常适用。)

有人能给我一个逻辑解释(最好引用规范),说明为什么更改getter的上下文是非法的吗?


1
дљ†еПѓиГљйЬАи¶БдљњзФ®definedPropertyжЭ•еЃЪдєЙдљ†жГ≥и¶БзЪДgetterгАВ - elclanrs
好的。请直接发布您的示例作为答案,即使它不完全符合问题要求也可以。 - seebiscuit
2个回答

16
问题在于方法语法不使用函数表达式。它是一种定义好的语法结构。

MethodDefinition[Yield]

PropertyName[?Yield] ( StrictFormalParameters ) { FunctionBody }

GeneratorMethod[?Yield]

get PropertyName[?Yield] ( ) { FunctionBody }

set PropertyName[?Yield] ( PropertySetParameterList ) { FunctionBody }

PropertySetParameterList

FormalParameter

由于它不是函数表达式,因此您无法访问函数的方法或属性。

您可以使用Object.defineProperty来实现您想要的功能。

var proxy = { ... };
Object.defineProperty(proxy, 'left', {
  get: function() {
    return this.el.offsetLeft;
  }.bind(this)
});

那么,{ aFunc() { ... } } != { aFunc: function () { ... } }!?(我并不是在进行JS比较,只是规范上的属性定义。外部括号存在是为了给方法提供“上下文”)。如果以上内容是真的,那么这与getter/setter无关,而是与方法语法有关! - seebiscuit
我不相信defineProperty的解决方案可行。似乎绑定函数的this值被覆盖为getter的所有者。如果你有var proxy = {foo: "foo"};并且你执行.bind({foo: "bar"}),调用proxy.left会给你一个"foo"而不是"bar"的结果……除非我在某个地方犯了错误。 - user1106925
请注意,您还可以使用 Object.defineProperties() 方法,它允许您一次定义多个属性(如果您不想使用默认值,则需要更多的冗长代码)。 - Andrew

3

对于类代理,您可能想使用以下内容:

class Main {
    constructor() {
        this._adapter = new Adapter();
        return this._createProxy();
    }

    _createProxy() {
        return new Proxy(this, {
            get(me, propertyName) {
                if (typeof me._adapter[propertyName] === 'function') {
                    return me._adapter[propertyName].bind(me._adapter);
                }
                return (function () {
                    return me._adapter[propertyName];
                }.bind(me._adapter))();
            }
        });
    }
}

class Adapter {
    constructor() {
        this._foo = true;
        this._yuk = 2;
    }

    get foo() {
        return this._foo;
    }

    baz() {
        return 4*this._yuk;
    }
}

这样做,getter和方法都将在正确的上下文中封装:
let main = new Main();
console.log(main.foo);   // -> true
console.log(main.baz()); // -> 8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接