4

我正在学习 JavaScript。

为什么要在对象之外定义函数?

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName;   
}

Man.prototype.getName = function () {    
    return this.firstName + this.lastName;
};

对我来说看起来有点奇怪。如果我在类中添加函数(删除 .protoype 等),它会起作用,但我被告知要在对象之外定义函数。

为什么?

4

2 回答 2

8

对我来说看起来有点奇怪。

这就是设置由构造函数分配的原型的工作原理。而且你不是唯一一个觉得尴尬的人,见下文。:-) (更新:请参阅下文,了解 ES6 如何使这变得如此简单。

如果我在类中添加函数(删除 .protoype 等),它会起作用,但我被告知要在对象之外定义函数。

如果你这样做:

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName;
    this.getName = function () {    
        return this.firstName + this.lastName;
    };
}

...然后每个Man对象都有自己的函数副本。他们不共享,您最终会为每个对象创建一个新的函数Man对象。(智能引擎可以重用底层函数代码,但会有两个函数对象。)原型的目的是创建可以被构造函数构造的对象共享的特性。

原型的另一个好处是对象与原型的连接是持续的,这意味着您可以通过添加到它们的原型来向已经存在的对象添加特性。例子:

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName;   
}

Man.prototype.getName = function () {    
    return this.firstName + " " + this.lastName;
};

var joe = new Man("Joe", "Bloggs");
console.log(joe.getName()); // "Joe Bloggs"

Man.prototype.introduction = function() {
    return "Hi there, I'm " + this.getName();
};

console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs"

请注意我们在创建如何添加introduction到原型中。没关系,查找是动态的。当你这样做时,引擎会寻找一个属性,如果没有找到它,就会去寻找原型。因此,稍后(间接)添加到原型中会增强现有对象。 joejoe.introductionintroductionjoe


你不是唯一一个觉得语法尴尬的人。您经常看到人们创建“ extend”方法,例如 jQuery、Underscore、Prototype 等中的方法。extend 方法只是将源对象的属性分配给目标对象。它的简单形式是:

function extend(target, source) {
    var name;
    for (name in source) {
        target[name] = source[name];
    }
}

...尽管通常您会看到具有更多功能的东西(多个源对象,返回目的地等)。

然后你可以像这样使用它:

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName;   
}
extend(Man.prototype, {
    getName: function () {    
        return this.firstName + this.lastName;
    },
    introduction: function() {
        return "Hi there, I'm " + this.getName();
    }
});

它使用对象初始值设定项语法(有时称为“对象文字”),将其传递给extendextend并将属性放在Man.prototype.

您还会看到像我的Lineage脚本这样的东西,它进一步简化了语法并处理了一些其他的事情(比如调用父原型的函数版本)更简单。


从 ES6 开始,它几乎已经完成并且正在进入浏览器(你也可以转译),这变得简单多了:

class Man { 
    constructor(firstName, lastName) {
        this.firstName = firstName; 
        this.lastName = lastName;   
    }

    getName() {    
        return this.firstName + " " + this.lastName;
    }

    introduction() {
        return "Hi there, I'm " + this.getName();
    }
}

var joe = new Man("Joe", "Bloggs");
console.log(joe.getName()); // "Joe Bloggs"

console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs"
于 2013-07-28T08:26:53.547 回答
1

可以在对象内部定义函数,但这并不总是可能的(内置对象、第三方库等)。

大概这本书/教程/老师希望您使用原型,因为他们希望您学习如何使用该方法扩展对象。

于 2013-07-28T08:24:11.833 回答