两者之间有什么区别
var A = function () {
this.x = function () {
//do something
};
};
and
var A = function () { };
A.prototype.x = function () {
//do something
};
两者之间有什么区别
var A = function () {
this.x = function () {
//do something
};
};
and
var A = function () { };
A.prototype.x = function () {
//do something
};
当前回答
当您使用原型时,函数只会被加载到内存中一次(取决于您创建的对象数量),并且您可以随时重写该函数。
其他回答
第一个示例仅更改该对象的接口。第二个示例更改该类的所有对象的接口。
我知道这已经得到了答案,但我想展示一个速度差异的实际例子。
直接作用于对象:
函数ExampleFn(){this.print=函数(){console.log(“正在调用打印!”);}}var对象=[];控制台时间('x');for(设i=0;i<2000000;i++){objects.push(new ExampleFn());}console.timeEnd('x');//x: 1151.960693359375毫秒
原型上的功能:
函数ExampleFn(){}ExampleFn.prototype.print=函数(){console.log(“正在调用打印!”);}var对象=[];控制台时间('y');for(设i=0;i<2000000;i++){objects.push(new ExampleFn());}console.timeEnd('y');//x: 617.866943359375毫秒
在这里,我们使用Chrome中的打印方法创建了2000000个新对象。我们将每个对象存储在一个数组中。在原型上打印大约需要1/2的时间。
这些例子有非常不同的结果。
在研究差异之前,应注意以下几点:
构造函数的原型提供了一种通过实例的私有[[prototype]]属性在实例之间共享方法和值的方法。函数的this是通过函数的调用方式或使用bind(此处未讨论)来设置的。如果在对象上调用函数(例如myObj.method()),则方法中的函数将引用该对象。如果这不是通过调用或使用bind设置的,则默认为全局对象(浏览器中的窗口)或严格模式,保持未定义。JavaScript是一种面向对象的语言,即大多数值都是对象,包括函数。(字符串、数字和布尔值不是对象。)
以下是有问题的片段:
var A = function () {
this.x = function () {
//do something
};
};
在这种情况下,变量A被分配了一个引用函数的值。当使用A()调用该函数时,函数的this不会被调用设置,因此它默认为全局对象,表达式this.x是有效的window.x。结果是,对右侧函数表达式的引用被分配给window.x。
在以下情况下:
var A = function () { };
A.prototype.x = function () {
//do something
};
发生了非常不同的事情。在第一行中,变量A被分配给一个函数的引用。在JavaScript中,默认情况下,所有函数对象都有一个prototype属性,因此没有单独的代码来创建a.prototype对象。
在第二行中,为A.prototype.x分配了对函数的引用。如果x属性不存在,这将创建一个x属性,如果存在,则分配一个新值。因此,与第一个示例的不同之处在于,表达式中包含了对象的x属性。
另一个例子如下。这与第一个类似(也许你想问的是什么):
var A = new function () {
this.x = function () {
//do something
};
};
在本例中,在函数表达式之前添加了新运算符,以便将函数作为构造函数调用。当使用new调用时,函数的this被设置为引用一个新Object,该Object的私有[[Prototype]]属性被设置为参考构造函数的公共原型。因此,在赋值语句中,将在这个新对象上创建x属性。当作为构造函数调用时,函数默认返回其this对象,因此不需要单独返回this;陈述
要检查A是否具有x属性:
console.log(A.x) // function () {
// //do something
// };
这是一种不常见的new用法,因为引用构造函数的唯一方法是通过A.constructor
var A = function () {
this.x = function () {
//do something
};
};
var a = new A();
实现类似结果的另一种方法是使用立即调用的函数表达式:
var A = (function () {
this.x = function () {
//do something
};
}());
在本例中,A指定了调用右侧函数的返回值。在这里,由于在调用中未设置此项,因此它将引用全局对象,而此.x是有效的window.x。由于函数不返回任何内容,因此A的值将为undefined。
如果要将Javascript对象序列化为JSON或从JSON反序列化,这两种方法之间的差异也会很明显。序列化对象时,对象原型上定义的方法不会被序列化,例如,如果您只想序列化对象的数据部分,而不想序列化其方法,这会很方便:
var A = function () {
this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance));
// {"objectsOwnProperties":"are serialized"}
相关问题:
JavaScript是一种原型语言,这意味着什么?JavaScript中函数的作用域是什么?“this”关键字是如何工作的?
Sidenote:这两种方法之间可能没有任何显著的内存节省,但是使用原型共享方法和财产可能比每个拥有自己副本的实例使用更少的内存。
JavaScript不是低级语言。将原型设计或其他继承模式视为显式改变内存分配方式的一种方式可能不是很有价值。
正如其他人在第一个版本中所说的那样,使用“this”会导致类A的每个实例都有自己的函数方法“x”的独立副本。而使用“prototype”将意味着类A的每个实例将使用方法“x”的相同副本。
这里有一些代码显示了这种细微的差异:
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
this.x = function() { alert( value ); }
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };
B.prototype.updateX = function( value ) {
B.prototype.x = function() { alert( value ); }
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we have changed it for all instances
正如其他人所提到的,选择一种或另一种方法有多种原因。我的样本只是为了清楚地展示差异。
正如其他答案中所讨论的,这确实是一个性能考虑因素,因为原型中的函数与所有实例化共享,而不是为每个实例化创建的函数。
我制作了一个jsperf来展示这一点。实例化类所需的时间有着巨大的差异,尽管只有在创建许多实例时,它才真正相关。
http://jsperf.com/functions-in-constructor-vs-prototype