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;