JavaScript,高阶函数,闭包,怎么样? [英] JavaScript, Higher Order Functions, Closures, how come?

查看:58
本文介绍了JavaScript,高阶函数,闭包,怎么样?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



请看下面的代码:


< html>

< head>

< script>

函数add(elementId){

var container = document.getElementById(elementId);

for (var i = 0; i< 10; i ++){

var elt = document.createElement(''div'');

elt.innerHTML =" " + i;


//小心!

elt.onclick = function(){window.alert("" + i);};

container.appendChild(elt);

}

}

< / script>


< / head>


< body>

< div id = myDiv onClick = add(''myDiv' ')>

这是'我的DIV

< / div>

< / body>

< / html>


现在,当你点击它生成的DIV元素并添加10

DIV元素时。这没关系,但当你点击儿童DIV时,

警报给你10.不是你点击第一个和

你得到0和下一个一个和一个等等。


为什么匿名函数总是显示10的值?


我很惊讶这个输出!


任何想法,解释和提示?


-

Emre Sevinc


eMBA软件开发人员积极参与:

http: www.bilgi.edu.tr http://ileriseviye.org
http://www.bilgi.edu.tr http://fazlamesai.net

认知科学学生 http://cazci.com
http://www.cogsci.boun.edu.tr

解决方案

Emre Sevinc写道:

< html>
< head>
< script>
功能add(elementId){
var container = document.getElementById(elementId);
for(var i = 0;我< 10; i ++){
var elt = document.createElement(''div'');
elt.innerHTML ="" + i;

//小心!
elt.onclick = function(){window.alert("" + i);};
container.appendChild(elt );
}
}
< / script>
< / head>

< body>
< div id = myDiv onClick = add(''myDiv'')>
这是我的DIV
< / div>
< / body>
< / html>

现在,当您单击它生成的DIV元素并添加10个/或DIV元素时。这没关系,但是当你点击儿童DIV时,
警报会给你10.不是你点击第一个,而是你得到0而下一个和1等等。 />
为什么匿名函数总是显示10的值?



警报显示调用警报时i的值。 ie

当你点击div时循环已经完成并且''我'是

10.


当您从函数内的外部作用域访问变量时,它总是

作用于变量的当前值。你似乎已经预料到它会在创建函数时创建变量''的值的副本,但是它不会这样做。\\ br
不会这样做。 />

如果要在创建函数时使用该值,则需要

将该值保存在另一个变量中。一种方法是在另一个工厂函数中创建

函数:


函数new_alert(value){

return function(){window.alert(value);};

};


...

elt.onclick = new_alert(i);


这样工厂函数的参数保持不变,即使我增加了,但是你会看到你期望的值。

。 />


>>>>> " DB" == Duncan Booth< du ********** @ invalid.invalid>写道:


DB> Emre Sevinc写道:

< html> < HEAD> <脚本> function add(elementId){var container
= document.getElementById(elementId); for(var i = 0; i< 10;
[...]
为什么匿名函数总是显示10的值?



DB>警报显示当警报被调用时,我的值为b,即,当你点击div时,循环已经

DB>完成运行,''我'是10.


这仍然让我感到困惑。我正在生成一个函数 - 飞行

并将其分配给新的DIV元素的onClick属性和

这是在循环结束之前完成的。对吗?如果这是正确的,我的意思是必须取值0,1,... 9.我认为

这是关键点,让我感到困惑。什么样的订单

的执行是这个吗?


DB>当您从

DB>函数中的外部范围访问变量时,它始终作用于

DB>变量的当前值。你好像哈我希望它能复制一份

DB>创建函数时变量'的值,但它不会是
DB>那样做。


是的,你是对的。我期望它用我提供的

值构建一个函数= 0,1,...,9(我不明白

为什么它没有't)。


DB>如果你想使用该函数时的值

DB>创建后,您必须将该值保存在另一个变量中。一个

DB>这样做的方法是在另一个内部创建函数

DB>工厂功能:


DB> function new_alert(value){return function()

DB> {window.alert(值);}; };


DB> ... elt.onclick = new_alert(i);


DB>这样,工厂功能的参数仍然是

DB>即使我增加了,所以你看到了价值

DB>你期待的。


是的,它现在有效,但我仍然对这种情况感到困惑

(我的想法是在Lisp和JavaScript之间摇摆! :))


非常感谢您的解释。

-

Emre Sevinc

eMBA软件开发人员积极参与:

http: www.bilgi.edu.tr http://ileriseviye.org
http://www.bilgi.edu.tr http://fazlamesai.net

认知科学学生 http://cazci.com
http://www.cogsci.boun.edu.tr





Emre Sevinc写道:

function add(elementId){
var container = document.getElementById(elementId);
for( var i = 0;我< 10; i ++){
var elt = document.createElement(''div'');
elt.innerHTML ="" + i;

//小心!
elt.onclick = function(){window.alert("" + i);};
container.appendChild(elt );
}
}
现在,当你点击它生成的DIV元素并添加10个DIV元素时。这没关系,但是当你点击儿童DIV时,
警报会给你10.不是你点击第一个,而是你得到0而下一个和1等等。 />
为什么那个匿名函数总是显示10的值?




你的主题确定原因,闭包。 (没有更高的命令

函数(函数将函数作为参数)但是,不确定

为什么你的主题也为它们命名)。


至于闭包,那些你定义为onclick

事件处理程序的任何函数都是函数add的内部函数,其中声明了

变量i。当调用并执行add时,该变量i

从0增加到10,最后一个值是

中可用的那些内部函数的闭包,因为它们是添加

调用完成后执行。如果你在添加调用期间执行了一个onclick处理程序

那么当然i的当前值是访问的内容,例如


function add(){

var container = document.body;

for(var i = 0; i< 10; i ++){

var elt = document.createElement (''div'');

elt.appendChild(document.createTextNode(i));

elt.onclick = function(){window.alert(" " + i);};

container.appendChild(elt);

if(i == 5){

elt.onclick ();

}

}

}

add();


我可以在执行

add期间通过这些内部函数更改并在添加完成后更改:


function add(){

var container = document.body;

for(var i = 0; i< 10; i ++){

var elt = document .createElement(''div'');

elt.appendChild(document.createTextNode(i));

elt.onclick = function() {alert(++ i); };

container.appendChild(elt);

if(i == 5){

elt.onclick();

}

}

}

add();



查看有关闭包的常见问题解答说明:

< http://www.jibbering.com/faq/faq_notes/closures.html>


如果你想拥有一个onclick处理程序,它在创建事件处理程序时使用我拥有的i值
然后构建一个函数

with new Function eg

elt.onclick = new Function(evt,alert(" + i +);");

是单向的。

-


Martin Honnen
http://JavaScript.FAQTs.com/



Take a look at the following snippet:

<html>
<head>
<script>
function add(elementId) {
var container = document.getElementById(elementId);
for (var i = 0; i < 10; i++) {
var elt = document.createElement(''div'');
elt.innerHTML = "" + i;

// Beware!
elt.onclick = function () {window.alert("" + i);};
container.appendChild(elt);
}
}
</script>

</head>

<body>
<div id=myDiv onClick=add(''myDiv'')>
Here''s my DIV
</div>
</body>
</html>

Now, when you click on the DIV element it produces and adds 10
DIV elements. That''s okay but when you click on the child DIVs,
alert gives you 10. Not that you click on the first one and
you get 0 and the next one and 1, etc.

Why does that anonymous function always show the value of 10?

I''m very surprised at this output!

Any ideas, explanations, tips?

--
Emre Sevinc

eMBA Software Developer Actively engaged in:
http:www.bilgi.edu.tr http://ileriseviye.org
http://www.bilgi.edu.tr http://fazlamesai.net
Cognitive Science Student http://cazci.com
http://www.cogsci.boun.edu.tr

解决方案

Emre Sevinc wrote:

<html>
<head>
<script>
function add(elementId) {
var container = document.getElementById(elementId);
for (var i = 0; i < 10; i++) {
var elt = document.createElement(''div'');
elt.innerHTML = "" + i;

// Beware!
elt.onclick = function () {window.alert("" + i);};
container.appendChild(elt);
}
}
</script>

</head>

<body>
<div id=myDiv onClick=add(''myDiv'')>
Here''s my DIV
</div>
</body>
</html>

Now, when you click on the DIV element it produces and adds 10
DIV elements. That''s okay but when you click on the child DIVs,
alert gives you 10. Not that you click on the first one and
you get 0 and the next one and 1, etc.

Why does that anonymous function always show the value of 10?


The alert shows you the value of ''i'' at the time when alert is called. i.e.
by the time you click on the div the loop has finished running and ''i'' is
10.

When you access a variable from an outer scope inside a function it always
acts on the current value of the variable. You seem to have expected it to
make a copy of the variable''s value when the function was created, but it
won''t do that.

If you want to use the value at the time the function is created you have
to save that value in another variable. One way to do this is to create the
function inside another factory function:

function new_alert(value) {
return function () {window.alert(value);};
};

...
elt.onclick = new_alert(i);

This way the parameter of the factory function remains unchanged even
though i is incremented so you see the value you expected.


>>>>> "DB" == Duncan Booth <du**********@invalid.invalid> writes:

DB> Emre Sevinc wrote:

<html> <head> <script> function add(elementId) { var container
= document.getElementById(elementId); for (var i = 0; i < 10;
[...]
Why does that anonymous function always show the value of 10?


DB> The alert shows you the value of ''i'' at the time when alert is
DB> called. i.e. by the time you click on the div the loop has
DB> finished running and ''i'' is 10.

That''s what still confuses me. I''m generating a function on-the-fly
and assigning it to a new DIV element''s onClick attribute and
this is done before the loop ends. Right? If that is right, I mean
that generated functions must be taking values 0, 1, ... 9. I think
this is the crucial point and which confuses me. What kind of an order
of execution is this?

DB> When you access a variable from an outer scope inside a
DB> function it always acts on the current value of the
DB> variable. You seem to have expected it to make a copy of the
DB> variable''s value when the function was created, but it won''t
DB> do that.

Yes, you''re right. I expected it to build a function with the
values I have provided = 0, 1, ..., 9 (and I don''t understand
why it didn''t).

DB> If you want to use the value at the time the function is
DB> created you have to save that value in another variable. One
DB> way to do this is to create the function inside another
DB> factory function:

DB> function new_alert(value) { return function ()
DB> {window.alert(value);}; };

DB> ... elt.onclick = new_alert(i);

DB> This way the parameter of the factory function remains
DB> unchanged even though i is incremented so you see the value
DB> you expected.

Yes, it works now, but I''m still somehow baffled at this situation
(my mind is swinging between Lisp and JavaScript! :))

Thank you very much for the explanations.
--
Emre Sevinc

eMBA Software Developer Actively engaged in:
http:www.bilgi.edu.tr http://ileriseviye.org
http://www.bilgi.edu.tr http://fazlamesai.net
Cognitive Science Student http://cazci.com
http://www.cogsci.boun.edu.tr




Emre Sevinc wrote:

function add(elementId) {
var container = document.getElementById(elementId);
for (var i = 0; i < 10; i++) {
var elt = document.createElement(''div'');
elt.innerHTML = "" + i;

// Beware!
elt.onclick = function () {window.alert("" + i);};
container.appendChild(elt);
}
} Now, when you click on the DIV element it produces and adds 10
DIV elements. That''s okay but when you click on the child DIVs,
alert gives you 10. Not that you click on the first one and
you get 0 and the next one and 1, etc.

Why does that anonymous function always show the value of 10?



Well your subject names the reason, closures. (There are no higher order
functions (functions taking functions as arguments) however, not sure
why your subject names them too).

As for the closure, those anynymous functions you defined as the onclick
event handler are inner functions of the function add in which the
variable i is declared. When add is called and executed, that variable i
is incremented from 0 to 10 and the last value is what is available in
the closure to those inner functions as they are executed after the add
call is finished. If you executed an onclick handler during the add call
then of course the current value of i is what is accessed e.g.

function add() {
var container = document.body;
for (var i = 0; i < 10; i++) {
var elt = document.createElement(''div'');
elt.appendChild(document.createTextNode(i));
elt.onclick = function () {window.alert("" + i);};
container.appendChild(elt);
if (i == 5) {
elt.onclick();
}
}
}
add();

And i can be changed by those inner functions during the execution of
add and after add has been finished:

function add() {
var container = document.body;
for (var i = 0; i < 10; i++) {
var elt = document.createElement(''div'');
elt.appendChild(document.createTextNode(i));
elt.onclick = function () { alert(++i); };
container.appendChild(elt);
if (i == 5) {
elt.onclick();
}
}
}
add();


Check the FAQ notes on closures:
<http://www.jibbering.com/faq/faq_notes/closures.html>

If you want to have an onclick handler that uses the i value that i has
during the creation of the event handler then a function constructed
with new Function e.g.
elt.onclick = new Function("evt", "alert(" + i + ");");
is one way.
--

Martin Honnen
http://JavaScript.FAQTs.com/


这篇关于JavaScript,高阶函数,闭包,怎么样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆