2012-10-01 52 views
2

我一直在尝试各种方法来模拟Javascript中的经典继承,并且我找到了一些方法来实现它。但是,我很好奇为什么我不能以某种方式做到这一点,以及我如何尝试解决它。Javascript - 在构造函数中用左手赋值来更改对象

我已经试过这样:

var squeaker = new squeek(); 

function monsterMaker(newMonster) { 
    newMonster.type = "monster"; 
    newMonster.health = 10; 
    return newMonster; 
} 

function squeek() { 
    this.name = "squeek"; 
    this = monsterMaker(this); 
} 

我想我明白为什么发生这种情况,我也想通了,它周围的方式(即jQuery的$ .extend),但有没有办法改变新创建的对象以这种方式使用左侧分配或解决方法,而不使用额外的库?

+2

您不能更改此参考。 –

回答

1

您不能分配到this,但你并不需要:你的代码,如果它的工作,将相当于该代码,它不工作:

var squeaker = new squeek(); 

function monsterMaker(newMonster) { 
    newMonster.type = "monster"; 
    newMonster.health = 10; 
    return newMonster; 
} 

function squeek() { 
    this.name = "squeek"; 
    monsterMaker(this); // sets properties on this 
} 

(虽然JavaScript是通在这种情况下,“值”是整个this对象,因此在某些方面它就像通过引用一样。)

+0

这工作完美。谢谢。 – Manic

+1

因为调用函数已经有了对传入对象的引用并且没有使用返回值,所以'monsterMaker'函数不需要返回。 – RobG

+0

@RobG:我不知道,我认为'monsterMaker'支​​持被称为'var monster = monsterMaker({})'是非常合理的。你说“回报价值不被使用”,但我认为你不可能真的知道这一点;你只知道'squeek'不使用它。 – ruakh

1

不,您不能指定为this。但是,你不需要!只需将实例(this)传递给monsterMaker,该函数就会为其添加一些属性 - 正是您想要的。您不需要返回对象,也不需要使用返回的对象 - 它仍然是this

function Squeek() { 
    this.name = "squeek"; 
    monsterMaker(this); 
} 

new Squeek(); // will have type and health 
+0

@ user1689607:否 - 'Squeek'是一个构造函数。 'return this'不会改变任何东西。 – Bergi

+0

是的,我错了。 +1 –

1

你应该尝试:

var squeaker = new squeek(); 

function monsterMaker(newMonster) { 
    this.type = "monster"; 
    this.health = 10; 
} 

function squeek() { 
    this.name = "squeek"; 
    monsterMaker.call(this); 
} 

这样你就可以“装饰”要与monsterMaker函数的性质的任何对象。

但是,进一步的思考,我想你已经到达了点,在那里你将需要原型继承...

1

这是一种与原型继承来做到这一点。要查看控制台输出,请在Chrome中按F12或在FireFox中打开FireBug。 Chrome会为您提供一个交互式对象来深入研究。

function monsterMaker() { 
    this.type = "monster"; 
    this.health = 10; 
} 

function squeek() { 
    this.name = "squeek"; 
    //monsterMaker.call(this); // sets properties on this 
} 
squeek.prototype = new monsterMaker(); 
squeek.prototype.constructor = monsterMaker; 

var squeaker = new squeek(); 

console.log(squeaker); 
console.log(squeaker.name); 
console.log(squeaker.type); 
console.log(squeaker.health); 

看到它在这里工作:

http://www.quirkscode.com/flat/forumPosts/extendThis/extendThis.html

这里有一些链接:

https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain

https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Inheritance_Revisited

从第二MDN链接上面拉,你可以做了 “新的JavaScript的方式”(ECMAScript中5),因此(包括库用于扩展和示例代码 - 使用控制台查看输出样本:

// Original Author: FireFly - Jonas Höglund - ##javascript channel 
// on irc.freenode.net - see THANKS File 

/////////////// 
// Library code 
/////////////// 

var ExtendBase = {}; 

Object.defineProperty(ExtendBase, 'extend', { 
    enumerable: false 
    , value: function(obj) { 
     'use strict'; 

     var descs = {} 
     , objectInheritCounter = 0; 

     objectInheritCounter += 1; 

     Object.getOwnPropertyNames(obj).forEach(function(key) { 
     descs[key] = Object.getOwnPropertyDescriptor(obj, key) 
     }); 

     return Object.create(this, descs); 
    } 
}); 

/////////////// 
// Sample Usage 
/////////////// 

var Person = ExtendBase.extend({ 
    // missing: name 

    // A person can tell you its name. 
    talk: function() { 
    return "Hello, I'm " + this.name 
    } 
}) 

var WorkingPerson = Person.extend({ 
    // missing: name, occupation 

    // A working person also tells you their occupation when they talk. 
    talk: function() { 
    return Person.talk.call(this) + " and I am a " + this.occupation 
    } 
}) 

var p1 = WorkingPerson.extend({ name:"Harry", occupation:"wizard" }) 
console.log(p1.talk()); // "Hello, I'm Harry and I am a wizard" 

看到它在这里工作:

http://www.quirkscode.com/flat/JSLearning/src/extend/extend.html

+0

我不认为健康点应该是原型上的一个属性... – Bergi

+0

Bergi:你能告诉我你为什么这么想吗?我不确定为什么 - 不是争论性的,只是不确定你为什么这么说。谢谢。 – Aeoril

0

JavaScipt是​​一种基于原型的语言。与其试图模仿经典的面向对象的语言,不如试着原型。

在这种情况下,您想创建一个Monster原型;和基于Monster原型的原型。然后你从对象实例化一个squeaker

/* Set up your Monster prototype */ 
function Monster() { /* constructor */} 
Monster.prototype.type = "monster"; 
Monster.prototype.health = 10; 

/* Now use the prototype of a Monster to create the prototype of a Squeek */ 
function Squeek() { /* constructor */ } 
Squeek.prototype = new Monster(); // thanks Bergi and RobG 
Squeek.prototype.constructor = Squeek; // thanks RobG 
Squeek.prototype.name = "squeek"; 

/* Now let's instantiate a Squeek */ 
var squeaker = new Squeek(); 
console.log(squeaker.name); // squeek 
console.log(squeaker.type); // monster 
console.log(squeaker.health); // 10 
console.log(squeaker.constructor === Squeek); // true 

var monster = new Monster(); 
console.log(monster.name); // undefined 
+0

为什么你将'Monster.prototype.name'设置为''squeek“'? – Bergi

+1

更好地将'Monster'的*实例*分配给'Squeek'的原型。另外,您还想修改'Squeek.prototype'的构造函数属性,因为这是'Squeek'实例将继承的属性。 Squeek构造函数是“函数”对象的一个​​实例,所以这就是它的构造函数属性(它继承自其['Prototype]]'应该引用的内容。 – RobG

+0

Bergi + RobG,谢谢你们的更正。 –