JavaScript 原型对象 - 如何访问继承

JavaScript prototype-Object - how to access inheritance

本文关键字:访问 继承 何访问 原型 对象 JavaScript      更新时间:2023-09-26

目前,我试图理解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);

现在我的问题:我将人员对象分配给我的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 的原型对象中 - 好的,但是在这种情况下,我从原型中有什么优势?

你能解释一下这种行为吗?为什么我无法访问 sayWeight(( 函数?

因为创建对象后无法更改对象的原型。您正在设置 prototype 属性,但 javascript 解释器使用的内部原型引用,即 __proto__ 仍然是实际使用的引用,当前__proto__引用的是 Object.prototype

如果您将此行friend.prototype = Person;更改为此行friend.__proto__ = Person.prototype;则一切正常。

如果您的浏览器支持 ES5,那么您可以使用 Object.create() 来创建继承自给定原型的对象,或者您可以使用 Javascript: The Good Parts 一书中采用的解决方法,并由 David Flanagan 在他的书中稍微扭曲: Javascript 权威指南:

// 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__属性的替代方法是使用ES6中标准化的Object.setPrototypeOf()

编辑以涵盖最后一个问题

sayweight和sayHello函数有什么区别?

不同之处在于,现在每个新的Person实例(例如new Person()(将具有不同的sayHello()函数,但具有共享的sayWeight()函数。

var friend = new Person();
var anotherFriend = new Person();
console.log(friend.sayHello === anotherFriend.sayHello); // OUTPUTS FALSE
console.log(friend.sayWeight === anotherFriend.sayWeight); // OUTPUTS TRUE

在这种情况下,原型有什么优势?

更少的内存,代码在所有 person 实例中重用,如果您已经有一个或多个 person 对象,并且想要向所有这些对象添加一个新方法而不依次修改每个对象,那么您可以将该方法添加到原型中,它们都将从中继承。

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