深入理解JavaScript Object.defineProperty
不修改引擎代码自定义Egret组件代码
需求描述:
开发微信小游戏,大多存在“获取昵称头像”需要用户同意授权的交互,如果用户同意则游戏中使用微信返回的头像地址,如果不同意获取头像失败,则服务器给它随机1个虚拟头像: http://cdn.xxxxxx.com/project/img/avatar/head/1.jpg(1是1-10000中随机出来的)
这是1个很长且可能变化的地址,为了更好的灵活性和减少服务器存储空间,数据库我们想只存1个id,而不是整个url图片路径,把域名文件夹路径配置在外部。
需求实现1:
通常情况下,我们会这样处理,在业务代码处针对头像地址分别分别判断:
var img:eui.Image;
var headurl = userinfo.headurl;//用户存储的头像地址(有可能是完整的微信头像地址,也有可能是服务器构造的id)
if(!isNaN(headurl)){
img.source = "http://cdn.xxxxxx.com/project/img/avatar/head/" + headurl + ".jpg";
}
else{
img.source = headurl;
}
如果很多地方都需要显示用户的头像,那么这样重复性的代码就会分布在很多地方,这不是好的代码编写习惯。
有同学就说了,可以把这个代码封装成1个方法,以供需要的地方调用
fuction setImgSource(img, headurl){
if(!isNaN(headurl)){
img.source = "http://cdn.xxxxxx.com/project/img/avatar/head/" + headurl + ".jpg";
}
else{
img.source = headurl;
}
}
setImgSource(img, userinfo.headurl);
这样在显示头像地址的地方只需要添加1行代码,的确比较简单,但是不可否认的是很容易遗漏。
这里提供另一种思路,重写Egret引擎的source方法,当然不是去修改引擎代码文件(可以但不建议),见下面需求实现2.
需求实现2:
在不修改引擎代码文件的基础上如何重写代码呢? 那就是使用 Object.defineProperty 方法
Object.defineProperty的用法是:
Object.defineProperty(person,'name',{
configurable:false, //能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true
enumerable:false, //对象属性是否可通过for-in循环,flase为不可循环,默认值为true
writable:false, //对象属性是否可修改,flase为不可修改,默认值为true
value:0 //对象属性的默认值,默认值为undefined
});
回到本题的需求,在项目启动的时候执行如下代码
let rootURL = "http://cdn.xxxxxx.com/project/img/avatar/head/";
Object.defineProperty(eui.Image.prototype, "source", {
get: function () {
return this._source;
},
set: function (value) {
if (value == this._source) {
return;
}
if(value && !isNaN(value)){ //如果是数字,表示是虚拟头像,需要构造头像路径
value = rootURL + value + ".jpg";
}
this._source = value;
if (this.$stage) {
this.parseSource();
}
else {
this.sourceChanged = true;
this.invalidateProperties();
}
},
enumerable: true,
configurable: true
});
这样就完美解决了这个需求。
扩展思考:
Object.defineProperty 能定义 enumerable属性,这个属性作用是设置对象属性是否可通过for-in循环,flase为不可循环,默认值为true
我们试试这段代码
var date = new Date();
for(var key in date){
console.log(key);
}
输出是 undefined
因此可以得出结论,JavaScript的Date对象是设置了 enumerable属性是 false,从而避免对外暴露该对象的具体方法和属性。
参考文章:https://blog.csdn.net/qq_17335153/article/details/52584727