0

目前,我尝试理解 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 的原型对象中 - 好的,但在这种情况下,原型有什么优势?

4

2 回答 2

2

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

因为你不能在创建对象后更改它的原型。您正在设置原型属性,但 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.
}

NOTE __proto__不是标准化属性,不应在生产代码中使用,或者正如@alex 在他的评论中指出的那样,它正在标准化。

注 2:正如@thg435 在他的评论中提到的,使用该__proto__属性的替代方法是使用Object.setPrototypeOf()ES6 中的标准化。

编辑以涵盖最后一个问题

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 对象,并且您想为所有对象添加一个新方法而不依次修改每个对象,那么您可以将该方法添加到原型中,然后他们都将继承它。

于 2013-10-12T09:00:08.327 回答
1

Person不继承Person.prototype,只有Persondo 的实例。此外,对于一个普通的Object来说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
于 2013-10-12T09:05:14.123 回答