题目
在不改变以下代码的情况下,如何获取函数fn
中局部变量obj
中所有键值?
function fn (key) {
const obj = { a: 1, b: 2, /* other props */ }
return obj[key];
}
分析
可以看出obj会调用其某个key获取其值,而根据this上下文的原理,如果通过obj调用某个函数,那么this能够直接获取到obj对象,然后就可以通过Object.keys(this)
获取到obj的所有键值。
而题目中只是通过key去获取该属性的值,并没有调用什么函数。那么这里就应该想到通过Object.defineProperty
劫持obj的某个属性的get,然后return Object.keys(this)
,如下:
var obj = {a: 1, b: 2};
Object.defineProperty(obj, 'somekey', {
get () { return Object.keys(this) }
});
obj.somekey // ['a', 'b']
但是按照题目的要求,我们能直接劫持obj,那么这里就需要利用到原型链的原理。假定obj上没有'somekey'
,那么就会在其原型链上查找,即Object.prototype
上查找该属性。那么我们可以直接劫持Object.prototype
上的'somekey'
。
但问题就在于如何保证这个'somekey'
在obj上面不存在?— Symbol
!
解答
let key = Symbol();
Object.defineProperty(Object.prototype, key, {
get () { return Object.keys(this) }
});
fn(key); // ['a', 'b', /* other props */]
番外篇
当然还有一个骚操作—通过fn.toString
获取到函数内容的字符串,然后通过正则去匹配。