实例详解-类(二)
//===给Object.prototype添加只读不可枚举不可配置的属性objectId
(function(){
Object.defineProperty(Object.prototype,'objectId',{
get:idGetter, //读取objectId时直接调用idGetter函数
enumerable:false,
configurable:false
});
function idGetter(){
if(!(idprop in this)) { //检测是否存在idprop
if (!Object.isExtensible(this)) {
throw Error('can not define id for nonextensible objects');
}
Object.defineProperty(this, idprop, {
value: nextid++,
writable: false,
enumerable: false,
configurable: false
});
}
return this(idprop);
}
var idprop = '|**objectid**|'; //假设这个属性没用到
var nextid = 1;
}());
//====创建一个不可变得类,它的属性,方法都是不可变得===
//===Object.defineProperty()和Object.defineProperties()可以用来创建新属性,也可以修改已有属性的特性。
// 更改或设置属性描述时,未指定的属性保持已有值,默认是false
function Range(from,to){
var props = {
from:{value:from,enumerable:true,writable:false,configurable:false},
to:{value:to,enumerable:true,writable:false,configurable:false}
};
if(this instanceof Range) Object.defineProperties(this,props);
else return Object.create(Range.prototype,props);
}
//添加不可变方法,除了value,其它都是false
Object.defineProperties(Range.prototype,{
includes:{value:function(x){return this.from<=x && x<=this.to;}},
foreach:{value:function(f){for(var x=Math.ceil(this.from);x<=this.to;x++) f(x)}}
});
//=====设置属性描述的工具函数========
function freezeProps(o){
var props = (arguments.length == 1) //如果只有一个参数
?Object.getOwnPropertyNames(o) //使用所有属性
:Array.prototype.slice.call(arguments,1); //否则传入了指定名字的属性
props.forEach(function(n){
//if(!Object.getOwnPropertyDescriptor(o,n).configurable) return; //忽略不可配置属性
Object.defineProperty(o,n,{writable:false,configurable:false});
});
return o;
}
function hideProps(o){
var props = (arguments.length == 1)
?Object.getOwnPropertyNames(o)
:Array.prototype.slice.call(arguments,1);
props.forEach(function(n){
//if(!Object.getOwnPropertyDescriptor(o,n).configurable) return;
Object.defineProperty(o,n,{enumerable:false});
});
return o;
}
//==使用以上工具函数
function Range1(from,to){
this.from = from;
this.to = to;
freezeProps(this);
}
Range1.prototype = hideProps({
constructor:Range1,
includes:function(x){return this.from<=x && x<= this.to;},
foreach:function(f){for(var x=Math.ceil(this.from);x<=this.to;x++) f(x)},
toString:function(){return '('+this.from+'...'+this.to+')'}
});
var r = new Range1(4,6);
r.from = 1;
r.to = 8;
console.log(r.from); //4 无法修改
console.log(r.to);
//==========封装对象的私有状态(构造函数的属性)======
function Range2(from,to){
function getFrom(){return from;}
function getTo(){return to;}
function setFrom(f){ from = f;}
function setTo(t){ to = t;}
Object.defineProperties(this,{
from:{get:getFrom,set:setFrom,enumerable:true,configurable:false},
to:{get:getTo,set:setTo,enumerable:true,configurable:false}
});
}
Range2.prototype = hideProps({
constructor:Range1,
includes:function(x){return this.from<=x && x<= this.to;},
foreach:function(f){for(var x=Math.ceil(this.from);x<=this.to;x++) f(x)},
toString:function(){return '('+this.from+'...'+this.to+')'}
});