84669 person learning
152542 person learning
20005 person learning
5487 person learning
7821 person learning
359900 person learning
3350 person learning
180660 person learning
48569 person learning
18603 person learning
40936 person learning
1549 person learning
1183 person learning
32909 person learning
第一次调用函数时候第四行window.onload=func是调用了preparePlaceholde这个函数我明白 。但是第二次调用函数时候第二行的window.onload还等于 preparePlaceholde 并且给了oldonload这是怎么回事?window.onload为什么存下了上一次调用时候的值。
这是我自己试着弄得,最后结果是undefine.拜托知道的帮我解释一下
光阴似箭催人老,日月如移越少年。
function addLoadEvent(func){ var oldonload=window.onload;//[1] if(typeof window.onload!='function'){//[2] window.onload=func; }else { window.onload=function(){ //[3] oldonload(); func(); } } }
[1]保留原始的全局onload属性对应的值,不管是普通对象还是函数对象[2]判断原onload属性对象是否是函数对象,如果不是函数对象,那么将传入的函数对象func赋值给onload属性[3]如果是函数对象,那么新建一个匿名函数,这个函数对象将调用原来onload对应的函数队形及传入的函数对象;接下来函数就返回在[3]中声明匿名函数将会创建一个闭包作用域出来,在这个函数闭包作用域中将绑定addLoadEvent函数中定义的oldonload变量和func变量。注意闭包作用域在函数声明-词法分析阶段就存在的,和函数是否调用无关
接下来看调用的过程,为了描述的清楚,多调用了一次
addLoadEvent(preparePlacehoder);//[4] addLoadEvent(prepareGallery);//[5] addLoadEvent(showUsrProfile);//[6]
第1种情况:window.onload不为函数对象[4] addLoadEvent第1次调用过后,window.onload将绑定preparePlacehoder函数对象[5] 当addLoadEvent第2次执行时,保留window.onload老的值,赋值给oldonload,此时的值为[4]调用时传入的preparePlacehoder函数对象;流程走到[3],window.onload被重新赋值,新建一个匿名函数对象(给个名字anonFun_A),这个函数对象将形成一个闭包作用域(也给个名字闭包A),在这个闭包作用域下oldonload(oldonload_A)变量和func变量(func_A)将被引用,它们指向的函数对象在函数返回后被保留为不会被销毁掉;[6] 当addLoadEvent第3次执行时,过程和[5]相同,不同的是,此时创建的匿名函数对象是新的(给个名字anonFun_B),形成的闭包作用域也是个新的(给个名字闭包B),oldonload变量(oldonload_B)和func变量(func_B)也是新的,在闭包B下被引用
那么经过3次掉调用后。有以下的对应关系:
window.onload-》anonFun_B anonFun_B 调用 oldonload_B 和 func_B 在闭包B作用域下 oldonload_B-》anonFun_A anonFun_A 调用 oldonload_A 和 func_A 在闭包A作用域下 oldonload_A-》preparePlacehoder func_A-》prepareGallery func_B-》showUsrProfile
在onload指向的函数对象anonFun_B被执行后,之前按顺序加入的函数对象都将被依次调用。这一切的功劳都要归结于闭包-其在函数声明定义的时候形成一个和函数对象本身关联在一个的作用域,将在本身函数体内需要引用,但不在本身函数体内声明的,在外层函数体内能找到的变量的变量放在这个作用域下,进而在函数被调用的时候能够使用这些变量
这一切的功劳都要归结于闭包-其在函数声明定义的时候形成一个和函数对象本身关联在一个的作用域,将在本身函数体内需要引用,但不在本身函数体内声明的,在外层函数体内能找到的变量的变量放在这个作用域下,进而在函数被调用的时候能够使用这些变量
第2种情况:window.onload为函数对象基本流程相同,只是会多建一个匿名函数,多一个闭包作用域
我们看个简单的例子吧:
var p={ onload:function(){ console.log("0"); } }; function addLoadEvent(func){ var oldonload=p.onload;//[1] if(typeof p.onload!='function'){//[2] p.onload=func; }else { p.onload=function(){ //[3] oldonload(); func(); } } } addLoadEvent(function(){ console.log("1"); }); addLoadEvent(function(){ console.log("2"); }); addLoadEvent(function(){ console.log("3"); }); p.onload();
运行的结果输出为:0123
而下面的代码和上面的代码完全不同,没有可比性,因为不涉及到任何闭包
function addLoadEvent(a){ var p1=p3; var p2=a; var p3; if(p2==1){ p3=a; }else{ console.log(p1); } } addLoadEvent('1'); addLoadEvent('2');
建议群主直接贴代码。这样比截图方便多了,能帮你很快分析出问题。
[1]保留原始的全局onload属性对应的值,不管是普通对象还是函数对象
[2]判断原onload属性对象是否是函数对象,如果不是函数对象,那么将传入的函数对象func赋值给onload属性
[3]如果是函数对象,那么新建一个匿名函数,这个函数对象将调用原来onload对应的函数队形及传入的函数对象;
接下来函数就返回
在[3]中声明匿名函数将会创建一个闭包作用域出来,在这个函数闭包作用域中将绑定addLoadEvent函数中定义的
oldonload变量和func变量。注意闭包作用域在函数声明-词法分析阶段就存在的,和函数是否调用无关
接下来看调用的过程,为了描述的清楚,多调用了一次
第1种情况:window.onload不为函数对象
[4] addLoadEvent第1次调用过后,window.onload将绑定preparePlacehoder函数对象
[5] 当addLoadEvent第2次执行时,保留window.onload老的值,赋值给oldonload,此时的值为[4]调用时传入的preparePlacehoder函数对象;
流程走到[3],window.onload被重新赋值,新建一个匿名函数对象(给个名字anonFun_A),这个函数对象将形成一个闭包作用域(也给个名字闭包A),在这个闭包作用域下oldonload(oldonload_A)变量和func变量(func_A)将被引用,它们指向的函数对象在函数返回后被保留为不会被销毁掉;
[6] 当addLoadEvent第3次执行时,过程和[5]相同,不同的是,此时创建的匿名函数对象是新的(给个名字anonFun_B),形成的闭包作用域也是个新的(给个名字闭包B),oldonload变量(oldonload_B)和func变量(func_B)也是新的,在闭包B下被引用
那么经过3次掉调用后。
有以下的对应关系:
在onload指向的函数对象anonFun_B被执行后,之前按顺序加入的函数对象都将被依次调用。
这一切的功劳都要归结于闭包-其在函数声明定义的时候形成一个和函数对象本身关联在一个的作用域,将在本身函数体内需要引用,但不在本身函数体内声明的,在外层函数体内能找到的变量的变量放在这个作用域下,进而在函数被调用的时候能够使用这些变量
第2种情况:window.onload为函数对象
基本流程相同,只是会多建一个匿名函数,多一个闭包作用域
我们看个简单的例子吧:
运行的结果输出为:
0
1
2
3
而下面的代码和上面的代码完全不同,没有可比性,因为不涉及到任何闭包
建议群主直接贴代码。这样比截图方便多了,能帮你很快分析出问题。