在Kyle Simpson(@ kyle-simpson)高级JavaScript课程here的练习1中,其目的是扩展对范围,吊装等的理解,我发现很多事情很难遵循。
<!DOCTYPE html>
<html>
<head>
<title>Exercise 1</title>
</head>
<body>
<h1>Exercise 1</h1>
<script src="ex1.js"></script>
</body>
</html>
A();
function C() {
console.log("OOPS!");
}
function E(f) {
console.log("E");
f();
var f = F;
}
var A = function() {
console.log("A");
B();
};
var C;
function G() {
console.log("G");
H();
var H = function() {
console.log("H");
I();
};
}
var D = d;
function d() {
console.log("D");
E();
}
function I() {
console.log("I");
J();
J();
}
B = function() {
console.log("B");
C();
};
var F = function() {
console.log("F");
G();
};
var rest = "KLMNOPQRSTUVWXYZ".split("");
for (var i=0; i<rest.length; i++) {
(function(i){
// define the current function
window[rest[i]] = function() {
console.log(rest[i]);
if (i < (rest.length-1)) {
// TODO: call the next function
}
};
})(i);
}
var J = function() {
J = function() {
console.log("J");
K();
};
};
C = function() {
console.log("C");
D();
};
说明(README.md)
修复代码,使其在控制台中打印出字母A-Z。
不能:
可以/必须:
(function(global){
function C() {
console.log("OOPS!");
}
function E(f) {
console.log("E");
f();
var f = F;
}
var A = function() {
console.log("A");
B();
};
var C;
function G() {
console.log("G");
H();
function H() {
console.log("H");
I();
}
}
var D = d;
function d() {
console.log("D");
E(F);
}
function I() {
console.log("I");
J();
J();
}
B = function() {
console.log("B");
C();
};
var F = function() {
console.log("F");
G();
};
var rest = "KLMNOPQRSTUVWXYZ".split(""), fns = {};
for (var i=0; i<rest.length; i++) {
(function(i){
// define the current function
fns[rest[i]] = function() {
console.log(rest[i]);
if (i < (rest.length-1)) {
fns[rest[i+1]]();
}
};
})(i);
}
var J = function() {
J = function() {
console.log("J");
fns.K();
};
};
function C() {
console.log("C");
D();
}
return A;
})(window)();
我很好地遵循解决方案,直到I
被打印出来。
I
打印后部分代码的问题 ** 1. **在解决方案(和练习代码)中,作者对函数I
使用以下函数声明,对J
使用函数表达式。该函数以这样的方式在函数本身内更新函数引用J
的赋值以打印'J'。但是,在J
内调用I
时 - 为什么J()
需要调用两次?
var J = function() {
J = function() {
console.log("J");
K();
};
};
function I() {
console.log("I");
J();
J();
}
2. 在练习代码中,作者希望修复以下代码行以打印字母L到Z.
对于每个字母,运行匿名函数以通过字母创建函数名称(对于字母“K”到“Z”并粘贴到窗口对象 - 我不理解的部分是
1)何时调用每个字母的这些函数 - 我通过行window[rest[i+1]]();
看到调用 - 但是我们如何到达这里?
2)当创建第i个字母的函数时,我们正在调用i + 1个字母的函数(通过window[rest[i+1]]();
),这个函数可能在那时未定义 - 但代码工作并打印出字母L到ž
var rest = "KLMNOPQRSTUVWXYZ".split("");
for (var i=0; i<rest.length; i++) {
(function(i){
// define the current function
window[rest[i]] = function() {
console.log(rest[i]);
if (i < (rest.length-1)) {
// TODO: call the next function
window[rest[i+1]]();
}
};
})(i);
}
答案 0 :(得分:1)
该功能以功能参考
J
的分配在功能本身内更新,以打印J&#39;。
完全。
但是,在
J
内拨打I
时 - 为什么J()
需要被调用两次?
第一个电话 - 正如您所说 - 仅更新J
变量。第二个调用实际上将调用更新的函数,即记录&#39; J&#39;并继续K
。
何时调用每个字母的这些函数?
正如你所说,他们被称为#34;递归&#34;从这些函数内部直到i
到达终点。第一个启动链的调用位于上面的J
函数中:
fns.K();
(请注意rest[0]
是K
)
当创建第i个字母的函数时,我们调用第i + 1个字母的函数(通过
window[rest[i+1]]();
),此时可能未定义
没有。下一个函数的调用是在我们正在创建的函数内部。这些函数只是创建的,它们尚未从循环内调用 - 函数调用就是IIFE的函数调用。循环结束后,将从J
调用它们。
答案 1 :(得分:1)
然而,当从I内部调用J时 - 为什么J()需要被调用两次?
在下面给出的代码示例中:
var J = function() {
J = function() {
console.log("J");
K();
};
};
function I() {
console.log("I");
J(); // The first call refines the value of J
J(); // This now calls the inner J instead
}
在I
函数中,第一个J
调用的作用基本上是重新定义函数J
的内容。第一次调用后,J
函数将从:
function () {
J = function() { // Here inside the call is where J is being redefined
console.log("J");
K();
};
}
要:
function () {
console.log("J");
K();
}
这就是需要第二次通话的原因。请注意,对J
的所有其他函数调用都可以正常工作并打印J
并调用K()
,因此除了用于学习目的之外,它不是很实用。
什么时候调用每个字母的这些函数 - 我通过行
window[rest[i+1]]();
看到调用 - 但是我们如何到达这里?
在这种情况下,您提供的代码实际上并没有做任何事情。这只是创建函数而不是运行任何函数,因此为什么window[rest[i+1]]
将在稍后定义,条件i < (rest.length-1)
将确保没有超出范围的调用。