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 | function test (a, b, c, d) { |
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
9define(['xx'], function () {
var a = '1'
module.exports = {
a: a,
b: function () {
return a + 'hi'
}
}
})
工厂函数执行后,会return出一个对象,对象里引用了工厂函数内部的东西。
画重点,this
js中,函数执行时this的指向,跟你如何执行这个函数有关。
- 如果该函数被执行时,是直接调用的: 如 test(), 则内部this永远指向全局对象。(在严格模式下,会是undefined)
- 如果函数执行时,是作为方法调用的,例如obj.test(), 则函数内部this便指向对象obj,这个跟其他语言类似,容易理解。(因为方法调用时,函数会被隐式传入一个this,指向调用该函数的母体对象)
在第二种情况中,如果obj.test函数内部存在一个嵌套的函数定义abc, 那么在函数test内部又直接执行abc()的时候,abc内部的this已经跟obj.test这个调用无关了。如:
1
2
3
4
5
6obj.test = function () {
function abc () {
console.log(this)
}
abc()
}如果像上面这样, 当你调用obj.test(), 打印出来的还是window,因为abc调用时还是采用的直接调用的方式。如果希望访问obj这个对象,则应该这样做:
1
2
3
4
5
6
7obj.test = function () {
var self = this
function abc () {
console.log(self)
}
abc()
}利用了闭包机制,函数作用域内可以引用上层作用域内的变量。
通过new进行构造函数调用时。构造函数内部的this指向新创建的该类型的对象。这个跟其他语言也类似。所以我们构造函数中一般都通过this对该new出来的新对象进行一些初始化的动作。如:
1
2
3
4function Dog () {
this.color = 'white'
this.age = 2
}在构造函数末尾可以return一下this,也可以不写,因为默认就return新创建的对象。
- 通过apply,call,bind调用
这时,this指向跟调用apply时传入的this指针有关。