专栏首页菩提树下的杨过由javascript中"匿名函数调用写法"引出的一些东东

由javascript中"匿名函数调用写法"引出的一些东东

匿名函数自动调用的三种写法如下:

var f1 = function(){alert("f1");}();

(function(){alert("f2");}());

void function(){alert("f3");}();

再来看一段代码:

function Person(properties){
	for(var p in properties){				
		(function(context){	
			var t = p;
			context["get" + t] = function(){return properties[t];}
			context["set" + t] = function(val){properties[t] = val;}
		}(this));
	}
}

var p = new Person({name:"菩提树下的杨过",sex:"男"});
alert(p.getname());//弹出"菩提树下的杨过"
alert(p.getsex());//弹出"男"
alert(p.name);//弹出:undefined

Person类为所有传入的对象属性,自动生成了getXXX与setXXX方法,这一段代码虽然很短,却包含了诸多js中的关键概念:

1.json对象表示法

当我们把"{name:"菩提树下的杨过",sex:"男"}"做为参数,传入Person构造函数时,实际上就建立了一个字典结构的键值对:

name --> "菩提树下的杨过" sex --> "男"

即  name - value 结构,所以也就能用for ...in语句来遍历了

以上结论,可以这样测试

var obj = {name:"菩提树下的杨过",sex:"男"};
for(var p in obj){
    alert("名称:" + p + ",值:" + obj[p]);
}

2.匿名函数的自动调用

这一段代码结构可以简化为:

function Person(properties){
for(var p in properties){    
    (  
      function(){ 
       ...
      }()  
    );
  }
}

可以看到,里面其实就是调用了匿名函数(即文章最开头的第二种写法)

3.函数调用时的上下文关系

每个函数调用时总会关联一个上下文(如果找不到上下文,则最终会关联到window对象)

function foo(fn){   
 //this.barbar = "Foo.barbar";
 if (typeof fn === "function"){
  fn();
 } 
}

var bar = {
 barbar : "Hello,World!",
 method:function(){    
  alert(this.barbar);
 }
}

bar.method(); //调用时,medhod中的this指的就是bar对象的上下文,此时this.barbar 与 bar.barbar等效  

foo(bar.method);//调用时,这时bar.method中的this指代的是foo内部的上下文,而foo中并没有barbar的定义,因此最终this.barbar其实就是foo.barbar,所以会弹出"undefined",如果把foo中的注释行去掉注释,就更能映证这一点

这是最近网上热传的"javascript令人费解的10件事"中的一段代码,我在注释中加了自己的理解,再回到文中的代码,代码的本意是想让Person类动态添加对所有的属性的getXXX与setXXX方法(通过匿名函数的自动调用),而匿名函数在执行时getXXX与setXXX函数的上下文this默认是指向匿名函数的,而非Person类本身!为了解决这个问题,不得不在匿名函数中增加了一个参数context,并且在调用时用(function(...){}(this));把Person的上下文this传入到匿名函数中

4.闭包 关于闭包,不再做过多的学术解释,先给一段代码:

<ul>
 <li id="a1">aa</li>
 <li id="a2">aa</li>
 <li id="a3">aa</li>
</ul>

<script type="text/javascript">

for (var i=1;i<= 3;i++){
 var li = document.getElementById("a" + i);
 li.onclick = function(){
  alert(i);
 }
}

</script>

解释onclick生成了一个匿名函数,并引用外层的变量i,形成闭包,造成变量i在该函数中共享(可以理解为三个li的onclick函数中都引用同一个变量i),而i在循环结束后,变成4,因此所有li最终点击都是弹出4

解决办法:

<script type="text/javascript">
for (var i=1;i<= 3;i++){
 var li = document.getElementById("a" + i);
 li.i = i;
 li.onclick = function(){    
  alert(this.i);
 }
}
</script>

再回到文中的代码,同样匿名函数引用外层的变量p,形成闭包,如果不用var t = p;中转一下变量,则最后所有的getXXX与setXXX方法,都是对应最后一个属性的.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • javascript中定义私有方法(private method)

    一度以为在javascript的世界里,所有方法都是公有的,无法真正从技术上定义一个私有方法,今天又一次发现:其实我错了!  var Person = func...

    菩提树下的杨过
  • FluorineFx:基于RSO(远程共享对象)的文本聊天室

    在前一篇“FluorineFx:远程共享对象(Remote SharedObjects)”里,已经大致知道了在FluorineFX中如何使用RSO,这一篇将利用...

    菩提树下的杨过
  • javascript:双链表-插入排序

    数组存储前提下,插入排序算法,在最坏情况下,前面的元素需要不断向后移,以便在插入点留出空位,让目标元素插入。 换成链表时,显然无需做这种大量移动,根据每个节点的...

    菩提树下的杨过
  • 深入理解JavaScript系列(37):设计模式之享元模式

    享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。

    用户4962466
  • JavaScript组件设计思想

    上个周,并肩作战的田老师离职了,尽管在一起愉快玩耍的时间不到一年,自己仍然还是从其身上学到、体会到了好多关于知识、理想的东西。对于大多数年轻人关于“晚上想想千条...

    奋飛
  • Openlayers4中实现动态线效果

    lzugis
  • 面向对象+模块化设计绘制canvas星空动画

    require.js的相关内容已在我的博文 《requireJs的使用,以canvas绘制星空为例》中描述, 可查看:https://cloud.tencent...

    lonelydawn
  • 【Golang语言社区--H5编程】smoke.js

    大家好,我是社区主编彬哥,今天给大家带来的H5游戏编程中,烟雾特效的js库; 源码如下 var smokemachine = function (c...

    李海彬
  • canvas 绘点图

    deepcc
  • 【JS 口袋书】第 8 章:以更细的角度来看 JS 中的 this

    JS 中的this关键字对于初学者来说是一个谜,对于经验丰富的开发人员来说则是一个永恒的难题。this 实际上是一个移动的目标,在代码执行过程中可能会发生变化,...

    前端小智@大迁世界

扫码关注云+社区

领取腾讯云代金券