JavaScript 的 this 原理(精讲原理)

1.什么是this

定义:this是包含它的函数作为方法被调用时所属的对象
这句话有些绕,但是别着急,看完下面的文章,我们在回来看这句话

话不多说,看代码
	let obj = {
  		foo: function () {}
	};
    let foo = obj.foo;
    // 写法一
    obj.foo()
    // 写法二
    foo()

上面代码中虽然obj.foo()和foo()指向一个函数,但是执行结果可能不一样,请看下面的例子

	let obj = {
	  	foo: function () { 
	  		console.log(this.bar) 
	  	},
	 	 bar: 1
	};
   	let foo = obj.foo;
    let bar = 2;
    // 写法一
   	obj.foo()	//1
    // 写法二
    foo()		//2

为什么调用同一个函数,输出结果却不一样呢,请继续往下看

结果不一样的原因就是我们在函数内部使用了this关键字

 现在我们来分析一下上面的例子
 
 // 写法一
 obj.foo()  //1
 foo运行在obj环境,所以this指向obj
 
 // 写法二
 foo()  //2
 foo运行在全局环境,所以this指向window

网上很多教程会告诉你this指的是当前函数运行时所在的环境,这句
话没错,但是他们通常不告诉你为什么会这样,这篇文章就告诉你js这样
处理的原理,理解了这篇文章,你就会彻底理解this的作用

js之所以有this的设计,跟内存里面的数据结构有关系

2.内存的数据结构

ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型。
1.基本数据类型指的是简单的数据段,
2.引用数据类型指的是有多个值构成的对象。
3.当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值。

1.基本数据类型
Number、String 、Boolean、Null和Undefined。基本数据类型是按值访问的,
因为可以直接操作保存在变量中的实际值。
示例 :
let a = 10
let b = 'abc'
let c = true
let d = undefined

let e = a
e = 20
console.log(a); // 10值
上面e获取了a的值的拷贝,然后我们给e赋值为20,因为e的值是a的值的一份拷贝,
所以我们打印a的时候,输出的值还是10(这个地方对于初学者来说可能有点绕,
多看几遍,体味一下)
2.引用数据类型
1.也就是对象类型Object type,比如:Object 、Array 、Function 、Data等。
2.javascript的引用数据类型是保存在堆内存中的对象。
3.与其他语言的不同是,你不可以直接访问堆内存空间中的位置和操作堆内存
空间。只能操作对象在栈内存中的引用地址。

let obj = {
		a:1,
		b:function() {
			console.log(123)
		}
	}
let obj1 = obj

obj.c = '132'
console.log(obj1)	//{a:1,  b:function(){console.log(123)}, c:'123'}

下图图解

在这里插入图片描述

好,看到这里,我想大家对引用数据类型应该有一定的了解了

下面我们就来着重说明一下函数

注意: 函数是一个单独的值,所以它可以在不同的环境(上下文)执行。
我们就拿刚开始的例子来说

	let obj = {
	  	foo: function () { 
	  		console.log(this.bar) 
	  	},
	 	 bar: 1
	};
	
	可以看成
	let obj = {
		foo: '函数的引用地址', //这个引用地址指向真的的fun函数
	    bar: 1
	}
	函数是一个单独的值,所以它可以在不同的环境(上下文)执行

  	foo()	//单独执行

 	obj.foo()	//执行环境执行
环境变量

JavaScript 允许在函数体内部,引用当前环境的其他变量。

	var f = function () {
	  console.log(x);
	};
	上面代码中  变量x由运行环境提供

由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

	var f = function () {
	  console.log(this.x);
	};
	let obj = {
	  	foo: function () { 
	  		console.log(this.bar) 
	  	},
	 	 bar: 1
	};
   	let foo1 = obj.foo;
    let bar = 2;
    // 写法一
   	obj.foo()	//1
    // 写法二
    foo1()		//2
    
    我再来看最开始的这个例子
    1.写法一
    foo函数是经过obj调用的,是在obj环境运行的,所以this指的是obj环境
    2.写法二
    先把obj中foo函数的引用交给变量foo1,然后在全局环境下,执行这个
    拿到foo函数引用的变量foo1,所以this指的是全局环境
   

这里需要注意一点:加括号为调用该函数,返回值为函数返回值; 不加括号可认为是查看函数完整信息,即查看整个函数体,返回值即整个函数体

看到这,我们在回头去看本文刚开始的第一句话

this是包含它的函数作为方法被调用时所属的对象
把这句话分成三部分分别代入我们上面的例子中去
1.this是包含它的函数
2.作为方法被调用时
3.所属的对象

参考

阮一峰老师的 《JavaScript 的 this 原理》

        

结尾

希望大家看了本篇文章都有收获 …
如果文章有什么不对的地方,请斧正,感谢大家
新手一个,大佬勿喷,感谢

        

转载请注明出处,再次感谢
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值