两者之间有什么区别
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
};
当前回答
有什么区别?=>很多。
我认为,这个版本用于实现封装,即数据隐藏。它有助于处理私有变量。
让我们看一下以下示例:
var AdultPerson = function() {
var age;
this.setAge = function(val) {
// some housekeeping
age = val >= 18 && val;
};
this.getAge = function() {
return age;
};
this.isValid = function() {
return !!age;
};
};
现在,原型结构可以应用如下:
不同的成年人有不同的年龄,但所有成年人都享有相同的权利。所以,我们使用原型而不是这个添加它。
AdultPerson.prototype.getRights = function() {
// Should be valid
return this.isValid() && ['Booze', 'Drive'];
};
现在让我们看看实现。
var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )
var p2 = new AdultPerson;
p2.setAge(45);
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***
希望这有帮助。
其他回答
举两个例子:
var A = function() { this.hey = function() { alert('from A') } };
vs.
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
这里的大多数人(尤其是排名最高的答案)试图解释他们是如何不同的,而不解释为什么。我认为这是错误的,如果你首先了解基本面,差异就会变得明显。让我们先解释一下基本原理。。。
a) 函数是JavaScript中的一个对象。JavaScript中的每个对象都有一个内部属性(也就是说,你不能像访问其他财产一样访问它,除非是在像Chrome这样的浏览器中),通常被称为__proto__(你可以在Chrome中键入anyObject.__proto__来查看它引用了什么。这只是一个属性,仅此而已。JavaScript中的一个属性=对象内的一个变量,仅此之外。变量做什么?它们指向事物。
那么这个__proto__属性指向什么?嗯,通常是另一个对象(我们稍后会解释原因)。强制__proto__属性的JavaScript不指向另一个对象的唯一方法是使用var newObj=object.create(null)。即使这样做,__proto__特性仍然作为对象的属性存在,只是它不指向其他对象,而是指向null。
以下是大多数人感到困惑的地方:
当您在JavaScript中创建一个新函数(它也是一个对象,记得吗?)时,当它被定义时,JavaScript会自动在该函数上创建一个名为prototype的新属性。试试看:
var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined
A.prototype与__proto__属性完全不同。在我们的示例中,“A”现在有两个名为“prototype”和__proto__的财产。这对人们来说是一个很大的困惑。prototype和proto___财产没有任何关联,它们是指向不同值的不同事物。
您可能会想:为什么JavaScript在每个对象上都创建__proto__属性?嗯,一个词:授权。当你在一个对象上调用一个属性,而该对象没有属性时,JavaScript会查找__proto__引用的对象,看看它是否有属性。如果没有属性,则会查看该对象的__proto__属性,依此类推……直到链结束。因此,名称原型链。当然,如果__proto__没有指向一个对象,而是指向null,那么很不幸,JavaScript会意识到这一点,并返回未定义的属性。
您可能还想知道,当您定义函数时,为什么JavaScript会为函数创建一个名为prototype的属性?因为它试图欺骗你,是的,欺骗你它像基于类的语言一样工作。
让我们继续我们的示例,从A创建一个“对象”:
var a1 = new A();
当这件事发生时,背景中发生了一些事情。a1是一个普通变量,它被分配了一个新的空对象。
在函数调用a()之前使用了运算符new,这一事实在后台做了一些额外的事情。new关键字创建了一个新对象,该对象现在引用a1,并且该对象为空。以下是另外发生的情况:
我们说过,在每个函数定义上都创建了一个名为prototype的新属性(与__proto__属性不同,您可以访问它)?好吧,那处房产现在正在使用。
现在我们有一个新烘焙的空a1对象。我们说过JavaScript中的所有对象都有一个内部__proto__属性,该属性指向某个对象(a1也有它),无论它是null还是另一个对象。新运算符的作用是将__proto__属性设置为指向函数的原型属性。再读一遍。基本上是这样的:
a1.__proto__ = A.prototype;
我们说过,A.prototype只不过是一个空对象(除非我们在定义a1之前将其更改为其他对象)。所以现在基本上a1.__proto__指向的是A.prototype指向的同一个东西,那就是那个空对象。它们都指向发生此行时创建的同一对象:
A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}
现在,在处理vara1=newA()语句时会发生另一件事。基本上执行A(),如果A是这样的:
var A = function() { this.hey = function() { alert('from A') } };
函数(){}中的所有内容都将执行。当你到达这条线时,这条线变为a1,你会得到:
a1.hey = function() { alert('from A') }
我不会解释为什么这会变为a1,但这是一个很好的答案,可以了解更多信息。
总之,当您执行var a1=new A()时,后台会发生三件事:
创建一个全新的空对象并将其分配给a1。a1={}a1.__proto__属性被指定指向与A.prototype指向相同的对象(另一个空对象{})正在执行函数A(),并将其设置为步骤1中创建的新的空对象(请阅读上面我提到的答案,了解为什么会更改为a1)
现在,让我们尝试创建另一个对象:
var a2 = new A();
将重复步骤1、2、3。你注意到什么了吗?关键词是重复。第一步:a2将是一个新的空对象,第二步:它的__proto__属性将指向a原型所指向的相同对象,最重要的是,第三步:函数a()被AGAIN执行,这意味着a2将获得包含函数的hey属性。a1和a2有两个名为hey的独立财产,它们指向两个独立函数!我们现在在相同的两个不同的对象中有重复的函数在做相同的事情,哦。。。如果我们用新的A创建了1000个对象,那么可以想象这对内存的影响,毕竟所有的函数声明都比数字2占用更多的内存。那么我们如何防止这种情况呢?
还记得为什么__proto__属性存在于每个对象上吗?因此,如果您检索a1上的yoMan属性(它不存在),将查询它的__proto__属性,如果它是一个对象(大多数情况下是),它将检查它是否包含yoMan,如果它不包含,它将查询该对象的__proto__etc.如果它包含,它会获取该属性值并将其显示给您。
所以有人决定使用这个事实+当你创建a1时,它的__proto__属性指向同一个(空)对象。prototype指向并执行以下操作:
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
凉的现在,当您创建a1时,它会再次执行上面的所有3个步骤,在步骤3中,它不会执行任何操作,因为函数A()没有什么可执行的。如果我们这样做:
a1.hey
它将看到a1不包含hey,并将检查其__proto__属性对象,看看它是否包含hey。
使用这种方法,我们从步骤3中消除了在每次创建新对象时重复函数的部分。而不是a1和a2有一个单独的hey属性,现在它们都没有。这是件好事。。。如果你了解__proto__和Function.prototype,类似这样的问题将非常明显。
注意:有些人倾向于不将内部Prototype属性称为__proto__,我在文章中使用了这个名称,以将其与Functional.Prototype属性区分开来,这是两个不同的东西。
我知道这已经得到了答案,但我想展示一个速度差异的实际例子。
直接作用于对象:
函数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的时间。
第一个示例仅更改该对象的接口。第二个示例更改该类的所有对象的接口。
在大多数情况下,它们本质上是相同的,但第二个版本节省了内存,因为只有一个函数实例,而不是每个对象都有一个单独的函数。
使用第一个表单的原因是访问“私人成员”。例如:
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
由于javascript的作用域规则,private_var可用于分配给this.x的函数,但不能在对象外部使用。
有什么区别?=>很多。
我认为,这个版本用于实现封装,即数据隐藏。它有助于处理私有变量。
让我们看一下以下示例:
var AdultPerson = function() {
var age;
this.setAge = function(val) {
// some housekeeping
age = val >= 18 && val;
};
this.getAge = function() {
return age;
};
this.isValid = function() {
return !!age;
};
};
现在,原型结构可以应用如下:
不同的成年人有不同的年龄,但所有成年人都享有相同的权利。所以,我们使用原型而不是这个添加它。
AdultPerson.prototype.getRights = function() {
// Should be valid
return this.isValid() && ['Booze', 'Drive'];
};
现在让我们看看实现。
var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )
var p2 = new AdultPerson;
p2.setAge(45);
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***
希望这有帮助。