3

这两种在 JavaScript 中定义“类”的方法有什么区别?

方法一

在构造函数中定义方法:

function MyClass()
{
    this.foo = function() { console.log('hello world!'); };
}

方法二

在原型上定义方法:

function MyClass()
{}

MyClass.prototype.foo = function() { console.log('hello world!'); };
4

2 回答 2

4

第一个将在对象的每个实例化上创建一个新的函数对象,第二个将为每个实例分配对原型方法的引用。简而言之:第二种效率更高,因为所有实例都将共享一个函数对象。

这只是原型链的逻辑,您可以尝试通过任何对象访问任何内容:

var objLiteral = {foo:'bar'};

访问objLiteral.fooJS时会先查看对象本身已经定义的属性,如果找到则返回值。如果 JS 找不到对象本身的属性,它会检查对象的原型,因此:

objLiteral.valueOf();//method defined @Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true

但是,当您使用第一种方法时:

function SomeConstructor()
{
    this.methd = function()
    {
        return true;
    }
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!

这表明我们正在处理 2 个单独的函数对象。将函数定义移动到原型中,f.methd === g.methd;这将是真的:

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!

回应您的评论:

在原型级别定义方法允许您更改特定任务的方法,然后将其“重置”回其默认行为。假设您在创建 AJAX 请求的函数中:

someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);

JS 将再次检查对象是否具有在其自身上toString定义的属性,它具有。因此 JS 将删除您分配给该属性的功能。下次调用时,JS 将重新开始扫描原型链,并使用方法的第一次出现(在原型中)。让我们澄清一下:toStringtoString

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined @ instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.

甚至更好的是,您甚至可以用另一个原型中的方法替换实例的方法:

f.methd = Object.prototype.valueOf;//for as long as you need

最后一个例子是没有意义的,因为 f 已经有了valueOf方法:它的继承链看起来像这样:var f ---> SomeConstructor ---> Object,让你也可以访问所有 Object.prototype 方法!整洁,不是吗?

这些只是虚拟的例子,但我希望你看到这是使 JS 成为难以置信的灵活(有时太灵活,我必须承认)和富有表现力的语言的特性之一。

于 2012-09-05T15:14:29.460 回答
2

在第一种情况下,将为每个实例创建函数并将其设置为foo对象中的属性。在第二种情况下,它是共享功能。当您调用obj.propthen 它在对象本身中查找它,如果它不存在,则它在proto对象中查找它等等,它被称为chain of prototypes

例如,此代码提供foo

function MyClass() {
  this.foo = function () {};
}

var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);

但这不是:

function MyClass() {
}

MyClass.prototype.foo = function () {};

var myVariable = new MyClass();
for (var i in myVariable) if (myVariable.hasOwnProperty(i)) console.log(i);
于 2012-09-05T15:13:52.903 回答