我真的不知道 javascript 闭包
I don't really know javascript closure
这里是 plunker.
function factory() {
var yscale = function() {
console.log("original");
};
var status = {
yscale: yscale
};
function render() {
yscale = function() {
console.log("I am a scale");
};
}
render.__privateStatus = {
yscale: yscale
};
render.__privateStatus2 = status;
render.__privateStatusGetter = function() {
return status;
};
render.__privateStatusGetter2 = function() {
return yscale;
};
return render;
}
var chart = factory();
chart();
console.log(chart.__privateStatus.yscale); // "original"
console.log(chart.__privateStatus2.yscale); // "original"
console.log(chart.__privateStatusGetter().yscale); // "original"
console.log(chart.__privateStatusGetter2()); // "I am a scale"
我在闭包中 returned 一个函数,如果在闭包函数中发生一些初始化,阻止新值显示为 returned 函数状态的原因是什么?
谁能帮忙从语言本身解释一下?
更新
根据@RobG 的回答,我认为这个问题可以用
来简化
- 函数是原始类型吗?
- 函数和对象有什么区别?。
你可能注意到yscale是一个函数(在调用chart()之前它是未定义的,即使用一个函数初始化yscale,结果也是一样的)。如果函数是原始类型,我们就不能给它附加属性。如果函数是一个对象,我们可以使用引用传递来改变它的状态。
我知道我的第二个问题有点天真。如果你定义一个函数并让一个变量指向它,你不能通过将它分配给另一个函数来简单地改变它的内部状态。但是想一想我的第一个问题——我们可以通过附加方法来改变函数(或函数指针)的状态,比如 render.__privateMethods 来改变它的行为。
每个人都知道我们可以使用模块模式来使用对象 return 模块的 API。 Mike Bostock 表明 here 我们可以使用函数来实现与对象类似的功能,甚至更多,我们可以拥有类似构造函数的东西。我以为我非常了解功能和对象。但是随着一些胡思乱想,我感到困惑。
这就是我从 javascript 语言中寻找答案的原因,而不是从本能中寻找结果。
我猜你对以下 returns undefined:
感到惊讶
console.log(chart.__privateStatus.yscale);
那是因为当下面一行被执行时:
render.__privateStatus = {
yscale: yscale
}
yscale 变量的值是 undefined,所以这就是被分配的值。稍后更改变量的值无效。请注意,在 javascript 中,分配原始值会分配实际值,分配对象会分配对象的引用。因此,当 __privateStatus
被传递给对象的引用时, yscale 属性 被分配实际值 undefined.
同理:
console.log(chart.__privateStatus2.yscale);
returns 未定义,因为有:
var yscale;
var status = {
yscale: yscale // yscale is undefined when this assignment is made
};
所以status.yscale未定义,以后:
render.__privateStatus2 = status;
分配了对同一对象的引用。稍后更改 yscale 的值没有任何效果,其先前的值已被赋值。
同样适用于:
console.log(chart.__privateStatusGetter().yscale); // undefined
获取yscale的当前值,将函数改为:
render.__privateStatusGetter = function() {
return yscale; // use closure to variable to get current value
}
然后:
console.log(chart.__privateStatusGetter());
这里是 plunker.
function factory() {
var yscale = function() {
console.log("original");
};
var status = {
yscale: yscale
};
function render() {
yscale = function() {
console.log("I am a scale");
};
}
render.__privateStatus = {
yscale: yscale
};
render.__privateStatus2 = status;
render.__privateStatusGetter = function() {
return status;
};
render.__privateStatusGetter2 = function() {
return yscale;
};
return render;
}
var chart = factory();
chart();
console.log(chart.__privateStatus.yscale); // "original"
console.log(chart.__privateStatus2.yscale); // "original"
console.log(chart.__privateStatusGetter().yscale); // "original"
console.log(chart.__privateStatusGetter2()); // "I am a scale"
我在闭包中 returned 一个函数,如果在闭包函数中发生一些初始化,阻止新值显示为 returned 函数状态的原因是什么?
谁能帮忙从语言本身解释一下?
更新
根据@RobG 的回答,我认为这个问题可以用
来简化- 函数是原始类型吗?
- 函数和对象有什么区别?。
你可能注意到yscale是一个函数(在调用chart()之前它是未定义的,即使用一个函数初始化yscale,结果也是一样的)。如果函数是原始类型,我们就不能给它附加属性。如果函数是一个对象,我们可以使用引用传递来改变它的状态。
我知道我的第二个问题有点天真。如果你定义一个函数并让一个变量指向它,你不能通过将它分配给另一个函数来简单地改变它的内部状态。但是想一想我的第一个问题——我们可以通过附加方法来改变函数(或函数指针)的状态,比如 render.__privateMethods 来改变它的行为。
每个人都知道我们可以使用模块模式来使用对象 return 模块的 API。 Mike Bostock 表明 here 我们可以使用函数来实现与对象类似的功能,甚至更多,我们可以拥有类似构造函数的东西。我以为我非常了解功能和对象。但是随着一些胡思乱想,我感到困惑。
这就是我从 javascript 语言中寻找答案的原因,而不是从本能中寻找结果。
我猜你对以下 returns undefined:
感到惊讶console.log(chart.__privateStatus.yscale);
那是因为当下面一行被执行时:
render.__privateStatus = {
yscale: yscale
}
yscale 变量的值是 undefined,所以这就是被分配的值。稍后更改变量的值无效。请注意,在 javascript 中,分配原始值会分配实际值,分配对象会分配对象的引用。因此,当 __privateStatus
被传递给对象的引用时, yscale 属性 被分配实际值 undefined.
同理:
console.log(chart.__privateStatus2.yscale);
returns 未定义,因为有:
var yscale;
var status = {
yscale: yscale // yscale is undefined when this assignment is made
};
所以status.yscale未定义,以后:
render.__privateStatus2 = status;
分配了对同一对象的引用。稍后更改 yscale 的值没有任何效果,其先前的值已被赋值。
同样适用于:
console.log(chart.__privateStatusGetter().yscale); // undefined
获取yscale的当前值,将函数改为:
render.__privateStatusGetter = function() {
return yscale; // use closure to variable to get current value
}
然后:
console.log(chart.__privateStatusGetter());