首页 > 语言 > JavaScript > 正文

JS工作中的小贴士之”闭包“与事件委托的”阻止冒泡“

2024-05-06 14:56:02
字体:
来源:转载
供稿:网友

说下闭包的由来

function a() {var i = 0;function b() {console.log(i);}return b;}var c = a();c(); 

一般来说,当一个函数内部匿名函数用到了自己的变量,并且这个匿名函数被返回了,这就建立了一个闭包,比如上面的代码

这个时候,就算a调用结束被销毁,i也会存在不会消失当a定义时,js解释器会将函数a的作用域链设置为定义a时所在环境当执行a时,a会进入相应的执行环境,执行环境创建后才会有作用域scope属性,然后创建一个活动对象,然后将其置为作用域链的顶端

现在a的作用域链就有a的活动对象以及window

然后为活动对象加入arguments属性

这个时候a的返回函数b的引用给了c,b的作用域链包含a的活动对象引用,所以c可以访问到a的活动对象,这个时候a返回后不会被GC

以上便是对闭包的简单介绍,说多了就容易绕进去了,我们这里简单结束,然后进入实际的场景加以说明

实际场景

同事的疑惑

之前一个同事让我去看一个代码:

var User = function (opts) {var scope = this;for (var k in opts) {scope['get' + k] = function () {return opts[k];};scope['set' + k] = function (v) {return opts[k] = v;};}};var u = new User({name: '测试',age: 11}); 

代码本意很简单,希望对传入的对象生成get/set方法,但是他这里就遇到一个闭包问题:

导致这个问题的原因就是返回值内部使用的k永远是“age”,这个k便是由于getXXX函数共享的活动对象,这里修改也比较简单

var User = function (opts) {var scope = this;for (var k in opts) {(function (k) {scope['get' + k] = function () {return opts[k];};scope['set' + k] = function (v) {return opts[k] = v;};})(k);}};var u = new User({name: '测试',age: 11}); 

在for循环内部创建一个立即执行函数,将k传入,这个时候getXXX函数共享的就是各个匿名函数的“k”了

生成唯一ID

生成唯一ID也是闭包一个经典的使用方式

function getUUID() {var id = 0;return function () {return ++id;}}var uuid = getUUID(); 

这段代码其实非常有意义,我们在浏览器中不停的执行uuid()确实会得到不同的值,但是如果我们只使用getUUID()()的话每次值仍然一样

导致这个问题的原因是,我们将getUUID执行后的结果赋予uuid,这个时候uuid就保存对其中匿名函数的引用,而匿名函数保存着getUUID的活动对象,所以id一直未销毁

而直接调用的话,每次都会重新生成活动对象,所以id是不能保存的

一段有意思的代码

Util.tryUrl = function (url) {var iframe = document.createElement('iframe');iframe.height = 1;iframe.width = 1;iframe.frameBorder = 0;iframe.style.position = 'absolute';iframe.style.left = '-9999px';iframe.style.top = '-9999px';document.body.appendChild(iframe);Util.tryUrl = function (url) {iframe.src = url;};U.tryUrl(url);};             
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选