前言
近日,看到了这样一个笔试题目,题目如下:
var o = (function () {
var obj = { a: 1, b: 2 };
return { get: function (key) { return obj[key]; } }
})();
问:如何在不改变上述代码的情况下,修改obj对象
看到这里,你脑海里是不是翁翁的呀!!!
引发的思考
- 这里的考察点有哪些
- 如何解决
考察点
这里我想到的有以下几点:
- 原型与原型链的理解
- 闭包的理解
- JS定义属性枚举的相关api
- 对valueOf的一些理解
- 对this的一些理解
对于这些考察点的理解可自行查阅资料,这里就不过多赘述了
如何解决
我们都知道,在JS中,有一个函数,对于非基本类型可以直接返回本身,它就是原型链中的valueOf函数,
关于它的理解可参考mdn文档: valueOf概念
那么第一反应可能就是直接调用o.get('valueOf');
我们先来看下,valueOf输出的是个啥,代码如下:
console.log(o.get('valueOf'));
好了,来查看下运行结果:
于是,你开开开心心的写出如下代码:
var o = (function () {
var obj = { a: 1, b: 2 };
return { get: function (key) { return obj[key]; } }
})();
var obj = o.get('valueOf')();
console.log(obj);
好了,来运行看下结果:
看,它报错了,傻眼了吧。。。
这里,它就涉及到this指向问题了, 如果你对this有深入的理解, 应该会清楚上面方案里的this它指向了globalThis
那么,怎么办!!!
好了,接下来,我来提供下我想到的答案,可能不是最合适的,如果你有更合适的方案,也可以给出你的答案
这里就不废话了,直接上代码,如下:
var o = (function () {
var obj = { a: 1, b: 2 };
return { get: function (key) { return obj[key]; } }
})();
Object.defineProperty(Object.prototype, 'getProp', {
get() {
return this;
}
});
var obj = o.get('getProp');
console.log(obj);
好了,先来看下上面代码的运行结果:
看,这里就能或获取到o里面的obj对象本身了,就可以对其进行修改了
在上面的代码中加上如下代码:
console.log('修改之前: ', obj);
obj.a = 'aaa';
obj.b = 'bbb';
console.log('修改之后: ', obj);
运行结果如下:
看,成功了!!!
思考
这个问题就是一个典型的闭包漏洞问题,那么我们在实际的开发中,你如果了解并知道这个问题,就可以轻松的避免此类问题的存在了,接下来我们来看看,如何避免:
方案一:将原型设置为null
. 通过Object.setPrototypeOf(target, value) 设置其原型对象为null
代码如下:
var o = (function () {
var obj = { a: 1, b: 2 };
Object.setPrototypeOf(obj, null); // 这里也可以直接给__proto__赋值
return { get: function (key) { return obj[key]; } }
})();
方案二: 通过判断在访问非对象本身属性时,返回undefined
. 通过target.hasOwnProperty 判别是不是访问target本身上的属性,如果不是,直接返回undefined
代码如下:
var o = (function () {
var obj = { a: 1, b: 2 };
return {
get: function (key) {
if (obj.hasOwnProperty(key)) return obj[key];
return undefined;
}
}
})();
这里或许不是最合适的方案,如果你有更好的欢迎提出,大家一起进步