函数表达式和函数声明

JavaScript中创建函数有两种不同的方式。函数声明这种方式已经使用很久了,但慢慢的被函数表达式这种方式在替代。

//函数声明式
function funcDeclaration() {
    return 'A function declaration';
}
//函数表达式
var funcExpression = function () {
    return 'A function expression';
}

声明和表达式之间的差异

类似于var声明,函数声明可以提升到其他代码之前,但函数表达式不能提到其他代码之前,但它允许保留在本地变量范围内。

通常函数声明和函数表达式是可以相互互换使用,但有时函数表达式结果理解代码不需要一个临时的函数名。

扩展阅读

函数表达式的好处

函数表达式比函数声明式有几个更加有用的地方:

  • 是一个闭包
  • 可以作为其他函数的参数
  • 可以立即调用函数表达式(IIFE)

创建闭包

闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。

function tabsHandler(index) {
    return function tabClickEvent(evt) {
        // 制作tab
        // 可以从内部访问index变量.
    };
}
var tabs = document.querySelectorAll('.tab'),
    i;
for (i = 0; i < tabs.length; i += 1) {
    tabs[index].onclick = tabsHandler(i);
}

附加事件在循环后处理程序,所以一个闭包需要记住for中一个适当的值。

// 不好的代码,说明doSomething为什么需要闭包
var i;
for (i = 0; i < list.length; i += 1) {
    document.querySelector('#item' + i).onclick = function doSomething(evt) {
        // #item(i)做什么
        // 但是,这个函数执行时,i总是得到list.length的值
    }
}

很容易理解,通过for执行doSomething()函数会发生什么问题。

// 不好的代码,说明doSomething为什么需要闭包
var list = document.querySelectorAll('.item'),
    i,
    doSomething = function (evt) {
        // #item(i)做什么
        // 但是,这个函数执行时,i的值不在循环内
    };
for (i = 0; i < list.length; i += 1) {
    item[i].onclick = doSomething;
}

这里的解决方案是通过index作为函数参数传递给一个外部函数,以便将该值传递给一个内部函数。你通常会看到通过return一个函数来处理:

// 以下代码展示了一个闭包
var list = ['item1', 'item2', 'item3'],
    i,
    doSomethingHandler = function (itemIndex) {
        return function doSomething(evt) {
            // 现在doSomething函数可以通过 index变量来访问itemIndex参数
            // 以及其他变理也是可用的
            console.log('Doing something with ' + list[itemIndex]);
        };
    };
for (i = 0; i < list.length; i += 1) {
    list[i].onclick = doSomethingHandler(i);
}

在这个FAQ示例中可以帮助你更好的理解闭包。

扩展阅读

作为参数传递

函数表达式可以作为参数直接传递给函数,而没有必要赋值到另一个临时变量上。

在jQuery中,他们常以一个匿名函数的形式出现,如:

$(document).ready(function () {
    console.log('An anonymous function');
});

还可以使用类似forEach()方法,使用一个处理数组项的函数表达式传给forEach()。它们也不是匿名函数。给函数表达式命名是为了更好的知道表达函数应该做什么,也更好的帮助调试代码:

var productIds = ['12356', '13771', '15492'];

productIds.forEach(function showProduct(productId) {
    ...
});

立即调用函数表达式(IIFE)

IIFE是用来防止你的函数和变量影响全局变量。匿名函数作用域内的所有属性。这是一种常见的设计模式,用来防止代码产生不必要的副作用。

也利于代码块维护,有关于这方面更深入的介绍,可以阅读这篇文章

下面是有关于IIFE的一个简单示例:

(function () {
    // code in here
}());

作为一个模块使用时,更易于维护你的代码:

var myModule = (function () {
    var privateMethod = function () {
        console.log('A private method');
    },
    someMethod = function () {
        console.log('A public method');
    },
    anotherMethod = function () {
        console.log('Another public method');
    };

    return {
        someMethod: someMethod,
        anotherMethod: anotherMethod
    };
}());

扩展阅读

总结

正如我们所看到的,在代码中更多的使用函数表达式来实现函数声明式功能,这样使用你的代码更简洁,更易维护。函数表达多被广大的开发人员使用,也是开发中的一个重要组成部分。如果你在开发中碰到有关于函数表达式一些有意思的东西,欢迎在评论里与我们一起分享。

初学者学习笔记,如有不对,还希望高手指点。如有造成误解,还希望多多谅解。

原文链接:https://www.w3cplus.com/javascript/function-expressions-vs-declarations.html

发表评论

登录后才能评论