目前,我尝试了解Javascript原型对象。 以下情况:
// new Person object
function Person () {
this.greeth = function() {
console.log("Good morning, " + this.name);
};
};
// add new function to Person.prototype for inheritance
Person.prototype.sayWeight = function() {
console.log(this.weight);
};
// create new friend object
var friend = {
forename: "Bill",
lastname: "Gates",
weight: 78,
sayhello: function() {
console.dir("Hello " + this.forename + ' ' + this.lastname);
}
};
// assign Person.prototype to friend.prototye (inheritance)
friend.prototype = Person;
console.dir(friend);
现在我的问题:
我将Person对象分配给我的friend.prototype
。
根据我的理解,“friend
”应具有Person.prototype
的所有功能(即sayWeight()
friend.prototype = Person;
的原因。
但我能打电话的唯一功能就是friend.sayhello。
在我的输出(console.dir(friend);
)中,我可以看到sayWeight()
函数,但是当我调用它时,我收到错误(TypeError: Object #<Object> has no method 'sayWeight'
)
你能解释一下这种行为吗?为什么我无法访问sayWeight()
函数?
=============================================== ==========
另一个问题:
function Person() {
this.name = "Bill Gates";
this.weight = 78;
this.sayHello = function() {
console.log("Hello " + this.name);
}
}
Person.prototype.sayWeight = function() {
console.log(this.weight);
}
var friend = new Person();
sayWeight
和sayHello
功能有什么区别? sayWeight
函数位于Person的prototype-object中 - 好吧,但是在这种情况下我从原型中获得了哪些优势?
答案 0 :(得分:2)
你能解释一下这种行为吗?为什么我不能访问sayWeight()函数?
因为在创建对象后无法更改对象的原型。您正在设置prototype属性,但是javascript解释器使用的内部原型引用,即__proto__
仍然是有效使用的引用,目前__proto__
指的是Object.prototype
。
如果您将此行friend.prototype = Person;
更改为此friend.__proto__ = Person.prototype;
,那么一切都会有效。
如果您的浏览器支持ES5,那么您可以使用Object.create()
创建从给定原型继承的对象,或者您可以使用Javascript:The Good Parts一书中采用的解决方法,并且由David Flanagan扭曲一点在他的书中:Javascript The Definitive Guide:
// inherit() returns a newly created object that inherits properties from the
// prototype object p. It uses the ECMAScript 5 function Object.create() if
// it is defined, and otherwise falls back to an older technique.
function inherit(p) {
if (p == null) throw TypeError(); // p must be a non-null object
if (Object.create) // If Object.create() is defined...
return Object.create(p); // then just use it.
var t = typeof p; // Otherwise do some more type checking
if (t !== "object" && t !== "function") throw TypeError();
function f() {}; // Define a dummy constructor function.
f.prototype = p; // Set its prototype property to p.
return new f(); // Use f() to create an "heir" of p.
}
注意 __proto__
不是标准化属性,不应在生产代码中使用,或者@alex在其评论中指出它正在标准化的过程中。
注2:正如@ thg435在评论中提到的,使用__proto__
属性的替代方法是使用Object.setPrototypeOf()
,这是在ES6中标准化的。
sayWeight和sayHello函数之间有什么区别?
不同之处在于,现在Person
的每个新实例(例如new Person()
)都将具有不同的sayHello()
函数,但是共享{{1功能。
sayWeight()
在这种情况下,我从原型中获得了哪些优势?
更少的内存,跨所有人的实例重用代码,并且如果您已经有一个或多个人对象,并且想要为所有这些对象添加新方法而不依次修改每个对象,那么您可以将该方法添加到原型,他们都将继承它。
答案 1 :(得分:1)
Person
不会继承Person.prototype
,只会Person
的实例。此外,正常的对象说foo = {}
,foo.prototype
只是一个普通的属性。您需要构造函数或创建初始对象,将其定义为具有特定原型。
你真正想要的是
friend = Object.create(Person.prototype);
// or, for older browsers
friend = new Person();
// or some Object.create shim
/* which gives you
friend inherits Person.prototype
inherits Object.prototype */
这将建立原型链。如果您想创建许多朋友,最好设置一个新的构造函数 Friend
,其中包含Friend.prototype = Object.create(Person.prototype);
。如果您要向Person.prototype
添加属性,这也会保护Friend.prototype
。那么你会有
(instanceof) Friend inherits Friend.prototype
inherits Person.prototype
inherits Object.prototype