【问题标题】:Accessing prototype parent访问原型父级
【发布时间】:2015-12-01 08:36:43
【问题描述】:

假设我有一个Posts 课程。

我能做到:

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

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

现在考虑以下场景:

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

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

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

【问题讨论】:

    标签: javascript class inheritance prototype this


    【解决方案1】:

    只要你有一个“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。

    【讨论】:

    • 谢谢,我去看看那个帖子。我想我主要了解呼叫站点的问题,我只是认为可能有一些巧妙的语法解决方法。
    【解决方案2】:

    您遇到了一个有趣的问题。你所做的不是 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 并将其绑定到实例。此方法最常用于“私有”变量,但当您需要将计算数据添加到您的类或在您的情况下声明特定范围时也很有用。

    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),
    

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

    【讨论】:

    • 很好的答案,谢谢!我可能会将其分解为平面原型方法。我实际上认为这样做会“更干净”,因为我不会污染类的命名空间。但是后来我碰到了这个问题……
    • 另外,我无法修改 Posts 类本身,所以我想我无法使用您的其他解决方案。
    • 根据您的用例,另一种可能的解决方案是创建一个包含帖子的包装类(由您控制​​)。修改别人的原型通常会导致历史问题。
    【解决方案3】:

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

    post1.baz.foo.call(post1);
    

    将在 Posts 类的 foo 函数实例中创建 this 并将 console.log 正确的对象。

    Demo.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-17
      • 1970-01-01
      • 1970-01-01
      • 2013-06-24
      • 2018-11-17
      • 2017-02-25
      相关资源
      最近更新 更多