JavaScript prototype-Object - 如何访问继承

时间:2013-10-12 08:56:16

标签: javascript inheritance prototype

目前,我尝试了解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();

sayWeightsayHello功能有什么区别? sayWeight函数位于Person的prototype-object中 - 好吧,但是在这种情况下我从原型中获得了哪些优势?

2 个答案:

答案 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