本文分为两部分:
- 正确判断
this
- 手写
apply
、call
、bind
正确判断 this
this
是个容易让人混淆的概念,但只要我们理清了思路就会很容易理解。
对于单个规则来说,我们可以按照下面的流程来进行判断:
- 首先,判断函数类型
- 若是箭头函数,
this
就是包裹箭头函数的第一个普通函数的this
- 若是
apply
、call
、bind
,this
是第一个参数 - 普通函数的话,要判断函数是如何被调用的
new
的方式,this
被固化在实例上面- 除了
new
方式以外,判断函数是直接调用(foo()
)还是通过对象调用 (obj.foo()
)foo()
方式,this
为window
obj.foo()
方式,this
为obj
- 若是箭头函数,
通过这个流程,我们可以准确判断 this
。当然,如果我们向改变 this
,就可以采用以下方式:
- 使用箭头函数
- 使用
apply
、call
、bind
方法 - 当然,构造函数也可以改变
this
,通过对象调用也行
手写 apply
、call
、bind
关于 apply
、call
、bind
,都可以改变 this
的指向,但稍稍有些不同。
apply
和call
的区别
其实apply
和call
基本类似,他们的区别主要是传参不同call
的语法:
fun.call(thisArg[, arg1[, arg2[, …]]])apply
的语法:
fun.apply(thisArg, [argsArray])
所以apply
和call
的区别是call
方法接受的是若干个参数列表,而apply
接收的是一个包含多个参数的数组。bind
和apply
、call
区别bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
从这句话,我们可以看出,bind
是创建一个新的函数,需要我们手动去执行。
这是bind
与apply
、call
的主要区别。- 手写
apply
、call
、bind
本文完, 感谢阅读。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56Function.prototype.myCall = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
delete context.fn
return result
}
Function.prototype.myApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
context.fn = this
let result
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
return result
}
Function.prototype.myBind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
return function F() {
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
var obj = {
name: '这是'
}
function printName (fname, lname) {
console.log(this)
console.log(`${this.name} ${fname}${lname}`)
}
printName('liao', 'rui')
printName.myCall(obj, 'liao', 'rui')
printName.myApply(obj, ['liao', 'rui'])
printName.myBind(obj, 'liao', 'rui')()