JavaScript即学即用教程[7]-函数及闭包

函数自身的属性

  • length, 表示函数接收形参的个数
  • name,函数定义时候的名字
  • call, apply, bind。 通过这几个方法,可以实现间接调用自己的目的,而且调动时能改变一些函数的内部环境(如this)

函数内部可访问的变量

  • this, 每个函数内部都可以访问this,不过this的指向会根据不同的调用场景而变化。
  • arguments,每个函数内部都可以通过arguments来访问到传入的实参,arguments是一个类数组的对象,可以通过坐标访问,也可以访问length,但没有数组的那些方法。

bind, call, apply

ECMA5,给函数增加了bind, call, apply方法:

1
var funcA = funcB.bind(whichThis)

它会返回一个新的函数,新的函数在调用时,this已经默认指向whichThis,且不影响funcB。

call和apply都是立即执行一个函数,且执行的同时修改掉函数内部this的指向。

func.call(whichThis, arg1, arg2..), arg1,arg2表示要传递给func的实参。
func.apply(whichThis, arr或arguments对象),arr或arguments表示要传递的实参,apply会自动解构成一个个的参数传给func。

所以apply适合于那种正好处在某个函数内部,且希望把该函数接收到的参数全部传给func的情况。

1
2
3
4
function test (a, b, c, d) {
var obj = {}
func.apply(obj, arguments)
}

bind一般用在哪里?

一般用在给一个事件绑定handler的时候,你可能希望handler触发时,内部还维持着当前环境的this,这时就用到了bind。

自执行函数

1
(function () { /* code */ } ());

这种函数可以用来做一些操作,但不污染外层命名空间

闭包

其实闭包跟作用域有点关系。在js当中,所有函数会创建独立的作用域,而所有函数都可以引用其上层作用域的内容。
而闭包就是在表达函数内包含了自身环境(自身作用域)以及可以连接到外部上下文(作用域)的连接。

所以实际上在js当中,所有函数都是闭包(应该说闭包是一种特点,所有函数都具有闭包这种特点)。

当然,仅仅引用上层作用域是没有太大价值的,闭包最大价值在于一个函数A里return出一个函数B来,这个函数B还在引用着函数A里的环境,这就带来了价值,因为他可以隐藏函数A内部的一些变量和操作,但是外部又拿到了函数B,可以使用函数A内部的一些信息。从而实现了隐藏私有变量,向外暴漏接口的功能,这就是模块化啊!

比如AMD里的

1
2
3
4
5
6
7
8
9
define(['xx'], function () {
var a = '1'
module.exports = {
a: a,
b: function () {
return a + 'hi'
}
}
})

工厂函数执行后,会return出一个对象,对象里引用了工厂函数内部的东西。

画重点,this

js中,函数执行时this的指向,跟你如何执行这个函数有关。

  1. 如果该函数被执行时,是直接调用的: 如 test(), 则内部this永远指向全局对象。(在严格模式下,会是undefined)
  2. 如果函数执行时,是作为方法调用的,例如obj.test(), 则函数内部this便指向对象obj,这个跟其他语言类似,容易理解。(因为方法调用时,函数会被隐式传入一个this,指向调用该函数的母体对象)
  3. 在第二种情况中,如果obj.test函数内部存在一个嵌套的函数定义abc, 那么在函数test内部又直接执行abc()的时候,abc内部的this已经跟obj.test这个调用无关了。如:

    1
    2
    3
    4
    5
    6
    obj.test = function () {
    function abc () {
    console.log(this)
    }
    abc()
    }

    如果像上面这样, 当你调用obj.test(), 打印出来的还是window,因为abc调用时还是采用的直接调用的方式。如果希望访问obj这个对象,则应该这样做:

    1
    2
    3
    4
    5
    6
    7
    obj.test = function () {
    var self = this
    function abc () {
    console.log(self)
    }
    abc()
    }

    利用了闭包机制,函数作用域内可以引用上层作用域内的变量。

  1. 通过new进行构造函数调用时。构造函数内部的this指向新创建的该类型的对象。这个跟其他语言也类似。所以我们构造函数中一般都通过this对该new出来的新对象进行一些初始化的动作。如:

    1
    2
    3
    4
    function Dog () {
    this.color = 'white'
    this.age = 2
    }

    在构造函数末尾可以return一下this,也可以不写,因为默认就return新创建的对象。

  1. 通过apply,call,bind调用
    这时,this指向跟调用apply时传入的this指针有关。

应用

函数缓存

函数柯里化

函数

refer

一个前端的自我修养(有对闭包的解释)