单例私有属性
咱直接来看代码:
var Person = (function() {
var _age_ = 0;
function PersonConstructor() {}
PersonConstructor.prototype.setAge = function(age) {_age_ = age;}
PersonConstructor.prototype.getAge = function() {return _age_;}
return PersonConstructor;
})();
var p1 = new Person();
var p2 = new Person();
//测试结果
console.log(p1.age); // undefined
console.log(p2.age); // undefined
console.log(p1.getAge()); // 0
console.log(p2.getAge()); // 0
p1.setAge(12); // 通过p1设置age
console.log(p1.getAge()); // 12
console.log(p2.getAge()); // 12
从结果中看,可以看出,属性age
无法通过对象名.age
进行访问,只能通过setAge()
和getAge()
进行获取,这就是实现了 私有化属性 的定义;同时也可以看出,p1
和p2
同时共享age
属性,这便是 单例 的。
非单例私有属性
这里的实现主要包括以下几项内容:
- 私有化属性
- 非单例,即每个实例拥有独立的私有化属性
- 同源,即每个示例拥有相同的构造函数和原型,并且
set
和get
方法只定义一次
虽然说起来比较复杂,但是如果换个思路的话,其实很是简单,就在上述示例中进行修改,代码如下所示:
var Person = (function() {
var _ages_ = {};
function PersonConstructor() {
this.id = new Date().getTime() + Math.floor(Math.random() * 1000); //此处只是测试使用ID,实际生产环境为了避免id重复,可以使用uuid作为唯一标识
}
PersonConstructor.prototype.setAge = function(age) {
_ages_[this.id] = age;
}
PersonConstructor.prototype.getAge = function(age) {
return _ages_[this.id] || 0;
}
return PersonConstructor;
})();
var p1 = new Person();
var p2 = new Person();
//测试结果
console.log(p1.age); // undefined
console.log(p2.age); // undefined
console.log(p1.getAge()); // 0
console.log(p2.getAge()); // 0
p1.setAge(12); // 通过p1设置age
p1.setAge(13); // 通过p2设置age
console.log(p1.getAge()); // 12
console.log(p2.getAge()); // 13
console.log(p1.__proto__ === p2.__proto__); //true
console.log(p1.constructor === p2.constructor); //true
console.log(p1.getAge === p2.getAge); //true
console.log(p1.setAge === p2.setAge); //true
实现原理:实现原理很是简单,只是将单例情况下的_age_
变为对象_ages_
,并且在每个对象创建时分配一个唯一标识id
,在对age
属性操作时,实际是对_ages_
对象中对应id
的属性进行操作,便可满足要求。
可能存在问题
在本例中使用了javascript
中 闭包 的概念,因此便会涉及到 垃圾回收机制 的问题,此处暂未做测试,若有兴趣的读者可自行进行试验,在所有实例都已销毁的情况下,对象_ages_
的存在情况。