这段错误的代码,书里说问题在于,“事件处理器函数(我理解是function(e))绑定了变量i,而不是函数在构造时的变量i的值”,此句话,我完全没看明白,在我眼里,i只有一个...真说多余的话,(e)里面的e是多余的到是真的,还有就是函数结尾少了个()去自执行,求高人讲解一下,谢谢。var add_the_handlers = function (nodes){
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = function (e) {
alert(i);
}
}
};
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = function (e) {
alert(i);
}
}
};
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = function (e) {
alert(i);
}
}
};
正常情况下只会弹出nodes.length,事实上用不同浏览器弹出的会不同,以前测试的,忘记了是啥了,总之都是在nodes.length跟nodes.length之间。
其实上面的方法弹出来的是变量i,而i变量在for执行完的时候已经是nodes.length(当然浏览器内部的for执行不同造成了我上面说的偏差。)
可以选择闭包方式解决。
var add_the_handlers = function (nodes){
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = (function (n) {
return function(e){
alert(n);
}
})(i)
}
};
这个时候就造成了一个闭包,click绑定的事件句柄在执行的时候,他的执行环境就是那个只执行一次的匿名函数,而这个匿名函数的环境中有个变量n是分别是每次for循环执行的时候赋值的。
- -# 语言表达有问题,貌似我自己都没听懂。
不知道楼主能理解不?
<script>
var aa = (function(n){
return function(){
alert(n);
}
})(456464564);
document.getElementById('a').onclick = aa;
</script>javascript函数 执行的时候会有一个执行环境,函数可以访问该环境下,父函数(父对象?不知道该咋称呼)的变量。
就是儿子可以访问他爹的变量,但是他爹没法用他儿子的媳妇儿(私有变量)。
正如上例,n只是那个闭包函数内部的变量,但是抛出了一个function,他是匿名函数内部的(就是儿子),他能弹出他爹的变量。
所以就导致在别的地方,只要用了他儿子,就能知道他爹的一切。
更多的闭包的知识,楼主还是看下相关文档吧。
好吧,你说里面子菜单是ajax请求的。但是现在的菜单都一样的
我现在正是刚接触闭包理论,有一些看不明白,所以上来问。
var g = (function(aa){
return aa;
})(15646)这个时候,g获得的是aa的值,也就是15646;var g = (function(aa){
return function(){}
})(15646)这个时候,g获得的是一个function,只不过里面什么也没有var g = (function(aa){
return function(){
alert(aa)
}
})(15646)这个时候g获得的是一个function,并且他能弹出父亲的aa来,并且,父亲已经执行了,也就是说父亲内部已经定下来了,他的aa就是传进去的15646
而当吧这个放到for里面的时候,function (){}就代表定义一个新函数,所以,每一次for的时候父亲是通过function(){}重新定义的匿名函数,而且父亲都会当场执行,执行的结果是把当时的i的值作为自己的东西保存起来,并且把儿子扔出去(return)。
而儿子被赋给了
xx.onclick
所以在被点击的时候,儿子出卖了当时父亲保存的值。
return function(e){
alert(n);
}
(function(z){ })(i)//请注意这里,后面的括号代表运行前面的函数,括号里是传进去的值.z是形参、i是实参。
}
return function(e){
alert(n);
}
})(i)
在事件处理函数里,标准浏览器会将事件对象event作为第一个参数传进去(ie除外,BS微软)。
我们将这个function赋给onclick了,它的第一个参数就应该是event,
i只是他爹的参数。
参数可以看做是函数的私有变量。
也就是i是他爹的私有变量,他只是拿他爹的i。
儿子拿老子的,天经地义。
nodes[i].onclick = (function (n) {
function fn(e){
alert(n);
}
return fn;
})(i)这样写明白吗?
e跟i没关系,只是儿子函数fn的参数。
而弹出去的n是他爹的私有变量,这个私有变量就是他爹执行的时候获得的i。
nodes[i].onclick = (function (n) {
function fn(e){
alert(e);
}
return fn;
})(i)
fn(e){alert(e)}
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = function (e) {
alert(i);
}
}
};
这段代码其实是没有问题的,定义了一个增加事件响应函数而已,参数是节点数组,这样调用:
add_the_handlers([node1,ndoe2]);
这样就会给传入的2个节点增加一个事件响应函数,书里的原话都没错,是LZ理解错了!
之所以最终返回的i值都是nodes.length,这个涉及到了闭包的概念了,子函数引用到了父函数的变量i,因此在父函数作用结束后,其中的i变量不会被删除,依然存在于内存中,而每个node的事件函数引用的i都是指向同一个内存区域的,所以最终的值都会一样!
那比如说把alert(e)改成alert(n)的话,那是不是这个就对了?我现在怀疑是不是书上印错了...
nodes[i].onclick = (function (n) {
function fn(e){
alert(n);
}
return fn;
})(i)
改成alert(n)的话,这个n就是参数i的副本,不是i的引用了,所以能够按照顺序的弹出数字,而不是像alert(i)一样弹出的都是一样的值
这是书上的源码,也就是说如果按照书上的源码看,实际上i根本就没有被用到,如果是想在onclick的时候,弹出当前节点的序号的话,应该改成后alert(i),这个i必须与外层函数的形参一样,对吗?
书上源码:var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(e);
};
}(i);
}
}
我怀疑书上印错了,实现弹出序号的功能的话,应该是:var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(i);//这里的i应该与function (i)的形参一致才能有效?
};
}(i);
}
}
nodes[i].onclick = (function (n) {
function fn(e){
alert(e);
}
return fn;
})(i)
注册后nodes[i].onclick = function fn(i){
alert(i);
}
这个i的值是运行环境里的i,
哦~那如果书上是对的话,我就是非常不明白这个地方,为什么里面的e就是外面的i了?我一直就困惑在这个地方,比如你说的
nodes[i].onclick = (function (n) {
function fn(e){
alert(e);
}
return fn;
})(i)自执行完后,就等于:
nodes[i].onclick = function fn(i){
alert(i);
}那这是什么原理使得e就是i了?
你把书上的代码敲一下不就知道是否正确了吗?
你alert(typeof e)
如果是object就是event对象,如果是Number就是那个i了
<div>f</div>
<div>f</div>
<div>f</div>
<div>f</div>
<div>f</div>
<script>
var a = document.getElementsByTagName("div");
for(var i = 0,j=a.length;i<j;i++){
a[i].onclick = (function(n){
return function (e){
alert(typeof e);
}
})(i);
}
</script>如果弹出来是undefined(ie下)或者object(ff下)的话,那么e就应该是event。
也就是说e跟i没有任何联系,只是n被赋予了i的值。但是!惊叹号!
请看好书上的代码 是否是这样的for(var i = 0,j=a.length;i<j;i++){
(function(n){
a[n].onclick = function(e){
alert(n);
}
})(i);
}这样也正确。
看代码需要仔细。
另外,我建议楼主看一下《JavaScript权威指南 第五版》(传说中的“犀牛书”);
那上面的解释确实不错。
alert(n);
})(i);
但是有个小小的问题,根据书上源码的话,为什么alert出来的会是[Object MouseEvent]?e这个时候是onclick事件本身?
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(e);
};
}(i);
}
}
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function () {
alert(i);
};
}(i);
}
}
这样看看结果是什么
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (i) {
alert(i);
};
}(i);
}
}
这样的话是不是又是event啊?
这个方法将返回把对象强制转换成字符串的值。
但是对于一些对象,无法将其转换成字符串,他们有自己的toString的值。
Object的就是 [Object Object]
Array的是 [Object Array]
你onclick事件会把事件对象event作为第一个参数传进去,所以那个e其实是个event事件
alert的时候,会把参数自动toString(),你那个event事件的toString就是[Object MouseEvent]
你也可以
alert(e.toString());
应该会得到相同的结果。
这个你错了,e就是e,在FF下,是事件对象event,和i扯不到半点关系,i是作为参数传给了最外层的n,此时n保留了当时i的值的副本,e完全和i扯不上关系
大哥说笑了,你还能在乎我这点分,不过我发现就是你讲的最明白,最后我肯定会加分的,虽然没太多分可以送...关于这个解释,我大致已经明白了,讲得非常透,可最后还有一个问题,为什么在这个地方会把event当做第一个参数传进去呢?这会在什么情况下发生呢?谢谢谢谢~javascript中,任何对象都有一个toString方法
这个方法将返回把对象强制转换成字符串的值。
但是对于一些对象,无法将其转换成字符串,他们有自己的toString的值。
Object的就是 [Object Object]
Array的是 [Object Array]
你onclick事件会把事件对象event作为第一个参数传进去,所以那个e其实是个event事件
alert的时候,会把参数自动toString(),你那个event事件的toString就是[Object MouseEvent]
你也可以
alert(e.toString());
应该会得到相同的结果。
w3c制定的规则,在事件触发的时候,将event对象作为第一个参数传给处理函数。
标准浏览器都支持这一规范的,比如谷歌、苹果、火狐等等吧。
只是ie觉得自己很甩牛X,不支持这一规范。