this指向问题
# 普通函数中的this
非严格模式 this -> window
function a() {
console.log(this);
}
a(); // windows
2
3
4
严格模式 this -> undefined
"use strict"
function a() {
console.log(this);
}
a(); // undefined
2
3
4
5
# call,apply,bind中的this
情况1:this -> Window
a.call()
a.call(undefined)
a.call(null)
function a() { console.log(this); } // a.call(); // Window // a.call(undefined) // Window a.call(null) // Window
1
2
3
4
5
6情况2:传什么,this就是什么
function a() { console.log(this) } // a.apply("abc"); // String {'abc'} // a.call(123); // Number {123} const fn = a.bind({x: 1}); fn(); // {x: 1}
1
2
3
4
5
6
7
# 定时器中的this
情况1:定时器 + function this->Window
这种情况下的this始终指向Window
setTimeout(function() { console.log(this) // Window }, 100) function fn() { setTimeout(function() { console.log(this) }, 100) } // fn() // Window fn.call({x: 100}) // Window
1
2
3
4
5
6
7
8
9
10
11情况2:定时器 + 箭头函数 this->上层作用于的this
setTimeout(() => { console.log(this) // Window }, 100) // 普通函数的this是Window function fn() { console.log(this) // Window setTimeout(() => { console.log(this) // Window }, 100) } fn() // 箭头函数定时器的this,指向上层作用于的this function fn() { console.log(this) // {x: 100} setTimeout(() => { console.log(this) // {x: 100} }, 100) } fn.call({x: 100})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class obj{ fn() { setTimeout(() => { console.log(this) // obj {} },100) } } const o = new obj() o.fn()
1
2
3
4
5
6
7
8
9
# 箭头函数中的this
情况1:有function作用域的,this是上层作用域的this
class obj { say = ()=> { console.log(this) // obj {say: ƒ} } } const o = new obj() o.say()
1
2
3
4
5
6
7情况2:没有function作用域的,this是Window
const obj = { say: ()=> { console.log(this) // Window } } obj.say();
1
2
3
4
5
6const btn = document.getElementById("btn"); // btn.onclick = function() { // console.log(this) // <button id="btn">test</button> // } btn.onclick = ()=> { console.log(this) // Window }
1
2
3
4
5
6
7
8
# apply ,call , bind的区别
# apply和call
call() 与apply()只有一个区别,就是 call()
方法接受的是一个参数列表,而 apply()
方法接受的是一个包含多个参数的数组。 call(); 传递参数类型 直接返回调用结果.
call
和apply
的唯一区别就是,call
需要一个个的传可选参数,而apply
只需要传一个数组的可选参数。
普通函数的this默认指向Window。所以下面输出==undefined 作者: undefined.==
const book = {
title: '西游记',
author: '吴承恩',
}
function summary() {
console.log(`${this.title} 作者: ${this.author}.`)
}
summary() //undefined 作者: undefined
summary.call(book) // 西游记 作者: 吴承恩.
summary.apply(book) // 西游记 作者: 吴承恩.
function longerSummary(genre, year) {
console.log(
`${this.title} 作者: ${this.author}. 它是一个 ${genre} 在 ${year} 发表.`
)
}
longerSummary.call(book, '小说', 1999) // 西游记 作者: 吴承恩. 它是一个 小说 在 1999 发表.
longerSummary.apply(book, ['小说', 1999]) // 西游记 作者: 吴承恩. 它是一个 小说 在 1999 发表.
// longerSummary.apply(book, '小说', 1999) // this指向问题.html:125 Uncaught TypeError: CreateListFromArrayLike called on non-object
longerSummary.apply(book, ['小说', 1999]) // 西游记 作者: 吴承恩. 它是一个 小说 在 1999 发表.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# bind
call
和apply
都是一次性使用的方法 -- 如果你调用带有this
上下文的方法,它将含有此上下文,但是原始的函数依旧没改变。
有时候,你可能需要重复地使用方法来调用另一个对象的上下文,所以,在这种场景下你应该使用bind
方法来创建一个显示调用this
的全新函数。
const newSummary = summary.bind(book)
newSummary() // 西游记 作者: 吴承恩.
2
在这个例子中,每次你调用newSummary
,它都会返回绑定它的原始this
值。尝试绑定一个新的this
上下文将会失败。因此,你始终可以信任绑定的函数来返回你期待的this
值。
const newSummary = summary.bind(book)
newSummary() // 西游记 作者: 吴承恩.
const book2 = {
title: '1984',
author: 'George Orwell',
}
const newSummary2 = newSummary.bind(book2) // 并没有绑定成功
newSummary2(); // 西游记 作者: 吴承恩.
2
3
4
5
6
7
8
9
# 比较
# 相同点:
三者都是用来改变函数的上下文,也就是this
指向的。
# 不同点:
fn.bind
: 不会立即调用,而是返回一个绑定后的新函数。
fn.call
:立即调用,返回函数执行结果,this
指向第一个参数,后面可有多个参数,并且这些都是fn
函数的参数。
fn.apply
:立即调用,返回函数的执行结果,this
指向第一个参数,第二个参数是个数组,这个数组里内容是fn
函数的参数。
# 应用场景
需要立即调用使用
call
/apply
要传递的参数不多,则可以使用
fn.call(thisObj, arg1, arg2 ...)
要传递的参数很多,则可以用数组将参数整理好调用
fn.apply(thisObj, [arg1, arg2 ...])
不需要立即执行,而是想生成一个新的函数长期绑定某个函数给某个对象使用,使用
const newFn = fn.bind(thisObj); newFn(arg1, arg2...)