JavaScript的函数和做用域闭包

1. 函数

1.1 定义函数

function add(x, y){
    return x + y;
}

上述函数定义以下:javascript

  • 关键字function指出这是一个函数定义;
  • add是函数的名称;
  • (x, y)括号内列出函数的参数,多个参数以,分隔;
  • {}之间的代码是函数体,能够包含若干语句,甚至能够没有任何语句。

函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。
若是没有return语句,函数执行完毕后也会返回结果,只是结果为undefinedhtml

JavaScript的函数也是一个对象,函数名能够视为指向该函数的变量。所以,函数也能够像下面这样定义。java

var add = function (x, y){
    return x + y;
}

这种状况下,function (x, y){}是一个匿名函数,它没有函数名。可是,这个匿名函数赋值给了变量add,因此,经过变量add就能够调用该函数。数组

1.2 调用函数

调用函数时,按顺序传入参数便可。闭包

add(1, 2); // 3

关键字arguments只在函数内部起做用。咱们经过arguments能够得到调用者传入的全部参数。事实上,arguments最经常使用于判断传入参数的个数。app

function add(x, y){
    for(let i = 0; i < arguments.length; i++){
        console.log(arguments[i]);
    }
    return x + y;
}

console.log(add(1,5)); // 1 5 6

2. 做用域

2.1 概述

在JavaScript中,用var声明的变量是有做用域的。
若是一个变量在函数体内声明,则该变量的做用域是整个函数体。
若是两个不一样的函数各自声明了一个同名变量,那么这两个变量是相互独立的,互不影响。
因为JavaScript的函数能够嵌套,内部函数能够访问外部函数定义的变量,反过来则不行。
JavaScript的函数在查找变量时从自身函数定义开始,从"内"向"外"查找。
若是内部函数定义了与外部函数重名的变量,则内部函数的变量将"屏蔽"外部函数的变量。函数

2.2 变量提高

JavaScript会把变量声明提高到顶部。post

function foo(){
    console.log(x); // 不报错
    var x = 'Hello';
}

// 等同于

function foo(){
    var x;
    console.log(x);
    x = 'Hello';
}

3. 方法

在一个对象中绑定函数,称为这个对象的方法。学习

var me = {
    name: '张三',
    birth: 1994,
    age: function(){
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

console.log(me.age()); // 25

若是以对象的方法形式调用me.age(),函数age()this指被调用的对象me网站

3.1 applycallbind

var obj = {birth: 1990};

console.log(me.age.call(obj)); // 29
console.log(me.age.apply(obj)); // 29
let bind = me.age.bind(obj);
console.log(bind()); // 29

applycallbind这三个函数的做用是改变函数执行时的上下文,即改变函数运行时的this的指向。

  • applycall改变了函数的this上下文后便执行该函数,bind则返回改变了上下文后的一个函数。
  • applycall的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展示,apply把除了改变上下文对象的参数放在一个数组里面做为它的第二个参数。
let arr1 = [1, 2, 10, 4];
//例子:求数组中的最值
console.log(Math.max.call(null, 1, 2, 10, 4)); // 10
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); // 10

5. 高阶函数

5.1 概述

JavaScript的函数接收变量做为参数,而函数名能够视为指向该函数的变量。所以,一个函数能够接收另外一个函数做为参数。这种函数被称为高阶函数

function add(x, y, f) {
    return f(x) + f(y);
}

console.log(add(-5, 6, Math.abs)); // 11

内置对象Array提供了一些高阶函数:

  • map
  • reduce
  • filter
  • sort
  • every
  • find
  • findIndex
  • forEach

相关阅读JavaScript Array 对象

5.2 闭包

高阶函数除了能够接受函数做为参数外,还能够把函数做为结果值返回。

/*      
function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}
*/
function lazy_sum(arr) {
    return function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    };
}

var f = lazy_sum([1, 2, 3, 4, 5]);
console.log(f()); // 15

lazy_sum函数中定义了函数sumsum函数能够访问lazy_sum函数的变量arr(内部函数能够访问外部函数,参数能够看做函数中声明的变量)。当一个函数返回了一个函数后,相关的变量都保存在返回的函数中。
返回的sum函数依然保持对lazy_sum函数的做用域的引用,这个引用就叫做闭包
注意:返回的函数没有当即执行,而是直到调用了f()才执行。
使用闭包时要牢记一点是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

再看另外一个例子。

var buildMultiplier = function(x) {
    return function(y) {
        return x * y;
    }
}

var double = buildMultiplier(2);
var triple = buildMultiplier(3);

console.log(double(3)); // 6
console.log(triple(3)); // 9

参考

相关文章
相关标签/搜索