2015-09-05 84 views
1

假设我有一个Posts类。访问原型父项

我可以这样做:

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

当我打电话post1.foo()(与post1作为Posts类的实例),由控制台输出的this将等于post1

现在考虑以下情形:

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

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

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

回答

2

你都撞在一个有趣的问题。你正在做的不是Javascript中的常见模式(为原型分配一个嵌套对象),表面上它看起来应该起作用。

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

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

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

因为this被引用对象的功能在里面。这就是你的情况。范围正在比您想要的更早解决。另外:如果函数没有嵌套在一个对象中,并且你没有使用new,那么this将成为全局对象(window在浏览器中)。

正确的方式做,这可能是在构造函数中的帖子,在这里你可以设置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), 

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

+0

很好的答案,谢谢!我可能会把它分解成平面原型方法。我其实认为这样做会更“干净”,因为我不会污染班级的名字空间。但后来我碰到这个问题... – Sacha

+0

另外,我不能修改'Posts'类本身,所以我想我不能使用你的其他解决方案。 – Sacha

+0

根据您的使用情况,另一个可能的解决方案是制作一个包含它的包装类(您控制的)。修改别人的原型往往会导致历史上的问题。 –

0

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

post1.baz.foo.call(post1); 

会让this文章类的你foo的功能实例内将console.log正确的对象。

Demo.

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. 

这些的优先级是explicit> implicit> default。

在你的情况下,你正在运行post1.baz.foo():你的呼叫站点是.baz。对于规则2,您绑定了thisbaz。你想要的是明确的,并致电post1.baz.foo.call(post1);

浅见如下

这实在是太丑了寿,所以我觉得你的痛苦。其原因如此复杂,是因为您正在针对谷物的语言工作。这可能是因为你正在尝试以java方式进行继承。

最后,还有一个绑定,但避免它:new。如果可以,永远不要使用新的。 JS不是Java,新的行为非常混乱。如果你想实例化新的对象,使用Object.create。

+0

谢谢,我会查看该帖子。我想我主要了解这个呼叫站点的问题,我只是觉得可能有某种聪明的syntaxic解决方法。 – Sacha