javascript中this关键字原理和用法

this关键字

在js中经常能看到各种this,this的理解对初学者有难度,如果弄不明白会寸步难行。网上针对this的解释千篇一律,很多人看了依然懵逼。本文将结合案例和自己的理解来解释this。文章不是教材,会存在口语化,类比的解释,目的是让读者看的更明白。nodejs和chrome环境中运行的结果有差异,会单独指出来。

面向对象

先以java为基础解释面向对象。new一个对象并执行可分为以下几个步骤:

  1. 定义一个class
  2. 以class中main方法为入口,然后再定义其他方法如method()
  3. new 一个对象为obj,然后obj.method()

典型代码如下:

public class Person{
    public static void main(String[] args) {
        Person obj = new Person();
        obj.method();
    }
    public void method(){
        System.out.println("Hello World");
    }
}

面向对象的基本用法是new一个实例,也就是对象出来,然后对象就可以调用这个类中定义的方法method。基本语法是obj.method(),我们把这个作为学习js中this关键字的主线。

obj.method()

js语法借鉴了java,是面向对象的编程语言,虽然继承是基于原型来设计的,但obj.method()的思路同样适用于js。
大家平时看到的最基础this使用场景是这样的:

let person = {
    name:"alice",
    show:function(){
        console.log(this);//person对象自己
    }
}
person.show();

执行show方法时,this就是person对象,换句话说就是哪个对象在执行方法,符合obj.method(),对象调用方法执行,方法中的this就是对象obj自己。上述代码在nodejs和chrome运行结果相同。

chrome中方法定义

console.log(this);//nodejs环境中为空对象{},chrome中为window对象
function show(){
    console.log(this);
}
show();//nodejs中为global对象,chrome中还是window对象

在nodejs中this和global不一样,这个要注意。global对象描述的是nodejs环境信息,也可以理解为是nodejs的自我简介。在这个代码的背后,nodejs是在极不情愿的情况下才返回的global对象,它其实是想返回undefined未定义的。换个理解思路,就是nodejs返回global对象是一个兜底的,不得已的选择。如果在代码首行开启严格模式"use strict",返回的就是undefined。早期js存在设计缺陷,它不是一个完整的编程语言,现在js发展起来有资格说话了,但为了兼容老代码才给了一个兜底的global。如果在chrome中,这个兜底的this就是window对象
上述代码2~4行定义了show方法,如果这3行代码在chrome运行,chrome实际会把这个方法放进this,也就是window对象中。this.show是定义定义,this.show()是方法在执行,是符合obj.method()的。即使此时直接使用show(),show前面不加任何东西,还是相同的结果。因为show前面的this或者window被隐藏了,它始终都符合obj.method()的。

在这里插入图片描述

nodejs中方法定义

但这个定义show的方法放在nodejs中会怎么样?也会放进this或者global对象中吗?答案是都不会,因为this.show和global.show都是undefined。在nodejs中定义了show方法,然后执行show(),这其实是一个裸方法(自己给起的名字,不要较真),不符合obj.method()。针对这种裸方法,它是没有this的,它就应该返回undefined(开启严格模式)。没开启严格模式,nodejs会给个兜底的global对象。这样就解释了同样的代码,在不同环境下的运行差异。看是否符合obj.method(),和兜底的this不同,nodejs兜底的this是global,chrome兜底的是window。

apply、bind、call

前面提到了obj.method(),对象obj在方法左边。如果是裸方法method()执行,method方法里的this就会被兜底的global或者window取代。js中引入call、apply、bind关键字,就是为了将裸方法拉回来,强行给一个obj。
method.call(obj),method.apply(obj),method.bind(obj)()
obj由开始的在左边,现在变为右边了。bind返回的是函数,因此还要单独加个括号表示执行

案例解析

案例1

var x = 1;//chrome中,本质是this.x = 1或者window.x=1;
          //nodejs,就是一个普通变量,既不在this中,也不在global中
function test() {
   console.log(this.x);
}
test();  // nodejs结果为undefined,因为是裸方法,test方法中的this就是兜底的global,
//但global中又没有x字段,只能undefined。
// chrome中运行结果为1,因为实际执行的是this.test(),符合obj.method(),这里this就是window,
//而第一行代码中也提到了window.x就是1。这个window是合法合理的,和用来兜底的window对象不要混为一谈,
//兜底的window对象是给裸方法准备的,是为实在找不到this准备的,这里不是裸方法。

案例2

var obj = {
    bar: 1,
    foo: function () { console.log(this.bar) }
};

var foo = obj.foo;//obj.foo是方法引用,简单点说就是把原本在obj对象中的方法单独捞出来了
var bar = 2;//chrome中就是this.bar = 2或者window.bar = 2
            //nodejs中就是普通变量,不在this或者global对象中

obj.foo() // 1 符合obj.method(),自然就是1
foo() //   前面把方法捞出来了,这里要执行
        //nodejs中就是裸方法执行,this就是兜底的global对象,而global对象又没有bar字段,故返回undefined;
        //chrome中实际执行的是this.foo(),符合obj.method(),this为window对象,而bar就在window对象中,
        //故返回2;

待更新,后面会引入箭头函数作为案例

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值