js中的this原理

JavaScript07

js中的this原理,第1张

this 指的是 函数运行时 所在的环境。(不是定义时所在的环境)

怎么理解这句话呢?看如下例子:

在这个例子中,首先第一个输出,因为wFunction是运行在全局环境中,所以 this 指向全局环境,所以输出1;第二个输出,因为wFunction运行在wObj环境中,所以 this 指向wObj,而wObj的w属性值为2,所以输出2;

那么问题来了,为什么第二个说是在wObj环境中运行呢,运行环境是怎么来判别的呢?这得从内存的数据结构说起。

首先,是考虑到内存的数据结构,才设计这个this的。那内存的数据结构是怎样的呢,先看个例子:

这里,javaScript引擎会在内存里先生成一个对象{w:5},然后把这个对象的内存地址(reference)赋值给wObj变量。

如果通过wObj.w来读取这个对象的属性w,则引擎会先从wObj这个变量拿到对象的内存地址,然后从该地址读出这个对象,返回w属性。

在看下面一个例子:

这里,javaScript引擎会先将函数function(){...} 单独保存在内存中 。然后javaScript引擎会在内存里生成一个对象{wFunc:wFunction},而wFunction则是函数的内存地址(reference)。然后把这个对象的内存地址赋值给wObj变量。

如果通过wObj.wFunc()执行函数,则引擎会先从wObj这个变量拿到对象的内存地址,然后从该地址读出这个对象,返回wFunc属性,而wFunc属性的值是函数function(){...}的内存地址(reference),因为这个 是单独的一个值,所以可以在不同环境(上下文)执行 。在这里函数是通过wObj找到的(wObj的属性wFunc),所以在wObj环境中执行的。

这里解释了为啥函数是可以在不同的环境中执行。那么问题来了,这动态的执行环境,怎么获取呢?

针对获取执行环境问题, this 就这么设计出来了,它的设计目的就是在函数体内部,指代函数 当前的运行环境

回到文章开头例子,并加以深化如下:

第一个输出,函数执行时,是通过全局变量wFunction找到函数引用地址的,它的执行环境则是全局,因此输出全局w,为1;

第二个输出,函数执行时,是通过wObj指向的对象里的wFunction属性找到的函数引用地址的,因此,它的执行环境则是wObj指向的对象,因此输出对象的w,为2;

第三个输出,函数执行时,是通过全局变量wObjFunc找到函数引用地址的,(因为let wObjFunc = wObj.wFunction这直接把函数的引用地址直接赋给了全局变量wObjFunc,所以wObjFunc直接指向函数本身)它的执行环境则是全局,因此输出全局w,为1;

第一个this.name指的是变量name(对应var name="The Window"这个),

第二个this.name指的是object这个map里面的name,this指的是object这个map对象。

this是Javascript语言的一个关键字它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,下面分四种情况:

情况一:纯粹的函数调用 :这是函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。

情况二:作为对象方法的调用 :函数还可以作为某个对象的方法调用,这时this就指这个上级对象。

情况三 作为构造函数调用 :所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。

情况四 apply调用 :apply()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。

一般this出现在函数里时,只有在函数执行时才能确定this是什么,因为this是指那个调用这个函数的对象。比如说有如下方法:

function test(){

alert(this.length)

}

则,如下调用:

var str = new String(“test”)

str.test = test

str.test()

此时的this就是字符串str,则调用过程弹出this的长度,实际就是弹出这里的str的长度,所以结果是4.

而如果是下面的调用:

var arr = new Array(1,2,3,4,5,6)

arr.test = test

arr.test()

则这里的this就是arr这个数组,相应的弹出的就是数组arr的长度,也就是6.

而当没有对象来调用这个函数,即直接调用时,如下:

test()

因为在js中,全局的定义默认都是window的属性或对象,所以这里的调用,实际上是如下调用:

window.test()

window的length为0.则弹出的就是0.如果你定义了一个length,比如如下调用:

var length = 10

test()

则弹出的就是10了。因为全局的定义一个length,实际相当于给window添加或重写了一个属性length。