2016-12-07 45 views
1

我很困惑,为什么我在这里得到这个错误。我想要一些启发。JavaScript对象原型似乎破碎

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); 
 
console.log(d2.speak()); 
 

 
console.log(d.speak()); //returns: TypeError: d.speak is not a function

returns: TypeError: d.speak is not a function

我明确地将属性添加到speakd.prototype。实际上,d1d2都可以访问其原型层次结构中的属性/函数。但是当我试图在d上调用它时,我得到一个TypeError。我尝试了各种“调整”,无济于事。为了排除任何范围问题,我尝试在IIFE中包装各种部分,但它没有效果。我从最后一行

console.log(d.speak); //returns: undefined 

,并得到undefined删除()。这告诉我speak不是d有权访问的属性/函数。即。将speak更改为blah,并获取登录到控制台的相同undefined

console.log(d.blah); //returns: undefined 

我知道我错过了一些可能对一组新的眼睛很明显的小东西。

+1

'd.speak()'不会工作,因为你已附上'说话()'函数到'D'的原型对象函数,而不是'd'函数本身。因此,无论是需要将'speak()'函数附加到'd'本身,比如'd.speak = function(){}'或调用'd.prototype.speak()'来调用它。 –

+1

我不知道你期望'd.speak()'返回什么结果? – Oriol

+0

@Oriol,'你好,我没有定义。'是我的期望。 – ppovoski

回答

3

这是预期。在大多数情况下,构造函数不是它自己的一个实例。构造函数定义了在其实例prototype中可用的方法,但是这个prototype没有出现在构造函数本身的[[Prototype]]链中。

理由很简单:

  • 一个目的只能有单一的[[Prototype]]。

  • 构造函数是一个函数,所以在[[Prototype]]链中必须有Function.prototype。这允许您在构造函数上调用函数方法,如callapply

  • 实例必须从构造函数的prototype继承,但不能从Function.prototype继承,因为它们不是函数。

因此,通常构造函数不能从它的prototype继承。有两个内置的例外:FunctionObject

也就是说,你可以选择摆脱上面的第二个或第三个不变量。然后你可以使它工作,但这是一个坏主意,因为通常人们依赖它们,而改变[[Prototype]]的性能很差。

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 
Object.setPrototypeOf(d, d.prototype); 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); // "Hello, I am d1." 
 
console.log(d2.speak()); // "Hello, I am d2." 
 
console.log(d.speak()); // "Hello, I am undefined." 
 

 
console.log(d.call); // undefined :(

function c(me) { this.me = me; } 
 
c.prototype = Object.create(Function.prototype); 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 
Object.setPrototypeOf(d, d.prototype); 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); // "Hello, I am d1." 
 
console.log(d2.speak()); // "Hello, I am d2." 
 
console.log(d.speak()); // "Hello, I am undefined." 
 

 
console.log(d1 instanceof Function); // true Huh????

+0

+1,但你应该在“*选择去除不变量*”之后添加一个免责声明,这是一个非常糟糕的主意:-) – Bergi

+0

@Bergi当然!我想警告但忘记了,谢谢。 – Oriol

+0

钉钉!干得不错! – ppovoski

1

您的变量d是一个构造函数函数。使用该构造函数上的prototype属性来访问您的实例从中继承的原型对象

console.log(d.prototype.speak) //=> [Function] 

演示:

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); 
 
console.log(d2.speak()); 
 

 
console.log(d.prototype.speak) //=> [Function]

+0

所以你是说用于该函数的变量'd'与用于原型的'd'不一样? – ppovoski

+1

函数'd'从未用于原型,只作为构造函数。 JavaScript中的每个函数都有自己的原型对象; 'd1'和'd2'的原型都是'd.prototype'。另一种思考方式:每次调用'new d'时,真正发生的事情是'Object.create(d.prototype)'。 – gyre