如何去耦合类中的嵌套对象函数

背景

这是一个简单的例子,演示了我正在努力完成的事情。 我正在尝试创build一个Person(name)Person(name) 。 这个类有一个对象say有几个与之相关的函数,例如

 Person.say.name(); 

当被调用时,这应该输出My name is (name provided)

简单的工作例子

 // node v0.10.15 var Person = function(name) { this.name = name; }; Person.prototype.greet = function() { console.log('Hello ' + this.name); }; Person.prototype.say = function() { var self = this; this.say = { name: function() { console.log('My name is ' + self.name); } }; }; Person.prototype.say(); var p = new Person('Nolan'); p.greet(); p.say.name(); 

以上将输出

 Hello Nolan My name is undefined 

我试过了

我试过使用绑定 :

 Person.prototype.say = function() { var name = function() { console.log('My name is ' + this.name); }; this.say = {}; this.say.name = name.bind(this); }; 

我也尝试在Person函数中使用defineProperty :

 var Person = function(name) { Object.defineProperty(this, 'name', { get: function() { return name; } }); }; 

但是输出保持不变。

什么工作

在Person函数中嵌套say对象的function是什么:

 var Person = function(name) { this.name = name; var self = this; this.say = { name: function() { console.log('My name is ' + self.name); } }; }; 

但是这正是我想要避免的,因为say对象除了name() (例如年龄,电子邮件等)之外还可以包含更多的函数,并且主Person函数会变得臃肿。

问题

如何从主Person函数中解耦say对象?

你的第一种方法不工作的原因是因为当你调用: x.say() ,在这个体内部会引用x

当你调用: x.say.name() ,在name体内, this将引用x.say

为了让x.say.name()给出正确的答案, x.say应该有一个对x的引用。 所以,在你的构造函数中,你需要将say对象和你的新实例连接起来(这就是为什么嵌套的东西可以工作)。

更好的分离可以这样完成:

 Sayer = function(person){ this.person = person; }; Sayer.prototype.name = function() { console.log('My name is ' + this.person.name); }; var Person = function(name) { this.name = name; this.say = new Sayer(this); }; Person.prototype.greet = function() { console.log('Hello ' + this.name); }; p = new Person('George'); p.say.name(); 

DEMO: http : //jsbin.com/OPuveGA/1/edit

PS:显然,你可以在你想要的任何命名空间(包括Person)中定义Sayer构造函数,所以你可以在Person构造函数中使用this.say = new Person.Sayer(this) – 检查上面的演示。

不知道这是你想到的:

 // node v0.10.15 var Person = function(name) { this.name = name; this.say = new Person.prototype.say(name); }; Person.prototype.greet = function() { console.log('Hello ' + this.name); }; Person.prototype.say = function(moniker) { this.moniker = moniker; this.name = function() { console.log('My name is ' + moniker); }; }; Person.prototype.say(); var p = new Person('Nolan'); p.greet(); p.say.name();