【面试必考点】这一次带你彻底学会this的指向问题

这篇具有很好参考价值的文章主要介绍了【面试必考点】这一次带你彻底学会this的指向问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

相信很多朋友和我一样,总是搞不清this的指向关系,由于没有硬性要求,所以又总是不想学习,经过两次面试后,笔者发现这个考点真是面试官常考的点大家静下心来一起学习这篇this的指向吧!


文章主体内容分为两块:this的指向以及如何改变this的指向

一、this的指向问题

1.1 全局中的this

全局的this指向window

    // 1. 全局中的this
    console.log(this) // window

1.2 普通函数中的this

普通函数中的this指向调用者

	function fn() {
	      console.log(this) // window
	   }
	 fn()  // window.fn(),window调用了fn函数,所以fn中的this表示window

这里的fn(),调用者实际上是window,只不过是window.fn(),window省略了

默认绑定 (指向window的情况) 函数调用模式 fn()

    let obj = {
        name : '前端百草阁',
        fn: function(){
            console.log(this.name)
        }
    }
    obj.fn() // 输出结果: 前端百草阁

这里的fn调用者是obj这个对象,所以this.name等价于obj.name

隐式绑定 (谁调用, this指向谁) 方法调用模式 obj.fn()

1.3 定时器中的this

定时器中的this指向全局对象window

	function sayHello() {
	  console.log(this);
	}
	
	setTimeout(sayHello, 1000); // window

1.4 事件处理函数中的this

事件处理函数中的this指向事件源

   document.body.addEventListener('click', function () {
      console.log(this) // body
    }) 

当触发点击事件时,打印 body,此例中事件源为body,所以this指向事件源(body)

1.5 构造函数中的this

构造函数中的this指向实例化对象
new 绑定(构造函数模式)

在使用 new 创建对象时也会进行 this 绑定

new 实例化对象的四步:
1.创建一个新对象
2.让构造函数里的this指向新对象
3.执行构造函数
4.返回实例

function Dog(age) {
     this.age = age
     this.say = function () {
       console.log(this)
       console.log(this.age)
     }
  }
  
  //利用构造函数创建实例化对象dog
 let dog = new Dog()
 dog.say()  // 输出结果: 
 		   //			Dog {age: 3, say: ƒ}
            //           3

这里的dog为实例化对象,所以构造函数中的this等价于dog这个实例化对象
有的同学可能会有点迷糊,这里大家切记this指向是在运行时确定的,而不是在定义时确定的
代码运行时实例化出了一个dog对象,这时this指向这个实例化对象,并不是说在定义构造函数时就确定this了

值得一提的是,若你在构造函数的原型对象上再添加一个方法,this依然指向实例化对象

	function Dog(age) {
	      this.age = age
	      this.say = function () {
	        console.log(this)
	        console.log(this.age)
	      }
	   }
	Dog.prototype.eat = function () {
      console.log(this)
    }
	   //利用构造函数创建实例化对象dog
	    let dog = new Dog()
	    dog.say()  // 输出结果: 
	    		   //			Dog {age: 3, say: ƒ}
	               //           3
	    dog.eat()  // 输出结果: Dog {age: 3, say: ƒ}

1.6 构造函数静态方法中的this

构造函数的静态方法中,this表示构造函数

	//	 构造函数Pig
		function Pig() {
	 
	  	 }
	    // 给构造函数,直接添加的方法,叫做静态方法
	    Pig.eat = function () {
	      console.log(this)
	    }
	    // 调用的时候,只能使用构造函数调用
	    Pig.eat() // 输出结果: ƒ Pig() { }

1.7 箭头函数中的this

箭头函数没有自己的this值,会继承外部作用域的this

箭头函数不同于传统函数,它其实没有属于⾃⼰的 this

它所谓的 this 是, 捕获其外层 上下⽂this 值作为⾃⼰的 this 值。

并且由于箭头函数没有属于⾃⼰的 this ,它是不能被 new 调⽤的。

我们可以通过 Babel 转换前后的代码来更清晰的理解箭头函数:

// 转换前的 ES6 代码
const obj = { 
  test() { 
    return () => { 
      console.log(this === obj)
    }
  } 
}
// 转换后的 ES5 代码
var obj = { 
  test: function getArrow() { 
    var that = this
    return function () { 
      console.log(that === obj)
    }
  } 
}

通过语法降级我们看到,箭头函数中的 this 就是它上层上下文函数中的 this


  var age = 10
    let obj = {
      age: 20,
      say: () => {
        console.log(this.age) // 10
      }
 }

obj.say()

这里大家觉得this.age是10 还是 20呢?
这里的箭头函数没有this,但是它会继承外部作用域的this,这里箭头函数作用域外,就是全局作用域window了,可能会有很多人觉得为什么不是obj的局部作用域呢? 因为!!对象的大括号不能当做一个作用域
所以这里的this.age 等价于 window.age 即为 10
再来一个例子

 var age = 10
 let obj = {
      age: 20,
      eat: function () {
        let fn = () => {
          console.log(this.age) // 箭头函数中没有this,所以这里的this指向eat方法中的this,即obj
        }
        fn()
      }
   }

obj.eat()

这里箭头函数中的this指向eat方法中的this,eat中的this又指向obj对象,所以这里的输出结果为20
【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向

二、修改函数中的this指向

接下来介绍的这三种方法的调用者都必须是函数

显式绑定 (又叫做硬绑定) 上下文调用模式, 想让this指向谁, this就指向谁

2.1 call

call的语法:函数.call(新的this,3,4),其中3,4代表传递的参数,34方便理解

let obj = { age: 20 }
 
function fn(x, y) {
    console.log(this)
    console.log(x + y)
  }
fn(34) // 正常调用函数,函数中的this指向 window
fn.call(obj, 3, 4)
    // 总结:
    // 1. 函数.call() 表示调用函数,原函数fn得以调用了
    // 2. 修改了原函数中的this,改成call方法的第一个参数
    // 3. 如果原函数有形参,可以通过call方法为原函数传递实参

fn.call(obj,3,4) ,call函数一调用,就把原先fn里的this(指向window)改成了一个新的this(指向obj),3,4分别代表x,y要传递的参数
【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向

2.2 apply

apply的语法:函数.apply(新的this, [3, 4]),其中3,4代表传递的参数,34方便理解

let obj = { age: 20 }
 
function fn(x, y) {
    console.log(this)
    console.log(x + y)
}
fn(34)
fn.apply(obj, [3, 4])
    // 总结:
    // 1. 函数.apply() 表示调用函数,原函数fn得以调用
    // 2. 修改了原函数中的this,改成 apply 方法的第一个参数
    // 3. 如果原函数有形参,可以通过 apply 方法为原函数传递实参,但是必须使用数组格式(这也是与call方法的区别)

【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向

2.3 bind

bind的用法就比较不一样了,我们先看看bind函数的特点
1. 函数.bind() 表示创建了一个新的函数,并且不会调用任何函数
2. 修改了新函数中的this,改成 bind 方法的第一个参数了
3. 如果原函数有形参,可以通过 bind 方法为新函数传递实参

所以接下来直接给大家演示bind的使用

let obj = { age: 20 }
function fn(x, y) {
    console.log(this)
    console.log(x + y)
}
let a = fn.bind(obj, 3, 4)
a()

这里因为fn.bind()不会调用任何函数,所以要自己调用一遍
也可以这么写

let obj = { age: 20 }
function fn(x, y) {
    console.log(this)
    console.log(x + y)
}
fn.bind(obj, 3, 4)()

【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向

三、 this指向练习

3.1 某小游戏公司笔试题

请大家先想想答案是多少,再看讲解

        let obj = {
            stringName : "我是abc",
            getName(){
                return function(){
                    return this.stringName
                }
            }
        }
        console.log(obj.getName()()); // undefined

找普通函数的this指向一定要知道调用者是谁,这道笔试题很多人会被误导,以为调用者全都是obj,其实不然
我换种写法,大家就一目了然了

        let obj = {
            stringName : "我是abc",
            getName(){
                return function(){
                    console.log(obj.getName);
                    return this.stringName
                }
            }
        }
        let fn = obj.getName()
        console.log(fn()) // undefined

这两种方式是一模一样的,这样大家是不是一眼就辨别出了呢?调用对象的方法的返回值,this指向的是全局对象window! 。这是因为返回的函数是作为全局函数被调用的,而不是作为 obj的方法被调用的
接下来,我们再看看如何才能读取到obj中的srtingName呢?

        let obj = {
            stringName : "我是abc",
            getName(){
                let that = this
                return function(){
                    return that.stringName
                }
            }
        }
        console.log(obj.getName()());

这里和上面不一样的点:这里利用一个变量that,存储了getName中的this,getName的调用者又是obj,相当于他利用一个that存储了一个this并且指向obj,所以运行结果是:
【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向

3.2 大厂笔试题

手写实现call函数

    Function.prototype.myCall = function(context, ...args) {
        // 判断是否传入了context,如果没有则默认为全局对象
        context = context || window;

        // 将当前函数设置为context的一个属性,以便调用时可以通过context调用
        context.fn = this;

        // 调用函数并传入参数
        const result = context.fn(...args);

        // 删除context的fn属性
        delete context.fn;

        // 返回函数的执行结果
        return result;
};
    function greeting(name) {
    console.log(`Hello, ${this.name + name}!`);
}
    let a = {
        name: "前端"
    }
    greeting.myCall(a,'百草阁');
};

【面试必考点】这一次带你彻底学会this的指向问题,面试,javascript,前端,this指向
实现要点:1.函数要调用 2.要改变this指向 3.要传参
如何实现改变this的指向呢? 大家注意context.fn = this这一行 ,this指向的其实就是greeting这个函数,相当于原本是window.greeting()调用,现在把函数作为context的一个属性调用,把this指向了这个context,改变了原greeting函数的调用方式,从而改变了this的指向

总结

本文重点讲解了,各种this的使用场景如何改变函数中this的指向以及this的练习题
其实很多时候我们都会在各种场景下碰到各类this的问题,但是我们都选择了得过且过,不想花时间去了解,何不在这一次和笔者一起全面的学习this这个面试必考点呢!文章来源地址https://www.toymoban.com/news/detail-541075.html

到了这里,关于【面试必考点】这一次带你彻底学会this的指向问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 史上最全C/C++面试八股文,一文带你彻底搞懂C/C++面试!

    目录 1.讲一讲封装、继承、多态是什么? 2.多态的实现原理(实现方式)是什么?以及多态的优点(特点)? 3.final的作用是什么? 4.虚函数是怎么实现的?它存放在哪里在内存的哪个区?什么时候生成的 5.智能指针的本质是什么,它们的实现原理是什么? 6.匿名函数

    2024年02月08日
    浏览(44)
  • 面试都在问的微服务、服务治理、RPC、下一代微服务… 一文带你彻底搞懂!

    文章每周持续更新,原创不易,「三连」让更多人看到是对我最大的肯定。可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 与微服务相对的另一个概念是传统的 单体式应用程序 ( Monolithic application ),单体式应用内部包含了所有需要的服务。

    2024年02月22日
    浏览(49)
  • 2023 Android面试官 常问的问题以及答案(附最新的Android面试大厂必考174题 )

    已经2023了 但是计算机的寒冬还没有过去 ,但是我们程序员的热情不会被磨灭(有钱就干 越多越有劲)。在这个金三银四的季节 许多公司也发布了更多的招聘岗位 面试机会多了 那我们跟要把握住。以下分享一些面试题给大家,希望能帮到大家找一份好工作。 1.Android与服务

    2023年04月09日
    浏览(49)
  • 32个Java面试必考点-09(上)消息队列Kafka架构与原理

    本课时主要讲解消息队列与数据库相关的知识,重点讲解三部分知识点: 1.Kafka 的架构与消息交互流程; 2.数据库事务的 4 大特性和分类; 3.MySQL 相关的内容,比如索引、MySQL 调优等。 消息队列与数据库知识点 先来看看相关知识点汇总,如下图。首先为了防止歧义进行说明

    2024年02月20日
    浏览(40)
  • 2023金三银四1000道java面试必考题(附答案,赶紧收藏)包含所有大厂高频面试知识点

    我的回答是: 很有必要 。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。现如今,Java 面试的本质就是八股文,把八股文面试题背好,面试才有可能表现好。金九银十招聘黄金季即将来临!大家在考研和找工作中纠结的时候,不妨先看一下面试题,毕竟我

    2023年04月09日
    浏览(55)
  • 【C/C++】结构体内存对齐 ----- 面试必考(超详细解析,小白一看就懂!!!)

    【C/C++】结构体内存对齐 ----- 面试必考(超详细解析,小白一看就懂!!!),C++,C语言超详细解析,c语言,c++,面试,linux,算法

    2024年03月09日
    浏览(46)
  • [C++]:万字超详细讲解多态以及多态的实现原理(面试的必考的c++考点)

    文章目录 前言 一、多态的定义及实现 1.多态的构成条件 2.c++11的override和final 3.重载,重写,重定义的比较 4.抽象类 5.多态的原理 6.多继承中的虚函数表 7.动态绑定和静态绑定 总结 多态的概念: 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的

    2023年04月22日
    浏览(60)
  • MacOS下彻底删除卸载jdk看这一篇就够了

    问题来源 最近发现打开IDEA的启动速度太慢了,发现原来下载的是intel版本的IDEA后来索性全换成arm版本的IDEA和jdk了,然后在卸载jdk的同时发现了几个坑。 根据官网的提示建议 注意:上述命令第二句 sudo rm -fr /Library/PreferencesPanes/JavaControlPanel.prefPane 部分机型PreferencesPanes有可能

    2024年02月12日
    浏览(49)
  • ssh详解–让你彻底学会ssh

    SSH全称secure shell,安全外壳协议(安全的shell),是一个计算机网络协议(默认端口号为22)。通过ssh协议可以在客户端 安全 (提供身份认证、信息加密)的 远程连接 LInux服务器或其他设备。 使用广泛的Xshell软件就是基于SSH协议远程连接。 SSH远程连接之后能干什么? SSH远程

    2024年02月05日
    浏览(49)
  • 【FFmpeg】学会添加水印,只要这一篇就足够

    打算写这样一篇文章很久了,算是对过往的一种总结,也希望能获得更多的反馈继续迭代。在这个人类的主要信息载体已经变为视频的年代,水印的添加也成为了一个许多人不可或缺的技能,对于技术人来讲,那就更不用提。本文详细的介绍了通过FFmpeg为视频添加各种各样的

    2024年02月01日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包