我得到了关于函数编写的测验:
/* ====== can not modify this line below till next dividing line ========= */
function foo() {
var obj = {
x : 1,
y : 2,
bar : bar()
}
function bar() {
/* ====== can not modify this line above ================================= */
/* so how can I get obj.x and obj.y here and returns their sum ..? */
/* ====== can not modify this line below till next dividing line ========= */
}
return obj;
}
console.log( foo().bar ); // expected 3
/* ====== can not modify this line above ================================= */

我自己找到了两种方法,一种是获得foo.toString()
并做一些REGEX
魔术。
另一个是注册一个全局变量,如window.run
来控制foo()
只运行一次。
但是我想知道还有其他方法可以解决这个问题吗?
感谢您的回复〜
答案 0 :(得分:5)
你做不到。在构造对象之前调用bar
,obj
将为undefined
,之前属性(1
和2
)的已评估值位于某处仅在内存中无法访问。另请参阅Self-references in object literal declarations。
鉴于你在一个具有相当任意限制的测验中发现了这个问题,他们似乎期待一个特技答案。有几种方法:
obj.x
和obj.y
在给定代码中也是常量 覆盖 console.log
进行出价,例如
function bar() {
var log = console.log.bind(console);
console.log = function(p) {
log(p.valueOf());
};
return {
valueOf: function() {
return obj.x + obj.y;
}
};
}
由于在调用console.log
之前foo()
被取消引用,因此无法正常工作。
类似的方法适用于console.log
行为can be customized而无需覆盖任何内容的环境:
function bar() {
return {
inspect: function() {
return String(obj.x + obj.y);
}
};
}
只需自己致电foo()
即可获取值,但不要在bar
上无限递归:
function bar() {
if (foo.stop) return null;
foo.stop = true;
var res = foo().x + foo().y;
foo.stop = false;
return res;
}
答案 1 :(得分:1)
如果真的“已锁定”进行修改,请使用以下“ magic ”(针对测试用例):
function foo() {
var obj = {
x : 1,
y : 2,
bar : bar()
}
function bar() {
var magic_sum = foo.toString().match(/var obj =\s*?\{\s*?x\s*?:\s*?(\d+),\s*?y\s*?:\s*?(\d+),/)
.slice(1,3).map(Number);
return magic_sum[0] + magic_sum[1];
}
return obj;
}
console.log(foo().bar);
算法:
foo.toString()
- 获取函数文本表示
.match(/var obj =\s*?\{\s*?x\s*?:\s*?(\d+),\s*?y\s*?:\s*?(\d+),/)
- 匹配x
和y
属性值
.slice(1,3)
- 从捕获的组合中获取值(x
,y
属性)
.map(Number)
- 将每个值投射到 Number 类型
答案 2 :(得分:1)
foo.callingTime = foo.callingTime || 1;
if(foo.callingTime === 1){
foo.callingTime++;
foo.tempObj = foo();
return foo.tempObj.x+foo.tempObj.y;
}
else if(foo.callingTime === 2){
foo.callingTime = 1;
return;
}