什么是匿名函数:没有实际名字的函数浏览器
匿名函数的做用:bash
一、经过匿名函数能够实现闭包(必须掌握的知识点)闭包
二、模拟块级做用域,减小全局变量。执行完匿名函数,存储在内存中相对应的变量会被销毁,使用块级做用域,会大大下降命名冲突的问题,没必要担忧搞乱全局做用域了。
函数
详解匿名函数:ui
声明一个普通函数:
this
function zxx () {
console.log('good girl')
}
复制代码
将函数的名字去掉spa
function () { // 此时浏览器会报错
console.log('good girl')
}
复制代码
正肯定义的匿名函数.net
(function () {
// 因为没有执行该匿名函数,因此不会执行匿名函数体内的语句。
console.log('zxx')
})
复制代码
对去掉名字的函数加入括号后就是一个匿名函数了:调试
小括号的做用:code
小括号能把咱们的表达式组合分块,而且每一块,也就是每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。因此,当咱们用一对小括号把匿名函数括起来的时候,实际上小括号返回的就是一个匿名函数的Function对象。所以,小括号对加上匿名函数就如同有名字的函数般被咱们取得它的引用位置了。因此若是在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。 通俗点讲就是,加入小括号后就实现了和具名函数同样的形式。
匿名函数自执行,也称为当即执行函数表达式(IIFE)
// 无参数的匿名函数
(function () {
console.log('zxx')
})();
// 带参数的匿名函数
(function (a, b, c) {
console.log('参数一:', a) // 参数一: 这是普通函数传参的地方
console.log('参数二:', b) // 参数二: 我是参数二
console.log('参数三:', c) // 参数三: zxx
})('这是普通函数传参的地方', '我是参数二', 'zxx')
复制代码
// 推荐使用
(function () {
console.log('zxx')
}())
复制代码
!function (zxx) {
console.log(zxx)
}('zxx')
复制代码
let zxx = function (zxx) {
console.log(zxx)
}('zxx')
复制代码
IIFE经常使用用法
IIFE 的另外一个很是广泛的进阶用法是把它们看成函数调用并传递参数进去。
var a = 2;
(function IIFE (global) {
var a = 3
console.log(a) // 3
console.log(global.a) // 2
})(window)
console.log(a) // 2
IIFE 还有一种变化的用途是倒置代码的运行顺序,
将须要运行的函数放在第二位,
在 IIFE 执行以后看成参数传递进去
var a = 2;
(function IIFE (def) {
def(window)
})(function def (global) {
var a = 3
console.log(a) // 3
console.log(global.a) // 2
})
复制代码
匿名函数应用场景
1.事件
$('#zxx').onclick = function () {
console.log('给按钮添加点击事件')
}
2.对象
var obj = {
name: 'zxx',
zxx: function () {
return this.name + ' is' + ' good girl'
}
}
console.log(obj.zxx()) // zxx is good girl
3.函数表达式
var zxx = function () {
return 'zxx is good girl'
}
console.log(zxx()) // zxx is good girl
4.回调函数
setInterval(function () {
console.log('zxx is good girl')
}, 1000)
5.做为函数的返回值
function zxx () {
// 返回匿名函数
return function () {
return 'zxx'
}
}
console.log(zxx()()) // zxx
复制代码
匿名函数模仿块级做用域
if (true) {
var a = 12 // a为全局变量
}
console.log(a) // 12
for (var i = 0; i < 3; i++) {
// console.log(i)
}
console.log(i) // 3 for没有本身的做用域,因此当循环结束后i就成为全局变量
if () {}for () {} 等没有本身的做用域。
若是有,出了本身的做用域,
声明的变量就会当即被销毁了。
但能够经过匿名函数来模拟块级做用域:
function fn () {
(function () { // 这里是咱们的块级做用域(私有做用域)
var zxx = 'good girl!' // 此变量在外部并未定义
console.log(zxx) // good girl!
})()
console.log(zxx) // 报错Uncaught ReferenceError: zxx is not defined
}
fn()
复制代码
习题一
function test(a, b, c, d){
console.log(a + b + c + d);
}(1, 2, 3, 4);
// 不执行也不报错
==============
function test(){
console.log(a + b + c + d);
}();
// 报错:Uncaught SyntaxError: Unexpected token )
复制代码
习题二
function zxxFn (){
var arr = [];
for(var i = 0; i < 10; i ++){
arr[i] = function (){
console.log(i);
}
}
return arr;
}
var zxx = zxxFn();
for(var j = 0; j < 10; j++){
zxx[j]();
}
复制代码
详解
zxxFn中因为for不是块级做用域,因此var i 变成 zxxFn的局部变量,每次新的i都会覆盖原来的,最终i=10。因此会输出10个10
习题三
function zxxFn(){
var arr = [];
for(var i = 0; i < 10; i ++){
(function(j){
arr[i] = function (){
console.log(j + " ");
}
}(i))
}
return arr;
}
var zxx= zxxFn();
for(var j = 0; j < 10; j++){
zxx[j]();
}
复制代码
详解:
这题使用了当即执行函数,把zxxFn中的i当参数传给了,匿名函数的j,因此每次执行j的状态都会更新,因此会输出0 1 2 3 4 5 6 7 8 9
匿名函数的缺点
1. 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难。
2. 若是没有函数名,当函数须要引用自身时只能使用已通过期的 arguments.callee 引用, 好比在递归中。另外一个函数须要引用自身的例子,是在事件触发后事件监听器须要解绑自身。
3. 匿名函数省略了对于代码可读性 / 可理解性很重要的函数名。一个描述性的名称可让代码不言自明。