javascript函数自执行里的this为什么指向window

JavaScript010

javascript函数自执行里的this为什么指向window,第1张

this关键字代指当前对象。未必仅指window.

比如:

<body>

<form onsubmit="return checkform(this)">

<input type="text" name="txtbox" />

<input type="button" value="button" onclick="callme(this)"/>

<input type="submit" value="submit" name="btnsubmit"/>

</form>

</body>这里的this指当前的form。

在checkform函数中就可以这么写:

function checkform(form){

     if(form.txtbox.value == ""){ alert("no data") return false }

}

在type="button"中,callme函数中的this,代表当前的button对象。

在javascript中写callme函数:

function callme(o){

    alert(Object.prototype.toString.call(o)) //结果显示:[object HTMLInputElement]

}

再试着运行这一段:

window.onload = function(){ callme(this)  } //结果显示:[object Window],这里的this才是指window

再试着运行这一段:

var m = {

    callme: function(){

        alert(Object.prototype.toString.call(this))

    }

}

window.onload = function(){ m.callme(this)  } //结果显示:[object Object],这里的this是指对象m,

这是一个文字表述起来很麻烦的问题,解释之前先记住一下几点:

Point 1 : 使用 var 声明一个变量,变量声明会被提前到作用域最的最前面,也就是说无论你在什么地方 var 一个变量,这个变量都在代码一开始就被声明了,在函数内声明的变量也是如此

Point 2:所有的函数在被当做函数执行的时候,this 都指向 window(global),ES6除外

然后说你的那段代码:

定义了一个全局的 num = 1;

定一个 obj,并且有一个属性 num = 2

obj 有一属性 fn,fn 的值是通过自动执行函数返回的 function

自动执行函数构成了一个闭包

以上是几个关键的点,下面解释一下 fn :

根据 上文 Point 1 和 Point 2 来看,实际上 fn 的代码等价于下面的代码:

fn : ( function() {

    var num // 根据 Point 1,num 在函数中的声明被提到最前

    window.num += 10 // 根据上文 Point 2,函数在自动执行过程中,this 指向的是 global

    

    num = num + 10 // num 被声明,但是没有赋值,所以 num == undefined,所以 num + 10 会是 NaN

    

    num = 3 // num 被赋值为 3

    

    return function() {

        

        this.num += 10

        

        num++ // 这个作用域内没有 num,但是因为形成了闭包,所以这个 num 是外层函数的 num,就是被赋值成了 3 的那个。

        

        console.log( num )

    

    }

} )()

下面看你执行的代码:

var fn=obj.fnfn()

num 初始值是3, 所以 num++ 是 4,同时 fn 被以普通函数来执行,所以里面的 this 指向 window,this.num 改变的是最外层 num 的值,最外层的 num 这时候等于 21 了(在函数自动执行的时候还 + 过10)。

obj.fn()

再执行一次 num++ 值是 5,fn 是被作为 obj 的属性执行的,所以 fn 里面的 this 指向的是 obj.num,所以 obj.num 等于 12

console.log( num ) 

这个 num 是最外层的 num。

console.log( obj.num )

这个没什么需要说的了。

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;