陌上寒

陌上寒个人博客

谈一谈javascript中的this

这是javascript作用域系列文章,感兴趣的同学请保持关注。

this

我们几乎每天都在和this打交道,先不去管他的概念,看一个小栗子,预热一下

this初探

⚠️约定:
我们之前的一篇文章提到过,使用let和const声明的变量没有挂载到全局变量下,所以在全局下声明的变量我们使用var

var heroName = '黄蓉'
function hero() {
  const heroName = "黄药师"
  console.log(this)//window
  console.log(this.heroName);//=>黄蓉
}

hero()

我们执行hero(),通过打印我们发现

this指向的是window全局,所以this.heroName,应当在全局下查找heroName,所以输出=>黄蓉
当全局下没有heroName呢?this指向的是全局,全局没有就是没有,那就是undefined

function hero() {
  const heroName = "黄药师"
  console.log(this)//window
  console.log(this.heroName);//=>undefined
}

hero()

我们继续看一个栗子

var heroName = '黄蓉'
function hero() {
  const heroName = "黄药师"
  console.log(this)//oHero
  console.log(this.heroName);//=>欧阳锋
}
const oHero={
  heroName:'欧阳锋',
  hero
}
oHero.hero()

提示:在声明oHero中的hero中,使用了ES6标准,当key和value同名是,可以像上面这样简写
上面的栗子中,调用hero()的环境变了 ,根据输出我们发现,this的指向变了
this的指向是oHero对象,所以this.heroName=>欧阳锋,同样的当oHero下没有heroName,毫无悬念,就会输出=>undefined
如果前面两个小栗子搞懂了,我们就继续
一个栗子

var heroName = '黄蓉'

function hero() {
  console.log(this.heroName);
}
const oHero1 = {
  heroName:'郭靖',
  hero
};

hero()//=>黄蓉
oHero1.hero()//=>郭靖

现在我们尝试着给this下一个定义:

this指的是函数运行时所在的环境,如果一个函数内部有this,this就会指向一个对象,指向哪个对象呢?取决于这个函数的执行环境。
补充(如果在全局下调用这个函数,则this指向全局,如果在某个对象下调用this,则this指向这个对象)
能看到这里,说明你很聪明,哇,this这么easy吗?

this并没有那么简单

再看一个栗子

var heroName = '黄蓉'
function hero1() {
  const heroName = "黄药师"
  this.hero2()
}
function hero2() {
  console.log(this.heroName);
}
hero1()

先不关心输出
我们在hero2中的console.log前加一个debugger,分别看下两个this的指向
《谈一谈javascript中的this》

《谈一谈javascript中的this》

可以发现。两个this均指向window
在脑中跑一遍这段代码,希望你还清醒
我们一起捋一下:
全局下执行hero1()
在hero1中,this指向的是全局=>window, 全局下存在hero2(),
在hero2中,this指向哪里?取决于是哪里调用的hero2(),是在hero1()中调用的hero2(),
所以hero2中的this指向hero1?输出=>黄药师?
但是我们通过debugger得出,hero2中的this指向的是window,所以输出必然是=>黄蓉
为什么呢?
我们再看一个栗子

function hero(){
  console.log(this.heroName);
}
var HERO1 = {
  heroName : '黄蓉',
  hero
}
var HERO2 = {
  heroName : '郭靖',
  HERO1
}
var HERO3 = {
  heroName : '郭靖',
  HERO2
}
HERO3.HERO2.HERO1.hero()//=>黄蓉

我相信不会有人写出这样的代码,除了我!
这依然是个调用链
我们在输出前打一个断点
《谈一谈javascript中的this》
this指向了谁?不是最初的调用方HERO3,而是上一次,或者所最后一次=>HERO1

this似乎也不难

出现上面这种情况,是由函数调用方式决定的

  1. 作为一个函数进行的调用
  2. 作为一个对象的方法进行的调用
    3. 作为构造器进行的调用
    4. 通过apply()、call()函数进行的调用

后面两个暂不做讨论
作为一个函数调用this指向window,作为一个对象的方法调用,this指向当前调用的对象
回顾之前的栗子

var heroName = '黄蓉'

function hero() {
  console.log(this.heroName);
}
const oHero1 = {
  heroName:'郭靖',
  hero
};

hero()//=>黄蓉
oHero1.hero()//=>郭靖

hero(),是作为一个函数进行调用的,所以this指向window
oHero1.hero(), 是作为一个函数的方法调用的,所以this指向oHero1对象
继续看一个栗子

function hero1(){
  this.hero2()
}
function hero2(){
  console.log(this.heroName);//Uncaught TypeError: this.hero2 is not a function
}
var HERO1 = {
  heroName : '黄蓉',
  hero1
}
var HERO2 = {
  heroName : '郭靖',
  HERO1
}
HERO2.HERO1.hero1()

报错了
HERO1对象下调用的hero1(),所以hero1()中this指向的是HERO1,但是HERO1中不存在方法hero2(),所以报错
稍作修改

function hero1(){
  HERO3.hero2()
}
function hero2(){
  console.log(this.heroName);//=>郭靖
}
var HERO1 = {
  heroName : '黄蓉',
  hero1
}
var HERO2 = {
  heroName : '郭靖',
  HERO1
}
var HERO3 = {
  heroName : '郭靖',
  hero2
}
HERO2.HERO1.hero1()

我们似乎总结出来一点小窍门,我们从最后的输出反推执行顺序
是谁调用的hero2(),是HERO3,所以hero2,中的this指向HERO3,所以输出是=>郭靖
啊?this好简单?真的吗?关于下次的讨论,敬请期待

END

发表评论

电子邮件地址不会被公开。 必填项已用*标注