this指向的問題以及改變方法
this指向問題最核心的一句話:
哪個物件呼叫函式,函式裡面的this就指向哪個物件
理解起來是有點抽象
下面是一些列子
1、普通函式呼叫
2、物件函式呼叫
3、建構函式呼叫
4、apply、call呼叫
5、箭頭函式呼叫
一、普通函式呼叫
在非嚴格模式下,this的指向都是window
下面需要注意let、var不同寫法的區別
先介紹下let、 var,let是塊級作用域變數,寫在函式中則只在函式內部有效。var申明的變數要不是全域性的,要麼就是函式級別的,不是塊級的
這裡用程式碼簡單介紹下let、var
都是let的情況下
<script> let fn = function() { let name = 'tom' if (true) { let name = 'pig' console.log(name); } console.log(name); } fn() </script>
先使用let後使用var
<script>
let fn = function() {
let name = 'tom'
if (true) {
var name = 'pig'
console.log(name);
}
console.log(name);
}
fn()
</script>
會發現報錯,因為var相當於函式級作用域,相當於一個函式作用域中有兩個n的變數,var作用於整個fn,和let衝突了,let不能重複的宣告,already been declared=已經被宣告。
先var 後let的情況
<script>
let fn = function() {
var name = 'tom'
if (true) {
let name = 'pig'
console.log(name);
}
console.log(name);
}
fn()
</script>
這裡沒發現報錯因為先宣告var再宣告let是可以的
上面可以簡單的對var let有個理解,方便理解下面的知識
1、使用let
<script>
let name = "tom"
function fn() {
console.log(this.name); //undefind
}
fn();
</script>
這裡打印出來的是undefined
2、使用var
<script>
var name = "tom"
function fn() {
console.log(this.name); //tom
}
fn();
</script>
這裡打印出來的是tom
區別就是上面描述的
3、使用window
<script>
window.name = "tom"
function fn() {
console.log(this.name); //tom
}
fn();
</script>
打印出來的是tom
二、物件函式呼叫
簡單的理解就是哪個函式呼叫,this就指向哪裡
<script>
let name = "tom"
let obj = {
id: 121,
fn: function() {
console.log(this.name);
console.log(this.id);
}
}
obj.fn()
</script>
這裡obj呼叫了函式,所以this指向指向了obj,obj中只有id沒有那麼
這裡會出現b賦值給a然後a呼叫,注意this指向不要搞混
<script>
let obj1 = {
name: "tom"
}
let obj2 = {
name: "pig",
fn: function() {
console.log(this.name);
}
}
obj1.fn = obj2.fn
obj1.fn()
</script>
再次宣告:哪個函式呼叫this就指向哪裡
三、建構函式呼叫
<script>
let fn = function() {
this.name = "tom"
}
let fn1 = new fn()
console.log(fn1.name);
let fn2 = new fn()
fn2.name = "pig"
console.log(fn2.name);
</script>
這裡可以看到this指向
這裡需要注意return的出現
<script>
let fn = function() {
this.name = "tom"
return {
username: 'age'
}
}
let fn1 = new fn()
console.log(fn1);
console.log(fn1.name);
</script>
這裡發現return中的this指向指向的直接指向這個物件,而不是函式
四、apply和call、bind
上面介紹了this在函式中的指向問題,在現實中我們可以改變this的指向,比如apply、call、bind
apply
用法:改變函式中的this指向。
xxx.apply(物件名,陣列) 就是將xxx函式中的this指向指向物件名,陣列中的元素依次與元素的引數對應
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.apply(obj, [3, 4])
call
用法:改變函式中的this指向問題,和apply的區別是第二個引數不為陣列
xxx.call(物件名,引數1,引數2,引數3.......) 就是將xxx函式中的this指向指向物件名,引數中的元素依次與元素的引數對應
<script>
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.call(obj, 3, 4)
</script>
bind
用法:改變函式中的this指向問題,和call寫法一樣,不同的地方是bind返回的是一個函式,所以我們在呼叫的時候在進行傳參
xxx.bind(物件)(引數1,引數2......)
<script>
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.bind(obj)(3, 4)
</script>
五、箭頭函式呼叫
ES6中提供的箭頭函式,箭頭函式中沒有this,箭頭函式中的this是繼承外部函式的this。
<script>
let obj = {
name: 'tom',
fn: function() {
setTimeout(function() {
console.log(this.name)
})
}
}
obj.fn()
</script>
這裡的到的this.name為undefined,因為普通函式中的this指向的是window物件,這裡window中並沒有定義name,所以為空。
<script>
let obj = {
name: 'tom',
fn: function() {
setTimeout(() => {
console.log(this.name)
})
}
}
obj.fn()
</script>
這裡使用箭頭函式,在定時器中找不到this指向會向上級查詢,所以是tom