js中this原理

问题的由来

js中一个很容易混淆的很难理解的点就是this的指向问题了,在面试环节this的出场率绝对在90%以上,所以今天来复习下this,探讨一下this的原理。
在很多时候我们会看到这样的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj={
foo:function(){
console.log(this.bar)
},
bar:1
}
var foo=obj.foo
var bar=2

//写法一
obj.foo()//1

//写法二
foo()//2

按照道理来讲obj.foo和foo指向的是同一个函数,但是为什么执行结果不一样呢?

这里就是老生常谈的this的指向问题了

在很多地方我们都会看到这样的说法,this指向的是函数运行时所在的环境(即执行上下文)。对于obj.foo()来说,foo运行在obj环境,所以this指向obj;对于foo()来说,foo运行在全局环境,所以this指向全局环境。所以两次的结果不一样。
这种解释没错,但是函数的运行环境到底是什么决定的?为什么obj.foo()执行环境是obj,foo()在全局环境执行?

内存的数据结构

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

1
var obj={foo:5}

上面的代码就一个对象赋值给变量obj。js会在内存里生成一个对象{foo:5},然后把这个对象的内存地址赋值给变量obj,也就是说遍历obj里面存储的是一个地址,要想兑取obj.foo的值,js引擎先从变量obj拿到地址,然后再从该地址读取出原始对象的内容,返回foo属性的值。

而原始的对象是以字典结构保存的,没一个属性都对应一个属性描述对象(内容,是否可写等)
alt

1
2
3
4
5
6
7
8
{
foo: {
[[value]]: 5
[[writable]]: true
[[enumerable]]: true
[[configurable]]: true
}
}

函数

上面的情况是对象的属性只是一个普通的数值,如果属性是一个函数呢?

1
2
3
var obj={
foo:function(){}
}

alt

这是js引擎会将函数单独保存在内存中,然后再将函数的所在的内存地址赋值给foo属性的value值。

由于函数是单独存放的值,所以它可以在不同的环境(上下文)执行

1
2
3
4
5
6
var f=function(){}
var obj={f:f}
//单独执行
f()
//obj环境执行
obj.f()

环境变量

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

1
2
3
var f=function(){
console.log(x)
}

在上面的代码中,函数体里面使用了变量X,该变量由运行环境提供。

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

1
2
3
4
5
6
7
8
9
10
11
12
var f=function(){
console.log(this.x)
}
var x=1;
var obj={
f:f,
x:2
}
//单独执行
f()//1
//obj环境
obj.f()//2

在上面代码中,函数f在全局执行,this.x指向全局环境的x
alt
在obj执行环境,this.x指向obj.x
alt

回到开头的问题,obj.foo()是通过obj找到foo,所以就是在obj执行环境。一旦var foo=obj.foo,变量foo就是直接指向函数本身,所以foo就变成在全局环境执行。


转载请注明: 前端无忧网 js中this原理

本篇
js中this原理 js中this原理
问题的由来js中一个很容易混淆的很难理解的点就是this的指向问题了,在面试环节this的出场率绝对在90%以上,所以今天来复习下this,探讨一下this的原理。在很多时候我们会看到这样的写法1234567891011121314var
2019-08-07 刘赛
下一篇
nodejs文件流操作 nodejs文件流操作
nodejs里面fs文件模块算是用的非常频繁了,常用的方法也非常多,其中readFile和writeFile就是读取文件和写入文件了。 123456789101112131415const fs=require("fs"
2019-07-22 刘赛