JavaScript this 的指向问题
原文作者:SegmentFault ——写bug
原文链接:https://segmentfault.com/a/1190000015438195
this的指向已经是一个老生常谈的问题,每逢面试都要去复习复习,近来巩固js的基础,决心彻底掌握这个知识点,一劳永逸。说明一下,为了不影响大家的思考过程,下面的代码都不会去注释答案,想知道答案,只需要去控制台执行一下。
四类场景逐一击破
首先,分析this的指向共有四种类型,在分析之前,我们首先带好两个锦囊:
1.函数被调用时(即运行时)才会确定该函数内this的指向。因为在函数中this与arguments是两个特殊的变量,在函数被调用时才会取得它们,而且搜索这两个变量时只会在活动对象范围里面去搜。(有关活动对象与变量对象的知识,请移步到js 中的活动对象 与 变量对象 什么区别?)
2.要确定函数中this的指向,必须先找到该函数被调用的位置。
认准第一种“test()”形式
var a = 1
function test () {
console.log(this.a)
}
test()
直接不带任何引用形式去调用函数,则this会指向全局对象,因为没有其他影响去改变this,this默认就是指向全局对象(浏览器是window,Node中是global)的。这个结论是在非严格模式的情况下,严格模式下这个this其实是undefined的。
认准第二种“xxx.test()”形式
var a = 1
function test () {
console.log(this.a)
}
var obj = {
a: 2,
test
}
obj.test()
这种形式对比起第一种,很明显test()已经是名花有主的了!看清楚,是谁呼唤的test()?没错,就是obj,所以this的指向就不言而喻了。一句话,谁去调用这个函数的,这个函数中的this就绑定到谁身上。
var a = 1
function test () {
console.log(this.a)
}
var obj = {
a: 2,
test
}
var obj0 = {
a: 3,
obj
}
obj0.obj.test()
即使是这种串串烧的形式,结果也是一样的,test()中的this只对直属上司(直接调用者obj)负责。再来看一个综合点的例子:
var a = 1
function test () {
console.log(this.a)
}
var obj = {
a: 2,
test
}
var testCopy = obj.test
testCopy()
嗯,聪明的你一定想到,换了个名字就能骗到我了!?虽然经过了一波改名换姓,但本质上还不是obj.test()嘛!结果一定和上面一样!唔,请F12在控制台试试,竟然……其实这里并不需要去思考什么,按照我们的套路,我们就认函数调时的样子,有没有看到最后调用的时候跟第一种情况一毛一样?我再介绍一个场景大家一定不会觉得陌生:
var a = 1
function test () {
console.log(this.a)
}
var obj = {
a: 2,
test
}
setTimeout(obj.test)
你可以意淫一下setTimeout的本质,是不是相当于有一个setTimeout函数,接收两个参数:
function setTimeout (fn, time) {
// 这里干了一大波不可描述的事情,最后会去调一下你传进来的回调函数
fn()
}
看到怎样调用你传进来的函数了吗!?再想想我们第一种形式的标题认准第一种“test()”形式。
认准第三种“test.call(xxx) / test.apply(xxx) / test.bind()”形式
看了上面两种形式之后,你可能会想,我非常讨厌上面那些矫情的扭扭捏捏的九曲十八弯的调用方式,让人毫无安全感,我要我自己指定this的指向,我要胜天半子!没问题,我的代码我做主:
var a = 1
function test () {
console.log(this.a)
}
var obj = {
a: 2,
test
}
var testCopy = obj.test
testCopy.call(obj)
可以看到,我们通过call(apply跟call的区别只是传参,作用是一样的,bind有点区别,bind能让我们的函数延迟执行,apply与call调用就执行,所以bind这样的形式我们也称为函数柯里化,这些就不是我们这里要说的啦)来调用testCopy,并且传入了你想要this指向的上下文,那么this就会乖乖按照你的指示行事啦。看到这里,我们也可以想象第一、二种形式其实可以转化成call/apply的形式,有一篇比较棒的文章描述了这样的思考过程,大家也可以看看this 的值到底是什么?一次说清楚
认准第四种“new test()”形式
终于到了最后一种形式了,这种形式比较好认,因为有标志性的new:
var a = 1
function test (a) {
this.a = a
}
var b = new test(2)
console.log(b.a)
new这个操作符其实是new了一个新对象出来,而被new的test我们称为构造函数,我们可以在这个构造函数里定义一下将要到来的新对象的一些属性。那么在构造函数里,我们怎样去描述这个还未出生的新对象呢?没错,就是用this。所以构造函数里的this指的就是将要被new出来的新对象。
One more thing
感谢大家看到这里,但还要说最后一种形式。等等,不是说好的只有四种形式吗!稍安勿躁,正常套路下确实只有上面四种,但是有个东西别忘了,就是大家最喜欢的箭头函数。
var a = 1
var test = () => {
console.log(this.a)
}
var obj = {
a: 2,
test
}
obj.test()
来,往上翻一下我们的第一个锦囊,“函数被调用时(即运行时)才会确定该函数内this的指向。”现在函数这两个字要加个词修饰一下,变成普通函数(非箭头函数)才能区别于箭头函数。箭头函数中的this在函数定义的时候就已经确定,它this指向的是它的外层作用域this的指向。
最后
我们最后还要说:“到此为止,真的没有了。”
希望看完这篇文章之后,再有人问this指向的问题,你可以嘴角微微上扬,冷笑一声:“不要再问我this的指向问题了。”
扬长而去。
JavaScript this 的指向问题的更多相关文章
- 图解javascript中this指向
JavaScript 是一种脚本语言,支持函数式编程.闭包.基于原型的继承等高级功能.JavaScript一开始看起来感觉会很容易入门,但是随着使用的深入,你会发JavaScript其实很难掌握,有些 ...
- javascript的this指向
JavaScript 是一种脚本语言,支持函数式编程.闭包.基于原型的继承等高级功能.JavaScript一开始看起来感觉会很容易入门,但是随着使用的深入,你会发现JavaScript其实很难掌握,有 ...
- JavaScript对象的指向问题
JavaScript对象的指向问题 标签(空格分隔): JavaScript 对象 在接触了JavaScript之后,我们常听到一句话就是一切皆对象,意思是说除了object以外,JavaScript ...
- JavaScript对象this指向(普通键this指向 非指向函数的键)
1.结论 JavaScript对象普通键(非指向函数的键)this指向是window. 2.示例 <!DOCTYPE html> <html lang="zh"& ...
- 图解javascript的this指向
图解javascript的this指向 作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... 以下就只有两张图,请放心食用!! #简版th ...
- javascript this关键字指向详解
在之前写代码的经历中,常常试过写着写着this就莫名其妙的不知道指向到哪里去了.今天看了曾探的javascript设计模式,里面特别谈到了this在不同情况下指代的对象,非常有意思. this指代的情 ...
- javascript this指针指向?
前言 理解javascript的指针就需要先了解js的执行环境和作用域!执行环境的定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,环境中定义的所有的变 ...
- javascript中this指向问题
本文参考http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html this是JavaScript的一个关 ...
- 从零开始学习前端JAVASCRIPT — JavaScript中this指向的四种情况
JavaScript中this的四种情况(非严格模式) 1.当this所在函数是事件处理函数时,this指向事件源.2.当this所在函数是构造函数时,this指向new出来的对象.3.this所在函 ...
- JavaScript 的 this 指向问题深度解析
与我们常见的很多语言不同,JavaScript 函数中的 this 指向并不是在函数定义的时候确定的,而是在调用的时候确定的.换句话说,函数的调用方式决定了 this 指向. JavaScript 中 ...
随机推荐
- lnmp 是不是该吐吐槽
lnmp 提供提供了便捷 , 并且手也伸的挺长的,它已不仅仅是个服务器环境那么简单 作为服务器继承环境来讲,可能每个人的认知程度不一,总之用了它需要服从它的规则 但从个人感觉上,其埋的坑还是让人不适, ...
- Python之匿名函数使用示例
#!/usr/bin/env python # -*- coding:utf8 -*- # #匿名函数 # y = lambda x:x+1 # print(y(10)) name = 'AK' #一 ...
- Python10之列表1(创建列表和列表添加元素的方法)
一.创建列表 列表名 = [’元素一‘,’元素二‘,’元素三‘,’元素四‘] 列表中的元素可以是任何类型,甚至可以是一个列表. list1 = ['詹姆斯','戴维斯','保罗乔治','字母哥',in ...
- 剑指offer22:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
1 题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 2 思路和方法 使用一个队列存放节点.先将根节点加入到队列中,然后循环遍历队列中的元素,遍历过程中,访问该节点的左右子节点,再将左 ...
- 在vue中使用ElementUI
完整引用ElementUI: 安装:在需要使用到的vue项目目录下,使用npm下载安装: npm/cnpm i element-ui -S/--save <!-- 引入样式 --> < ...
- "一起来捉妖"怎么从瘸腿中组合到最合心意的妖灵
背景: 最近两天活动,黑鬼白鬼合体觉醒秋容,陆无名,聂小倩,作为一个非土豪玩家,没有超高资质妖灵的我,想要在瘸腿妖灵中选取两个最佳选择,合体觉醒. 初选: 备选妖灵从5个维度录入数据,进行选择,分别为 ...
- Eclipse RCP难点:给Command传递参数(Object)
这个问题网络上没有答案,国外网站上也没有,本人研究了一天,终于搞明白如何实现,实际上是Eclipse RCP的ICommandService本身就已经提供的方法,只是网络上教的都是使用IHandler ...
- logback的使用和配置
参考:https://www.cnblogs.com/warking/p/5710303.html https://www.cnblogs.com 一.logback简介 1.logback: Log ...
- interface Part2(定义接口)
一. 在 C# 语言中,类之间的继承关系仅支持单重继承,而接口是为了实现多重继承关系设计的. 二. 一个类能同时实现多个接口,还能在实现接口的同时再继承其他类,并且接口之间也可以继承. 三. 无论是表 ...
- snort_inline
snort_inline Link http://snort-inline.sourceforge.net/oldhome.html What is snort_inline? snort_inl ...