访问原型父级

Accessing prototype parent

假设我有一个 Posts class。

我能做到:

Posts.prototype.foo = function () {
  console.log(this);
}

当我调用 post1.foo()post1Posts class 的实例)时,控制台输出的 this 将是等于 post1

现在考虑以下场景:

Posts.prototype.baz = {
  foo: function () {
   console.log(this);
  },
  bar: [1,2,3,4]
}

现在当我执行 post1.baz.foo() 时,this 的值不再是 post1,而是 {foo: ..., bar: ...}.

我的问题是:在第二种情况下,如何从 foo 中访问 post1

如果可以更改调用此方法的方式,则可以在 baz 中访问 this。例如:

post1.baz.foo.call(post1);

将在您的 foo 帖子 class 函数实例中创建 this 并将 console.log 更正对象。

Demo.

您遇到了一个有趣的问题。你所做的不是 Javascript 中的常见模式(将嵌套对象分配给原型),从表面上看它应该可以工作。

Javascript this 有两种解决方法。如果您正在使用 new 实例化函数,this 将成为对该实例化对象的引用(如您所知)。

但是,this 也可以解析为父对象 对象。也就是说,此代码将记录 'bar':

var obj = {
    prop: 'bar',
    log: function() { console.log( this.prop ); }
};
obj.log();

因为this引用了函数所在的对象。这就是你的情况。范围的解析比您想要的要早。

旁白:如果函数没有嵌套在对象中,并且您不使用 newthis 将成为全局对象(在浏览器中为 window) .

执行此操作的正确方法可能是在 Posts 的构造函数中,您可以在其中设置 this.whatever 并将其绑定到实例。此方法最常用于 "private" 变量,但当您需要将计算数据添加到 class 或在您的情况下声明特定范围时也很有用。

function Posts() {
    var self = this;

    this.baz = {
        foo: function () {
            console.log(self);
        },
        bar: [1,2,3,4]
    }
}

你也可以这样做:

    ...
    this.baz = {
        foo: function () {
            console.log(this);
        }.bind(this),

您可能想仔细看看为什么需要 class 原型上的嵌套对象。你能把它分解成所有平面原型方法吗?它是不需要在每个 class 实例上实例化的数据,并且可以从其他地方提取出来吗?

只要你有一个 "this" 关键字,它绑定到的对象取决于调用站点。仅在呼叫站点上。这里有更深入的讨论 you don't know js。我强烈建议你阅读那个。但是,如果你让我过度简化它,可以这样考虑:

每当你执行一个函数时,它大致就像你在做以下事情:

//default binding
fn() ~ fn.call(window)
// the default binding of this, is window, or undefined in strict mode.

但是,您可以使用

调用该函数
//implicit binding
obj.fn() ~ fn.call(ojb) 
// in this case you are implicitly binding this as the obj

或者如果你想明确,使用callapply:

//explicit bining
fn.call(obj)  
//this is explicitly binding obj as this.

它们的优先级是显式 > 隐式 > 默认。

在你的情况下,你是 运行 post1.baz.foo():你的呼叫站点是 .baz。对于规则 2,您将 this 绑定到 baz。您想要的是显式调用 post1.baz.foo.call(post1);

浅见如下

那真的很丑,所以我能感受到你的痛苦。它之所以如此复杂,是因为您正在 违背语言的原则 。这可能是因为您试图以 java 方式进行继承。

最后,还有一个绑定,但要避免它:new。如果可以,永远不要使用新的。 JS不是java,new的行为很迷惑。如果要实例化新对象,使用Object.create.