同事因为this指向的问题卡住的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对象上let\const 则不是,具体的后续介绍一下这两个申明变量的关键字 但是在某些场景下,this的改变都是意想不到的,实际上我们无法控制回调函数的执行方式,因此没有办法控制调用位置已得到期望的绑定即this指向。
接下来的显示绑定就可以用来解决这一隐式丢失问题。
js中的 ”所有“函数都有一些有用的特性,这个跟它的原型链有关系,后续我会在原型介绍,通过原型链js中变相实现继承的方法,其中call/apply/bind这三个方法就是函数原型链上的方法,可以在函数中调用它们。
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。this对象apply() 方法类似,只有一个区别,就是 apply() 方法接受的是一个参数列表,而 call() 方法接受的是一个包含多个参数的数组。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)apply()的方法类似,只是参数列表有所不同call 参数为单个传递call 参数为数组传递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)apply与bind之间有所不同,apply/call传入bind,则是返回一个this绑定后的函数,调用返回后的函数,就可以拿到期望的this。this时,可以传入参数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) 谈到bind关键字,就不得不谈构造函数,也就是JS中的 "类",后续原型篇章在跟大家继续探讨这个new关键字,首先要明白以下几点,new的时候发生了什么,有利于我们理解new Fn()的指向。
创建了一个空对象
将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}this的时候,那个this所指向的其实就是new Person()对象function bar() {
console.log(this) //info
}
const info = {
bar: bar
}
info.bar()p1,变相的可以认为隐式绑定 > 默认绑定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 icefunction bar() {
console.log(this) //123
}
const newFn = bar.bind(123)
newFn.call(456)首先我们来说一下,为什么是和widonw或者undefined比较,而不能对bind和call比较,思考下面代码
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 constructornew绑定和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}apply对bind进行了一次劫持,硬绑定了this为Person对象info 返回的固定this的函数new > new关键字 > bind > apply/call > 隐式绑定
首先箭头函数是默认绑定新增的语法
const foo = () => {}var fullName = 'global ice'
const info = {
fullName: 'ice',
getName: () => {
console.log(this.fullName)
}
}
info.getName() //global iceES6
ice的新特性,箭头函数不绑定ES6,它的this是上一层作用域,上一层作用域为this
window
global ice通过getObjName拿到this中的info (值为fullName的ice)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()当我调用 fullName 返回了一个新对象
当我调用返回对象的info.getName()方法时,我想拿到最外层的getObjName,我通过,fullName的this访问,拿到的this却是getObjName,不是我想要的结果
我需要在调用obj 把this保存下来,info.getName() 是通过隐式调用,所以它内部的this就是info对象
info.getName()是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前端开发)
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号