“修改默认操作”
面试题:
对于对象o有N个属性,不修改下面代码,编写一段程序获取到对象o的所有属性。1
2
3
4
5
6
7
8
9
10var foo = (function(){
var o = {
a: 1,
b: 2,
/**更多属性**/
};
return function(key) {
return o[key];
}
})();
对象o只是函数作用域中的一个局部变量,而对外提供的唯一接口foo(key)可以获取到对象o单独的某个key对应的value,如:foo(‘a’)返回1。但是这里要求获取一个未知属性个数对象o的所有属性。
在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter是一个隐藏函数,会在获取属性值时调用。setter也是一个隐藏函数,会在设置属性值时调用。
1 | var test = { |
答题提示:添加一个属性,并且借助修改其默认get方法暴露this (闭包应用)
答案:1
2
3
4
5
6
7
8Object.defineProperty(Object.prototype, 'self', {
get() {
return this;
}
});
var o = foo('self');
console.log(Object.keys(o)); // ['a', 'b']
评论:因为o上的属性有若干个,你不确定o上是否存在属性名为self的的属性,如果存在,你就获取不到原型上的self了,所以最好使用Symbol。
改进:
1
2
3
4
5
6
7
8
9 var key = Symbol();
Object.defineProperty(Object.prototype, key, {
get() {
return this;
}
});
var o = foo(key);
console.log(Object.keys(o)); // ['a', 'b']触发其他操作
搞一个方块,移动10像素
1
2
3
4
5
6 var box =document.createElement("div");
box.setAttribute("id","box");
box.setAttribute("style","width:30px;height:30px;background:red;");
var transformText = 'translateX(' + 10 + 'px)';
box.style.transform = transformText;
封装让方块移动的操作 当然可以这样
1
2
3 function moveBox(distance){
box.style.transform = 'translateX(' + distance + 'px)';
}
其实也可以这样
1
2
3
4
5
6
7
8
9 Object.defineProperty(box, 'move', {
set: function(value) {
var transformText = 'translateX(' + value + 'px)';
box.style.webkitTransform = transformText;
box.style.transform = transformText;
}
})
//调用
box.move = 100;熔断逻辑
Express.js 版本弃用一些旧版本的中间件,为了让用户能够更好地发现,有下面这段代码,通过修改get属性方法,让用户调用废弃属性时抛错并带上自定义的错误信息。
1
2
3
4
5
6
7
8
9
10
11
12
13 [
'json',
'urlencoded',
'bodyParser',
/* 此处省略很多包名 **/
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});
参考原文:关于Object的getter和setter 不会Object.defineProperty你就out了