一、 函数this指向
JavaScript 中的 this 指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解、由浅入深。
函数的调用方式决定了 this 指向的不同:
调用方式 | 非严格模式 | 备注 |
---|---|---|
普通函数调用 | window | 严格模式下是 undefined |
构造函数调用 | 实例对象 | 原型方法中 this 也是实例对象 |
对象方法调用 | 该方法所属对象 | 紧挨着的对象 |
事件绑定方法 | 绑定事件对象 | |
定时器函数 | window |
1、普通构造函数中的 this:
2、构造函数中的 this:
所谓构造函数 ,是一种特殊的函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
- 构造函数用于创建一类对象,首字母要大写。
- 构造函数要和 new 一起使用才有意义。
3、对象方法调用:
4、定时器中的 this:
setInterval 是BOM的,BOM中顶级对象是window,浏览器中所有的东西都是window的,而window往往是省略不写的。
5、原型对象方法中的 this :
6、严格模式的 this 指向:
f1() 是 window 调用的,而window往往在写的时候省略。
因为当严格模式下去调用函数的时候,它会认为函数应该是个方法,方法应该是通过对象调用的,那这个对象没写,那我 怎么知道这个 this 的是谁。但是说你要想真的调用这个函数就应该通过对象来调用,其实浏览器里面写的或者页面上写的所有的什么函数、方法最终都应该算是一个方法。而方法的本质是函数。也就是说方法是一个函数、函数也可以看成是方法。因为这个函数就是通过 window 对象调用的。对象调的东西就应该是个方法。那你要调用的话到底是谁调用的? 所以是 undefined
二、 函数的不同调用方式
- 普通函数
- 构造函数—通过new 来调用,创建对象
- 对象的方法
- 回调函数
三、函数也是对象
首先明确一下概念:函数是对象,对象不一定是函数
- 对象中有__proto__原型,是对象
- 函数中有prototype 原型, 是对象
方法是通过对象调用的,而函数能调用方法,那么函数也是对象。
所有的函数实际上都是Function的构造函数创建出来的实例对象,下面的代码为证:
所以,函数实际上也是对象,如果一个东西里面有prototype,又有__proto__,说明是函数,也是对象。
四、call、apply、bind
那了解了函数 this 指向的不同场景之后,我们知道有些情况下我们为了使用某种特定环境的 this 引用,这时候时候我们就需要采用一些特殊手段来处理了,例如我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。
然而实际上对于这种做法我们的 JavaScript 为我们专门提供了一些函数方法用来帮我们更优雅的处理函数内部 this 指向问题。
这就是接下来我们要学习的 call、apply、bind 三个函数方法。
- apply 和 call 是调用的时候改变 this指向
- bind 方法,是赋值一份的时候,改变了 this的指向
4.1 call 和 apply
call() 方法调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。
语法:
call 参数:
- thisArg
- 在 fun 函数运行时指定的 this 值
- 如果指定了 null 或者 undefined 则内部 this 指向 window
- arg1, arg2, …
- 指定的参数列表
apply 参数:
- apply() 与 call() 非常相似,不同之处在于提供参数的方式。
- apply() 使用参数数组而不是一组参数列表
只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用call 的方法改变this 的指向,来达到使用目的。
4.2 bind
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。
当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。
返回值:
返回由指定的this值和初始化参数改造的原函数拷贝。
示例1:
示例2:
示例3:
小结:
- call 和 apply 特性一样
- 都是用来调用函数,而且是立即调用
- 但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向
- call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
- apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
- 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window
- bind
- 在 bind 的同时,以参数列表的形式进行传递
- 在调用的时候,以参数列表的形式进行传递
- 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准
- 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部