我不太喜欢动态编程语言,但我已经编写了相当多的JavaScript代码。我从未真正了解过这种基于原型的编程,有人知道它是如何工作的吗?
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
我记得前一段时间我和人们进行了很多讨论(我不太确定我在做什么),但据我所知,没有什么课的概念。它只是一个对象,这些对象的实例是原始对象的克隆,对吗?
但JavaScript中这个“.prototype”属性的确切用途是什么?它与实例化对象有什么关系?
更新:正确方式
var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!
function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK
这些幻灯片也帮了大忙。
考虑以下keyValueStore对象:
var keyValueStore = (function() {
var count = 0;
var kvs = function() {
count++;
this.data = {};
this.get = function(key) { return this.data[key]; };
this.set = function(key, value) { this.data[key] = value; };
this.delete = function(key) { delete this.data[key]; };
this.getLength = function() {
var l = 0;
for (p in this.data) l++;
return l;
}
};
return { // Singleton public properties
'create' : function() { return new kvs(); },
'count' : function() { return count; }
};
})();
我可以通过执行以下操作创建此对象的新实例:
kvs = keyValueStore.create();
此对象的每个实例都将具有以下公共财产:
数据收到设置删去获取长度
现在,假设我们创建了这个keyValueStore对象的100个实例。尽管get、set、delete、getLength将对这100个实例中的每一个执行完全相同的操作,但每个实例都有自己的函数副本。
现在,想象一下,如果您只有一个get、set、delete和getLength副本,并且每个实例都引用相同的函数。这将更好地提高性能,并且需要更少的内存。
原型就是这样产生的。原型是财产的“蓝图”,它是继承而不是被实例复制的。因此,这意味着对于一个对象的所有实例,它只在内存中存在一次,并且由所有这些实例共享。
现在,再次考虑keyValueStore对象。我可以这样重写:
var keyValueStore = (function() {
var count = 0;
var kvs = function() {
count++;
this.data = {};
};
kvs.prototype = {
'get' : function(key) { return this.data[key]; },
'set' : function(key, value) { this.data[key] = value; },
'delete' : function(key) { delete this.data[key]; },
'getLength' : function() {
var l = 0;
for (p in this.data) l++;
return l;
}
};
return {
'create' : function() { return new kvs(); },
'count' : function() { return count; }
};
})();
这与keyValueStore对象的上一版本完全相同,只是它的所有方法现在都放在一个原型中。这意味着,所有100个实例现在都共享这四个方法,而不是每个实例都有自己的副本。
我总是喜欢用类比来理解这类事情在我看来,原型继承与类低音继承相比非常令人困惑,尽管原型是更简单的范例。事实上,对于原型来说,确实没有继承,因此名称本身就具有误导性,更像是一种“委托”。
想象一下。。。。
你在上高中,你在课堂上,有一个今天到期的测验,但你没有笔来填写你的答案。多!
你坐在你的朋友芬尼乌斯旁边,他可能有一支笔。你问,他环顾了一下他的桌子,但没有成功,但他不是说“我没有笔”,而是一个很好的朋友,他会和他的另一个朋友Derp检查是否有笔。德普确实有一支备用笔,并将其交给芬尼乌斯,后者将其交由你完成测验。德普已将笔交给芬尼乌斯,后者已将笔委托给你使用。
这里重要的是,德普不会把笔交给你,因为你和他没有直接关系。
这是原型如何工作的一个简化示例,其中搜索数据树以查找您要查找的对象。
如果您想从基础上理解原型和基于原型的继承的概念,请查看MDN官方文档,它们解释得很好。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
谈到继承,JavaScript只有一个构造:物体。每个对象都有一个私有属性,该属性包含指向另一个对象称为原型。该原型对象具有原型,依此类推,直到使用null到达对象作为其原型。根据定义,null没有原型,并且充当原型链中的最后一个环节。
此外,这里还有另一个很好的资源,可以使用简单的示例进行解释https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes