이것이 지적한 버그
문제, vue2의 이 포인팅 문제
로 인해 동료가 막혔고, 화살표 함수를 사용하여 해당 소품
>. 내가 그에게 소개했을 때 그는 그것을 몰랐고, 그 후 일부러 프론트엔드 커뮤니케이션 그룹을 살펴보았습니다. 지금까지 적어도 70%의 프론트엔드 프로그래머가 그것을 이해하지 못했습니다. 이것 code>가리키고, 배운 것이 없다면 큰 소리로 말해주세요. <code>bug
,vue2的this指向问题
,使用了箭头函数,导致拿不到对应的props
。当我给他介绍的时候他竟然不知道,随后也刻意的看了一下前端交流群,至今最起码还有70%以上的前端程序员搞不明白,今天给大家分享一下this
指向,如果啥都没学会,请给我一个大嘴巴子。
this
指向跟在哪里定义无关,跟如何调用,通过什么样的形式调用有关this
(这个) 这个函数如何被调用(方便记忆) 上面我们介绍了,this
的指向主要跟通过什么样的形式调用有关。接下来我就给大家介绍一下调用规则,没有规矩不成方圆,大家把这几种调用规则牢记于心就行了,没有什么难的地方。
函数最常用的调用方式,调用函数的类型:独立函数调用
function bar() { console.log(this) // window }
window
this
为undefined
用最通俗的话表示就是:对象拥有某个方法,通过这个对象访问方法且直接调用(注:箭头函数特殊,下面会讲解)
const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } info.getName() // 'ice'
info
发起调用,进行了隐式绑定,所以当前的this
为info
,通过this.fullName
毫无疑问的就访问值为ice
隐式丢失 普通
有些情况下会进行隐式丢失,被隐式绑定的函数会丢失绑定对象,也就是说它为变为默认绑定,默认绑定的this
值,为window
还是undefined
取决于您当前所处的环境,是否为严格模式。
const info = { fullName: 'ice', getName: function() { console.log(this.fullName) } } const fn = info.getName fn() //undefined
这种情况下就进行了隐式丢失,丢失了绑定的对象,为什么会产生这样的问题呢?如果熟悉内存的小伙伴,就会很容易理解。
info
找到了对应getName
的内存地址,赋值给变量fn
fn
直接进行了调用window
,从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)
bar
中的fn
为一个回调函数fn = info.getName
参数传递就是一种隐式赋值,其实跟上面的隐式丢失是一个意思,他们都是指向的fn = info.getName
引用,也就是它们的内存地址this
丢失,也就是函数独立调用,默认绑定规则,this
为全局的window
对象var
呢?var
申明的变量才会加入到全局window
对象上letconst
则不是,具体的后续介绍一下这两个申明变量的关键字 但是在某些场景下,this
的改变都是意想不到的,实际上我们无法控制回调函数的执行方式,因此没有办法控制调用位置已得到期望的绑定即this指向。
接下来的显示绑定就可以用来解决这一隐式丢失问题。
js中的 ”所有“函数都有一些有用的特性,这个跟它的原型链有关系,后续我会在原型介绍,通过原型链js中变相实现继承的方法,其中call/apply/bind
this
정의된 위치와는 아무런 관련이 없지만 호출 방법 및 형식과 관련이 없는 함수를 가리킵니다.this(this) 호출 방법(기억하기 쉬움)
this
를 가리키는 것은 주로 호출 형식과 관련이 있습니다. 다음으로 호출 규칙을 소개하겠습니다. 규칙이 없으면 아무것도 완료되지 않습니다. 이 호출 규칙을 명심하십시오. 🎜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)
window
이
는 정의되지 않음
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)
info
에 의해 호출되고 암시적으로 바인딩되므로 현재 this
는 info
입니다. code>this.fullName 액세스 값이 ice
이
값이 window인지 여부입니다. code> 또는 <code>undefine
은 현재 환경이 엄격 모드인지 여부에 따라 달라집니다. 🎜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)🎜 이 경우 암시적 손실이 수행되고 바인딩된 개체가 손실되는 이유는 무엇입니까? 기억에 익숙하다면 이해하기 쉬울 것이다. 🎜
info
를 통해 getName
에 해당하는 메모리 주소를 찾아 fn 변수에 할당합니다. code>
fn
을 통해 직접 호출이 이루어졌습니다. window, window
에서 fullName
속성을 제거하고 정의되지 않음
function Person(name, age) { this.name = name this.age = age } const p1 = new Person('ice', 20) console.log(p1) // {name:'ice', age:20}
bar
의 fn
은 콜백 함수입니다fn = info.getName code> 매개변수 전달은 일종의 암시적 할당이며 실제로 위의 암시적 손실과 동일한 의미를 갖습니다. 이는 모두 메모리 주소인 <code>fn = info.getName
참조를 가리킵니다. li>this
가 손실되었기 때문입니다. 즉, 함수가 독립적으로 호출되고 기본 바인딩 규칙은 this
가 전역 창이라는 것입니다. code> 객체
var
여야 하는 이유는 무엇입니까? var
로 선언된 변수만 전역 window
객체에 추가되기 때문입니다.letconst
인 경우 사용됨 > 아니요, 변수 선언을 위한 두 가지 키워드는 나중에 자세히 소개하겠습니다. 이
실제로 콜백 함수가 실행되는 방식을 제어할 수 없으므로 호출 위치가 예상되는 바인딩을 얻었는지, 즉 this가 이를 가리키는지 제어할 방법이 없습니다. 🎜🎜다음 디스플레이 바인딩을 사용하면 이 암시적 손실 문제를 해결할 수 있습니다. 🎜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前端开发)