没有原型继承的 JavaScript 中的 OOP
考虑以下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();
此对象的每个实例都将具有以下公共属性:
data
get
set
delete
getLength
现在,假设我们创建了这个 keyValueStore 对象的 100 个实例。尽管get、set、delete、getLength 将对这 100 个实例中的每一个执行完全相同的操作,但每个实例都有自己的此函数副本。
带有原型继承的 JavaScript 中的 OOP
现在,想象一下,如果您只有一个 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 个实例现在都共享这四种方法,而不是每个都有自己的副本。
资源
有关此问题的基本介绍,请参见例如。 inheritance and the prototype chainMDN website。
要更深入地了解原型继承,请参阅例如。 Aadit M Shah的文章Why Prototypal Inheritance Matters和Kyle Simpson的在线书You Don't Know JS: this & Object Prototypes。