同事因為this指向的問題卡住的bug
,vue2的this指向問題
,使用了箭頭函數,導致拿不到對應的props
。當我給他介紹的時候他竟然不知道,隨後也刻意的看了一下前端交流群,至今最起碼還有70%以上的前端程式設計師搞不明白,今天給大家分享一下this
指向,如果啥都沒學會,請給我一個大嘴巴子。
指向跟在哪裡定義無關,跟如何調用,透過什麼樣的形式調用有關
#(這個) 這個函數如何被調用(方便記憶)
this的指向主要跟透過什麼樣的形式呼叫有關。接下來我就跟大家介紹一下調用規則,沒有規矩不成方圓,大家把這幾種調用規則牢記於心就行了,沒有什麼難的地方。
function bar() { console.log(this) // window }
為
undefined
const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } info.getName() // 'ice'
發起調用,進行了隱式綁定,所以當前的
this為
info,透過
this.fullName毫無疑問的就訪問值為
ice
隱含丟失普通
有些情況下會進行隱式丟失,被隱式綁定的函數會丟失綁定對象,也就是說它為變成預設綁定,預設綁定的this值,為
window還是
undefined取決於您目前所處的環境,是否為嚴格模式。
const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } const fn = info.getName fn() //undefined這種情況下就進行了隱式丟失,丟失了綁定的對象,為什麼會產生這樣的問題呢?如果熟悉記憶體的小夥伴,就會很容易理解。
找到了對應
getName的記憶體位址,賦值給變數
fn
直接進行了呼叫
,從
window中取出
fullName屬性,必定為
undefined
#隱含遺失進階這裡大家首先要理解什麼是回調函數。其實可以這樣理解,就是我現在不呼叫它,把他透過參數的形式傳入到其他地方,在別的地方呼叫它。
//申明变量关键字必须为var var fullName = 'panpan' const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } function bar(fn) { //fn = info.getName fn() // panpan } bar(info.getName)
中的
fn為一個回呼函數
參數傳遞就是一種隱式賦值,其實跟上面的隱式遺失是一個意思,他們都是指向的
fn = info.getName引用,也就是它們的記憶體位址
遺失,也就是函數獨立調用,預設綁定規則,
this為全域的
window物件
##注意: 為什麼申明必須為
因為只有window
物件上
如果採用
的改變都是意想不到的,實際上我們無法控制回呼函數的執行方式,因此沒有辦法控制呼叫位置已得到期望的綁定即this指向。 接下來的顯示綁定就可以用來解決這個隱式遺失問題。
這三個方法就是函數原型鏈上的方法,可以在函數中呼叫它們。 <h4 data-id="heading-7"><strong>2.3.2 call</strong></h4>
<ul>
<li>
<code>call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
this
对象apply()
方法类似,只有一个区别,就是 call()
方法接受的是一个参数列表,而 apply()
方法接受的是一个包含多个参数的数组。var fullName = 'panpan' const info = { fullName: 'ice', getName: function(age, height) { console.log(this.fullName, age, height) } } function bar(fn) { fn.call(info, 20, 1.88) //ice 20 1.88 } bar(info.getName)
call
的方法类似,只是参数列表有所不同call
参数为单个传递apply
参数为数组传递var fullName = 'panpan' const info = { fullName: 'ice', getName: function(age, height) { console.log(this.fullName, age, height) } } function bar(fn) { fn.apply(info, [20, 1.88]) //ice 20 1.88 } bar(info.getName)
bind
与apply/call
之间有所不同,bind
传入this
,则是返回一个this
绑定后的函数,调用返回后的函数,就可以拿到期望的this。bind
时,可以传入参数bind
返回的参数也可以进行传参var fullName = 'panpan' const info = { fullName: 'ice', getName: function(age, height) { console.log(this.fullName, age, height) //ice 20 1.88 } } function bar(fn) { let newFn = fn.bind(info, 20) newFn(1.88) } bar(info.getName)
谈到new
关键字,就不得不谈构造函数,也就是JS中的 "类",后续原型篇章在跟大家继续探讨这个new关键字,首先要明白以下几点,new Fn()
的时候发生了什么,有利于我们理解this
的指向。
创建了一个空对象
将this指向所创建出来的对象
把这个对象的[[prototype]] 指向了构造函数的prototype属性
执行代码块代码
如果没有明确返回一个非空对象,那么返回的对象就是这个创建出来的对象
function Person(name, age) { this.name = name this.age = age } const p1 = new Person('ice', 20) console.log(p1) // {name:'ice', age:20}
new Person()
的时候,那个this所指向的其实就是p1
对象function bar() { console.log(this) //info } const info = { bar: bar } info.bar()
widonw或者undefined
,变相的可以认为隐式绑定 > 默认绑定var fullName = 'global ice' const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } info.getName.call(this) //global ice info.getName.apply(this) //global ice info.getName.bind(this)() //global ice
function bar() { console.log(this) //123 } const newFn = bar.bind(123) newFn.call(456)
首先我们来说一下,为什么是和bind
比较,而不能对call
和apply
比较,思考下面代码
const info = { height: 1.88 } function Person(name, age) { this.name = name this.age = age } const p1 = new Person.call('ice', 20) //报错: Uncaught TypeError: Person.call is not a constructor
new绑定和bind绑定比较
const info = { height: 1.88 } function Person(name, age) { this.name = name this.age = age } const hasBindPerson = Person.bind(info) const p1 = new hasBindPerson('ice', 20) console.log(info) //{height: 1.88}
bind
对Person
进行了一次劫持,硬绑定了this为info
对象new
返回的固定this的函数new关键字
> bind
> apply/call
> 隐式绑定
> 默认绑定
首先箭头函数是ES6
新增的语法
const foo = () => {}
var fullName = 'global ice' const info = { fullName: 'ice', getName: () => { console.log(this.fullName) } } info.getName() //global ice
ice
ES6
的新特性,箭头函数不绑定this
,它的this
是上一层作用域,上一层作用域为window
global ice
getObjName
通过this
拿到info
中的fullName
(值为ice
的fullName
)const info = { fullName: 'ice', getName: function() { let _this = this return { fullName: 'panpan', getObjName: function() { console.log(this) // obj console.log(_this.fullName) } } } } const obj = info.getName() obj.getObjName()
当我调用 info.getName()
返回了一个新对象
当我调用返回对象的getObjName
方法时,我想拿到最外层的fullName
,我通过,getObjName
的this访问,拿到的this却是obj
,不是我想要的结果
我需要在调用info.getName()
把this保存下来,info.getName()
是通过隐式调用,所以它内部的this就是info对象
getObjName
是obj对象,因为也是隐式绑定,this必定是obj对象,绕了一大圈我只是想拿到上层作用域的this而已,恰好箭头函数解决了这一问题
const info = { fullName: 'ice', getName: function() { return { fullName: 'panpan', getObjName: () => { console.log(this.fullName) } } } } const obj = info.getName() obj.getObjName()
默认绑定
隐式绑定
显示绑定 apply/call/bind(也称硬绑定)
new绑定
new绑定
bind
call/apply
隐式绑定
默认绑定
当一切都看起来不起作用的时候,我就会像个石匠一样去敲打石头,可能敲100次,石头没有任何反应,但是101次,石头可能就会裂为两半 我知道并不是第101次起了作用,而是前面积累所致。
大家有疑惑可以在评论区留言 第一时间为大家解答。
(学习视频分享:web前端开发)