this全面解析, 如何定位this指向,一文总结,再也不怕面试官追问啦

一、调用位置

在理解this的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中被调用的位置(而不是申明的位置)。只有仔细分析调用位置才能回答这个问题:这个this到底引用的是什么?

function foo() {console.log('foo')// 当前调用栈是: bar// 因此,当前调用位置在bar中
}function bar() {console.log('bar')// foo当前调用位置foo()// 当前调用栈是: bar// 因此,当前调用位置在bar中
}function baz() {console.log('baz')// bar当前调用位置bar()// 当前调用栈是: baz// 因此,当前调用位置是全局作用域
}// baz当前调用位置
// 全局作用域
baz()

二、绑定规则

1、默认绑定(非严格模式):独立函数调用

const a = 2
function foo() {console.log(this.a)
}
foo()  // 2
// foo() 在这里直接食用不带任何修饰的函数引用进行调用,因此只能使用默认绑定;调用位置为全局作用域,因此this默认绑定到全局作用域。

2、隐式绑定:调用位置是否有上下文,或者说是否被某个对象拥有或者包含

  • 当函数引用有上下文对象时,隐式绑定规则会把函数调用中this绑定到这个上下文对象上。
function foo() {console.log(this.a)
}
const obj = {a: 2,foo: foo
}
obj.foo()  // 2// 注意: 首先需要注意的是foo()的声明方式,及其之后是如何北方做引用属性添加到obj中的。但是无论是直接在obj中定义还是先定义在添加为引用属性,这个函数严格来说都不属于obj对象。
// 然而,调用位置会使用obj上下文来引用函数,因此你可以说函数被调用时obj对象‘拥有’或‘包含’它。// 当函数引用有上下文对象时,隐式绑定规则会把函数调用中this绑定到这个上下文对象上。

对象属性引用链中只有 最顶层 或者说 最后一层 会影响调用位置

function foo() {console.log(this.a)
}
const obj1 = {a: 2,foo: obj2
}
const obj2 = {a: 42,foo: foo
}
obj1.obj2.foo()  // 42

隐式丢失:一个最常见的this绑定问题就是 被隐式绑定的函数 会丢失绑定对象,也就是说它会引用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否是严格模式。

function foo() {console.log(this.a)
}
const obj = {a: 2,foo: foo
}
const bar = obj.foo // 函数别名!
const a = '我是全局对象' 
bar() // -> 我是全局对象
// 虽然bar是obj.foo的一个引用,但是实际上,他引用的是foo函数本身,因此此时的 bar()  相当于  foo(), 是一个不带任何修饰的函数调用,因此应用了默认绑定
function foo() {console.log(this.a)
}
function doFoo(fn) {// fn其实引用的是foofn()  // <--调用位置!
}
const obj = {a: 2,foo: foo
}
const a = '我是全局对象' 
doFoo(foo) // -> 我是全局对象
// 参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以结果和上一个例子一样
// 如果把函数传入语言内置的函数而不是自定义的函数,会怎么样呐?结果是一样的,没有区别
function foo() {console.log(this.a)
}
const obj = {a: 2,foo: foo
}
const a = '我是全局对象' 
setTimeout(obj.foo, 100)  // -> 我是全局对象// JavaScript环境中内置的setTimeout()函数实现和下面的代码类似:
function setTimeout(fn, delay) {// 等待delay毫秒fn() // <--调用位置!
}

3、显式绑定

function foo() {console.log(this.a)
}
const obj = {a: 2,
}
foo.call(obj) // -> 2
// 通过foo.call(...)可以在调用foo时强制把它绑定到obj上// 思考下面代码输出什么
const b = '我是全局对象' 
function foo() {console.log(this.b)
}
const obj = {b: 2,foo: foo
}
const bar = function(fn) {fn()
}
bar.call(obj, foo)  // -> 我是全局对象// 显然,通过这种方式还是无法解决绑定丢失问题

3.1、硬绑定

function foo() {console.log(this.b)
}
const obj = {b: 2,
}
const bar = function() {foo.call(obj)
}
bar()  // -> 2
// 硬绑定的bar不能再修改它的this
bar.call(window) // -> 2

由于硬绑定是一种非常常用的模式。所以在es5中提供了内置的方法Funtion.prototype.bind
bind(…)会返回一个硬编码的新函数,它会吧参数设置为this的上下文并调用原始函数

function foo(something) {console.log(this.a, something)return this.a + something
}
const obj = {a: 2,
}
const bar = foo.bind(obj)
const b = bar(3)  // -> 2 3
console.log(b) // -> 5

4、new绑定
使用new来调用函数,或者说发生构造函数调用时,它会自动执行下面的操作:

  1. 创建(构造)一个全新的对象
  2. 这个新对象会被执行[[原型]]链接(将这个对象的_proto_指向其构造函数的原型)
  3. 这个新对象会绑定到函数调用(构造函数)的this
  4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
function foo(a) {this.a = a
}
const bar = new foo(2)
console.log(bar.a)  // -> 2

三、优先级

如果某个调用位置同时使用四条规则,那谁的优先级更高呢?
1、隐式绑定与显式绑定谁的优先级更高?

function foo() {console.log(this.a)
}
const obj1 = {a: 2,foo: foo
}
const obj2 = {a: 3,foo: foo
}
obj1.foo()  // -> 2
obj2.foo()  // -> 3obj1.foo().call(obj2)  // -> 3
obj2.foo().call(obj1)  // -> 2//  可以看到,显式绑定优先级高于隐式绑定

2、隐式绑定与new绑定谁的优先级更高?

function foo(something) {this.a = something
}
const obj1 = {foo: foo
}
const obj2 = {}obj1.foo(2)
console.log(obj1.a)  // -> 2obj1.foo.call(obj2, 3)
console.log(obj2.a)  // -> 3const bar = new obj1.foo(4)
console.log(obj1.a)  // -> 2
console.log(bar.a)  // -> 4// 可以看到,new绑定的优先级高于隐式绑定

3、new绑定与显式绑定谁的优先级更高?
new和call/apply无法一起使用,因此无法通过 new foo.call(obj1)来直接进行测试,但是我们可以使用硬绑定来进行测试

function foo(something) {this.a = something
}
const obj1 = {}
const bar = foo.bind(obj1)
bar(2)
console.log(obj1.a)  // -> 2const baz = new bar(3)
console.log(obj1.a)  // -> 2
console.log(baz.a) // -> 3// 可以看到,new绑定的优先级高于显式绑定

四、判断this步骤

现在我们可以根据优先级来判断函数在某个调用位置引用的式哪条规则:

  1. 函数是否在new中调用(new)绑定?如果是的话this绑定的是新创刊的对象。
    const bar = new foo()
  2. 函数是否通过call,apply(显示绑定)或者bind(硬绑定)调用?如果是的话,this绑定的式指定对象。
    const bar = foo.call(obj2)
  3. 函数是否在某个上下文对象中调用(隐士绑定)?如果是的话,this绑定的是那个上下文对象
    const bar = obj1.foo()
  4. 如果都不是的话,使用默认绑定。如果在严格式模式下,就绑定到undefined,否则绑定到全局对象
    const bar = foo()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

踩着七彩祥云来接你的不一定是意中人,也可能是阿里云

你今天点外卖了吗&#xff1f;你今天剁手了吗&#xff1f; 你每次在饿了么和淘宝上的刷刷刷、点点点 都有阿里云服务器ECS在云端疯狂计算 ——阿里云ECS&#xff0c;支撑了阿里经济体全面上云—— ---- 天猫双11核心系统100%上云 阿里云征服史上最大流量洪峰 饿了么100%迁至阿…

深度思考 Spring Cloud + Alibaba Sentinel 源码原理

随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。作者 | 向寒 / 孙玄来源 | 架构之美头图 | 下载于视觉中国关于 Sentinel 1、理论篇以下是经过多年分…

WORDPRESS付费会员插件Paid Memberships Pro v2.12.5 – Plugin + All Addons

WORDPRESS付费会员插件Paid Memberships Pro v2.12.5 – Plugin All Addons 简介&#xff1a; Paid Memberships Pro是一款功能强大的会员订阅和内容限制管理插件&#xff0c;适用于WordPress网站。它提供了丰富的特性和工具&#xff0c;帮助网站所有者轻松地创建和管理付费…

云计算与星辰大海的结合

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 今年在疫情的影响下&#xff0c;各国的经济发展都遇到了一些困难&#xff0c;甚至除中国以外的主要经济体都会进入了负增长的…

uniapp 打包安卓 Android 抖音app 后端篇~02

文章目录1. 中间件配置2. 云短信配置1. 中间件配置 2. 云短信配置

深入理解javascript之原型和原型链

看到一篇关于原型和原型链很好的文章&#xff0c;一看就懂&#xff0c;分享给大家 什么是原型&#xff1f; 上面的Person.prototype就是原型&#xff0c;它是一个对象&#xff0c;我们也称它为原型对象。 . 原型的作用是什么&#xff1f; 原型的作用&#xff0c;就是共享方法…

从开源自治到微服务云化,用这剂良药提升微服务幸福感

前言 微服务发展至今&#xff0c;因其高内聚、低耦合等特性&#xff0c;以及诸多开源方案带来的开放性&#xff0c;已成为提升架构效率的最佳实践之一。当一项技术或一个框架成为事实标准之后&#xff0c;我们会把更多的注意力聚焦在运维效率和应用可用性的持续提升上。相信下…

uniapp 打包安卓 Android 抖音app 前后端调试篇~03

文章目录1. 未登录首页浏览短视频2. 发布视频-云短信登录3. 发布选择视频4. 上传短视频到云存储5. 测试发布视频6. 个人中心查看发布视频7. 首页查看刚发布视频8. 个人中心1. 未登录首页浏览短视频 在未登录的情况下&#xff0c;首页可以看短视频 2. 发布视频-云短信登录 点…

俯瞰云原生,这便是供应层

来源 | K8sMeetup社区作者 | Catherine Paganini&#xff0c;Jason Morgan头图 | 下载于视觉中国在都在说云原生&#xff0c;它的技术图谱你真的了解吗&#xff1f;中&#xff0c;我们对 CNCF 的云原生技术生态做了整体的介绍。从本篇开始&#xff0c;将详细介绍云原生全景图的…

进击的Kubernetes调度系统(一):SchedulingFramework

作者&#xff1a;王庆璨 张凯 前言 Kubernetes已经成为目前事实标准上的容器集群管理平台。它为容器化应用提供了自动化部署、运维、资源调度等全生命周期管理功能。经过3年多的快速发展&#xff0c;Kubernetes在稳定性、扩展性和规模化方面都有了长足进步。 尤其是Kubernete…

HTTP系列学习(笔记三):HTTP的发展历程思维导图

HTTP&#xff08;HyperText Transfer Protocol&#xff09;是万维网&#xff08;World Wide Web&#xff09;的基础协议。 0.9版本&#xff1a; 1.0版本&#xff1a; 1.1版本&#xff1a; 2.0版本&#xff1a; 2.0进化版本&#xff1a; 为了便于浏览记忆&#xff0c;整理了一份…

为什么说Serverless是云的未来?

作者 | 不瞋 阿里云高级技术专家 每隔几年&#xff0c;IT 界就会出现新突破性的进展。回望整个计算机技术发展史&#xff0c;我们会发现“抽象、解耦、集成”的主题贯穿其中。产业每一次的抽象、解耦、集成&#xff0c;都将创新推向新的高度&#xff0c;也催生出庞大的市场和…

(企业级)HBuilder X 安装蓝叠安卓模拟器

文章目录1. 下载蓝叠模拟器2. 设置 adb链接和root3. 设置竖屏4. 设置uni-app adb 环境变量5. 配置 HBuilderX adb5. 运行6.效果图7.常见模拟器1. 下载蓝叠模拟器 https://www.bluestacks.cn/ 2. 设置 adb链接和root 3. 设置竖屏 4. 设置uni-app adb 环境变量 在 HBuilderX…

小困惑,关于 Serverless 函数计算的字体安装

来源 | Serverless作者 | 孙飞宇头图 | 下载于视觉中国前言首先介绍下在本文出现的几个比较重要的概念&#xff1a;函数计算&#xff08;Function Compute&#xff09;&#xff1a;函数计算是一个事件驱动的服务&#xff0c;通过函数计算&#xff0c;用户无需管理服务器等运行情…

一文带你了解MySQL中的各种锁机制!

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; MySQL中的锁机制,按粒度分为行级锁,页级锁,表级锁&#xff0c;其中按用法还分为共享锁和排他锁. 行级锁 行级锁是Mysql中锁…

for循环中let,var 的经典面试题:for循环中 console.log(i)详解

同学们在刚准备面试时肯定见过一道经典面试题&#xff1a; for(var i 0; i < 10; i) {setTimeOut(function(){console.log(i)}) } // 输出 10 10 10 10 10 10 10 10 10 10for(let i 0; i < 10; i) {setTimeOut(function(){console.log(i)}) } // 输出 0 1 2 3 4 5 6 7…

Hibernate参数校验扩展

Hibernate参数校验 文章目录一、快速入门1. 校验bean2. controller二、企业实战2.1. 校验bean2.2. controller2.3. 全局异常拦截一、快速入门 1. 校验bean package com.gblfy.vo;import org.hibernate.validator.constraints.Length;import javax.validation.constraints.Ema…

后疫情时代,银行从数字化转型到智能化“迁徙”

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 全球数据智能趋势一览 笔者在搜索了众多机构发表的数据智能发展趋势报告&#xff0c;并做了筛选和甄别后&#xff0c;参考了公…

普通二本学校软件工程专业本科毕业的女生,没有考研,选择直接就业现如今过得怎样呐?

第一篇程序人生 在进入大学之前买的联想笔记本电脑被我之前放在窗户边&#xff0c;一个月之前去上班的时候忘记关窗户&#xff0c;下大雨给淋雨进水了&#xff0c;刚好开机密码的几个键盘失灵了&#xff0c;上周末在网上买了一个键盘&#xff0c;终于可以开机了&#xff0c;为…

阿里云交通数据中台解决方案打造“数字化生产力”

数字经济时代&#xff0c;计算、分析、处理等作为“关键生产要素”已成为行业和社会的共识。但是对于交通领域而言&#xff0c;以往端到端的方式进行平台搭建和应用开发已不能适应数字爆炸和产品快速迭代的要求。交通行业在计算分析方面面临着信息采集难、样式杂、变化快、价值…