this 去哪?

本文写于 2020 年 4 月 26 日

let obj = {
foo() {
console.log(this)
},
}
let bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window

最后两行函数的值为什么不一样???

之前关于函数的文章里写过了,let bar = obj.foo可以让bar()obj.foo()等价,那为什么 this 指向不一样?

在学 React 的时候,很多人会发现有个很烦人的操作,就是在constructor里面,需要bind(this)

首先需要从函数的调用开始讲起。

ES5 里面有三种函数调用形式:

foo(p1, p2)
console.log('================')
obj.foo(p1, p2)
console.log('================')
foo.call(obj, p1, p2)
/*
* 或者apply或者bind,这三个都是用来绑定this的
*/

乍看之下,前两种简单,后面一种复杂。很多人就选择完全不使用后面的call()

但实际上,后面的才是我们真正的写法,前面的都可以等价的变成该种写法:

func.call(context, p1, p2)

foo(p1, p2) 等价于 foo.call(undefined, p1, p2)

obj.foo(p1, p2) 等价于 obj.foo.call(obj, p1, p2)

很多人特别喜欢死记硬背这个 this 的指向,“谁调用 this 就指向谁”blablabla……

但实际上,this 是要为我们所用的,我想让你指向谁,你就要指向谁。我们不应该被它牵着走。

先看foo(p1, p2)中的 this 如何确定。

当你写下面代码时:

function foo() {
console.log(this)
}
foo()

等价于

function foo() {
console.log(this)
}
foo.call(undefined) // 可以简写为 foo.call()

按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

如果你传的第一个参数是null或者undefined, window 对象就是默认的。因此上面的打印结果是 window。

如果希望这里的 this 不是 window 该怎么做呢?

很简单:

func.call(obj) // 那么里面的 this 就是 obj 对象了

再看obj.foo(p1, p2) 里的 this 如何确定:

let obj = {
foo() {
console.log(this)
},
}
obj.foo()

他本身的指向就是 obj 自己,所以写成call()也就是:obj.foo.call(obj)

回到最上面的代码。

let obj = {
foo() {
console.log(this)
},
}
let bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar()
// 转换为 bar.call()
// 由于没有传 context
// 所以 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象

提一个有趣的用法:如果把函数放到数组里,然后数组[]调用函数,this 指向哪里呢?

function fn() {
console.log(this)
}
let arr = [fn, fn2]
arr[0]()

这里面的 this 是什么呢?

我们可以把arr[0]()理解为arr.0(),虽然后者的语法错了,但是形式与转换代码里的obj.foo(p1, p2)对应上了!

arr[0]() => arr.0() => arr.0.call(arr)

那么里面的 this 就是 arr 了。

总之,this 就是你 call 一个函数时,传入的第一个参数。

(完)

this 去哪?的更多相关文章

  1. 神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观

    前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本 ...

  2. 就这么漂来漂去---一个毕业三个月的java程序员的裸辞风波

    注:这并不是一篇技术文章,而是记录了我这几个月经历的入职,裸辞,找工作的心路历程,简单介绍一个博主的情况,我是16年毕业生,校招进了一家北京的公司,java开发,和很多年轻人一样,干了一段时间,我发现 ...

  3. 去IOE的一点反对意见以及其他

    某天在机场听见两老板在聊天,说到他们目前销售的报表老跟不上的问题,说要请一个人,专门合并和分析一些发过来的excel表格,我真想冲上去说,老板,你需要的是一个信息处理的系统,你需要咨询么.回来一直耿耿 ...

  4. IM 去中心化概念模型与架构设计

    今天打算写写关于 IM 去中心化涉及的架构模型变化和设计思路,去中心化的概念就是说用户的访问不是集中在一个数据中心,这里的去中心是针对数据中心而言的. 站在这个角度而言,实际上并非所有的业务都能做去中 ...

  5. JavaScript 函数节流和函数去抖应用场景辨析

    概述 也是好久没更新 源码解读,看着房价蹭蹭暴涨,心里也是五味杂陈,对未来充满恐惧和迷茫 ...(敢问一句你们上岸了吗) 言归正传,今天要介绍的是 underscore 中两个重要的方法,函数节流和函 ...

  6. 回车去替换铵钮的click点击功能

    某一时候,我们不想在form的所有必填的域均完成之后,再去使用mouse去点击铵钮来提交数据.而是直接按回车去focus提交的铵钮来提交. 可以写jQuery script程序:

  7. app使用微信支付成功后,点击返回到该app却跳到另外一个app去了

    刚接手了公司iOS的两个APP, 现在碰到了这样一个问题: 有一台iPhone在一个APP中使用了微信支付,支付成功后,点击返回到该APP,结果却跳到了另外一个APP去了. 这两个APP都是公司开发的 ...

  8. [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  9. [LeetCode] Serialize and Deserialize Binary Tree 二叉树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  10. openwrt下部署adbyby去广告大师 免luci 带自启动,自动开启透明代理

    最近朋友送了个360老路由器 C301,于是乎就掉进了智能路由器的坑, 玩智能路由器第一件事一定是去广告, 要么怎么对得起智能路由器- -! 路由器去广告当然首推广告屏蔽大师 www.adbyby.c ...

随机推荐

  1. 是否可以从一个静态(static)方法内部发出对非静态 (non-static)方法的调用?

    不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在 调用静态方法时可能对象并没有被初始化.

  2. Easyx库安装教程

    目录: 安装 使用 帮助文档 安装 打开Easyx官网https://easyx.cn/ 点击图中下载按钮,下载Easyx库.或者直接点此下载 双击运行 图中标注的绿色框内为官方提供的帮助文档,红色框 ...

  3. 一整套PCB设计流程和要点,老板再也不怕我出错!

    资料输入阶段 1. 在流程上接收到的资料是否齐全(包括:原理图.*.brd文件.料单.PCB设计说明以及PCB设计或更改要求.标准化要求说明.工艺设计说明文件) 2. 确认PCB模板是最新的 3. 确 ...

  4. 【静态页面架构】CSS之定位

    CSS架构 1.浮动: 是以float属性设置容器指定的位置 <style> div { width: 200px; height: 200px; } #qq { background-c ...

  5. 彻底搞懂CSS层叠上下文、层叠等级、层叠顺序、z-index

    前言 最近,在项目中遇到一个关于CSS中元素z-index属性的问题,具体问题不太好描述,总结起来就是当给元素和父元素色设置position属性和z-index相关属性后,页面上渲染的元素层级结果和我 ...

  6. es6-Set与Map

    se5中的set与map 在est5中开发者使用对象属性来模拟.set多用于检查键的存在,map多用于提取数据. { let set = Object.create(null) set.foo = t ...

  7. 设计一个基于svg的涂鸦组件(一)

    基于svg写了一个涂鸦组件,说项目之前先附上几张效果图: 项目地址:SVGraffiti 由于篇幅问题,本文先总体介绍一下项目的大概情况,重点介绍一下组件间的通信方式. 一.项目说明 该项目是基于we ...

  8. sparksql Seq生成DataFrame

    首先,使用样例类: case class User(id:Int,name: String,gender:String, age: Int) 之后使用Seq创建Dataframe val alice: ...

  9. 每日所学之自学习大数据的Linux环境的配置

    今天开始配置环境,因为下载镜像文件需要很长时间,加上训练,所以Linux环境之配置了一半 VMware下载及安装教程(Window) 在安装虚拟机时需要下载镜像文件 下面是我下载的镜像文件的地址 Ce ...

  10. Vue整合axios 插件方式

    1 创建一个vue的项目 使用命令 vue create axios-vue 创建,可以什么都不用勾选 2 安装axios npm install axios --save 如果安装过程很慢的话,也可 ...