匿名函数
在JavaScript这门脚本语言中,默认的定义函数格式如下:
function fn(a,b){ console.log(a+b); }
某些情况下定义函数时会省略掉函数名称如下:
function (a,b){ console.log(a+b); }
这样的函数就叫做匿名函数。
而众所周知,函数是通过函数名来调用的,当没有名字时该如何调用,用在什么地方呢?
调用方式
一:放进变量中
let myfn = function(a,b) { console.log(a+b); }; myfn(1,2);
这样一来,这个变量就相当于函数名,因此这个函数就等于是个普通函数了
二:直接执行
常用方式
- (匿名函数)()
- (匿名函数())
(function(a,b){ console.log(a+b); })(1,2) (function(a,b){ console.log(a+b); }(1,2))
三:利用事件调用
let btn = document.getElementById("btn"); btn.onclick = function() { console.log("clicked!"); }
四:作为对象的方法调用
let myobj = { name:"yumefx", hello:function(){ console.log("hello,"+this.name); } }; myobj.hello();
这种方法与第一种方法赋予变量类似。
五:作为另一个函数的参数
function myfn(fn){ fn(); } myfn(function(){ console.log("yes"); });
变量作用域
在ES6之前,当使用var声明变量时,只有全局作用域和函数作用域。
以函数声明为界,函数内部变量和外部变量是两个不同的作用域,内部声明的变量不可以在外部被访问,而内部可以调用和覆盖外部声明的所有变量,即使外层函数已经执行完毕(作用域嵌套)。
var tmp = new Date(); function f() { console.log(tmp); if (false){ var tmp = "hello"; } } f(); //undefined
这段代码中,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是由于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
所谓变量提升,就是将函数和变量的声明提升到当前作用域的最顶端,因此要想变量不是全局变量,那么就得用函数包起来。变量提升的结果就是声明的变量在声明前调用值为undefined而不会报错。
除此以外还有内存泄漏问题,例如用来计数的循环变量泄露为全局变量。
var s = "hello"; for (var i = 0; i < s.length; i++){ console.log(s[i]); } console.log(i);
在ES6之后,有了一个新的变量声明符号let,可以声明块级作用域,只有在当前代码块内有效,并且无法在声明前调用(let不存在变量提升)。
a //undefined { var a = 1; let b = 2; } a //1 b //ReferenceError: b is not defined.
另外,let不能在同一作用域内,重复声明同一个变量,例如不能在函数内部重新声明传入的参数。因此,匿名函数的闭包功能,其实就是在let出现前,将某些变量变成类似块级作用域的方式。
优点是可以防止内部变量污染外部变量,但要小心this指向、变量作用域、内存泄漏等问题。
this指向
var object = { name: "object", getName: function() { return function() { console.info(this.name) } } } object.getName()() //undefined
因为里面的闭包函数是在windows作用域下执行的,因此,this指向windows。
变量作用域
function outer() { var result = []; for (var i = 0; i < 10; i++){ result[i] = function() { console.info(i) } } return result; }
看起来似乎是输出等差数列0,1,2,3,4,…,9,实际上因为每个闭包函数访问变量i是outer执行环境下的变量i,随着循环的结束,i已经变成10了,所以最后打印出的是10,10,10,…,10
解决这个问题如下:
function outer() { var result = []; for (var i = 0; i < 10; i++){ result[i] = function(num) { return function() { console.info(num) } } } return result; }
这样访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样。
内存溢出
function showId() { var el = document.getElementById("app"); el.onclick = function(){ alert(el.id); } }
上面这样写会导致闭包引用外层的el,当执行完alert后,el无法释放内存。修改如下:
function showId() { var el = document.getElementById("app"); el.onclick = function(){ alert(el.id); } el = null; //主动释放el }
使用闭包解决递归调用问题
function factorial(num) { if(num <= 1) { return 1; }else{ return num * factorial(num-1); } } var anotherFactorial = factorial; factorial = null; anotherFactorial(4);
这样写是有问题的,因为最后是return num* argument.callee(num-1),argument.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错。
借助闭包实现修改如下:
function factorial = (function f(num) { if(num <= 1) { return 1; }else{ return num * factorial(num-1); } })
这样实际起作用的是闭包函数f,而不是外面的函数factorial。
每个人都经历着受骗和伤痛,
最终掌握了在这条街道生活下去的本领。
《我的晃荡的青春》
——东野圭吾
评论
I like what you guys are up too. Such clever work and reporting! Keep up the superb works guys I’ve included you guys to my own blogroll.
https://youtu.be/BmR_L57lgjY
Very interesting topic, appreciate it for posting.
https://youtu.be/JVKOorD1_io
Fitspresso stands out among the crowded health supplement market as an exceptional product.
https://youtu.be/UfCRl9HE2EQ
Nice post. I learn something more challenging on different blogs everyday. It will always be stimulating to read content from other writers and practice a little something from their store. I’d prefer to use some with the content on my blog whether you don’t mind. Natually I’ll give you a link on your web blog. Thanks for sharing.
https://youtu.be/pT3_IVg6L-I
292849 805720Oh my goodness! an remarkable article dude. Thank you Even so My business is experiencing issue with ur rss . Dont know why Unable to subscribe to it. Can there be anyone obtaining identical rss dilemma? Anybody who knows kindly respond. Thnkx 537814
Thanks for every other informative website. Where else may just I am getting that kind of information written in such an ideal way? I’ve a venture that I am just now working on, and I have been at the glance out for such info.
https://youtu.be/-ViKgPnMvcc
241265 18585I visited a lot of web site but I believe this one contains something extra in it in it 874087
Wow! Thank you! I constantly needed to write on my website something like that. Can I include a fragment of your post to my website?
https://youtu.be/9eZIPlO-CEE
124803 532745This internet page is often a walk-through for all of the details it suited you with this and didnt know who to ask. Glimpse here, and youll certainly discover it. 224187
876027 729309Id have to speak to you here. Which isnt something Which i do! I love to reading a post that should get men and women to feel. Also, thank you for allowing me to comment! 691908