函数

call与apply

call与apply是为了改变某函数运行时的上下文(this的指向)而存在的。

func1.call(this, arg1, arg2); //在参数个数确定时使用
    //或者
func1.apply(this, [arg1, arg2]); //在参数个数不确定时使用。

call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

    var domNodes = Array.prototype.slice.call(document.getElementsByTagName('* '));

这样domNodes就可以应用Array下的所有方法。

函数声明

函数声明是做了完全提升的,这使你在函数声明前就可以进行函数调用。变量声明是部分提升,只有声明会被提升,赋值(包括函数表达式)操作不会被提升,因此变量声明提前,但是赋值不会被覆盖。

function fn(flag) {
    if (flag) {
      var getValue = function () { return 'a'; }
    } else {
      var getValue = function () { return 'b'; }
    }
    return getValue();
}

//等价于

function fn (flag) {
var getValue;
getValue = function() { return 'a';}
getValue = function() {return 'b';}
if(flag) {
}
else {
}
}

因此无论flag为何值,返回的方法始终为重写后的方法。

不能在条件语句中声明函数

不得在非函数的代码块中声明函数,最常见的情况就是if和try语句。

在大多数情况下,都不会报错,但不建议这样使用。

if (true) {
  var f = function () {};
}

f() // undefined

if (true) {
  function f1() {}
}

f1() // 不报错

如果true改回false,在Chrome53版本中,会报错。

函数本身的作用域

var a = 1;
var x = function () {
  console.log(a);
};

function f() {
  var a = 2;
  x();//x在函数体外声明,绑定外层作用域。
}

f() // 1

函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。

函数参数传递方式

函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。

var p = 2;

function f(p) {
  p = 3;
}
f(p);

p // 2

如果写成全局对象,就成了传址传递。

如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

var obj = {p: 1};

function f(o) {
  o.p = 2;
}
f(obj);

obj.p // 2

如何是对象整体赋值,不会影响原来的实际参数。

高阶函数

一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。

闭包

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

函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数变量都保存在返回的函数中,这种称为闭包(Closure)

'use strict';

function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

箭头函数

x => x * x
//上面的箭头函数相当于:

function (x) {
    return x * x;
}

箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

Link

Last updated