关于环境对象this的学习,前面有一篇文章关于非箭头函数中this指向哪个对象的问题有描述过,这里是在做一个补充。
关于this的常见误解:指向函数对象自身,然而事实并非如此,可以看个例子:
function foo(num){
console.log("foo:"+ num)
this.count++
}
foo.count = 0
for(var i = 0; i < 10; i++){
if(i > 5){foo(i)}
}
console.log(foo.count)//0
console.log(window.count)//NaN
从运行结果是0来看,我们便可以推断出this并不是指向函数自身的。而且,在这里我们可以分析一下this指向谁。首先,寻找调用位置,接着查看调用方式,分析可得这里是普通调用,所以this指向全局对象。因此count值被泄露到全局作用域中去了。问题的关键是为什么count的值是NaN而不是10?答案就是因为count的初值是undefined啊。
当然,我们也可以强制使得this指向自身,利用call,apply,bind等方法可以达到这个目的,下面举例修改一下上面这个例子:
function foo(num){
console.log("foo:"+ num)
this.count++
}
foo.count = 0
for(var i = 0; i < 10; i++){
if(i > 5){foo.call(foo, i)}
}
console.log(foo.count)//4
** 如果使用严格模式的话,那么当使用普通方式调用一个非箭头函数的话,此时this并不会绑定到全局作用域,更确切的说是哪里都不绑定 **
function foo(){
"use strict"
console.log(this.a)
}
var a = 2
foo()//TypeError: this is undefined
完成下面几个例子来做个小测验:
function foo(){console.log(this.a)}
function doFoo(fn){fn()}//调用位置
var obj = {"a": 2, "foo": foo}
var a = "oops, global"
doFoo(obj.foo)//"oops, global"
例子2:
function foo(){console.log(this.a)}
var obj = {"a": 2, "foo": foo}
var a = "oops, global"
setTimeout(obj.foo, 1000)//"oops, global"
例子3:
function foo(something){this.a = something}
var obj1 = {}
var bar = foo.bind(obj1)
bar(2)//没有使用new操作符的情况
console.log(obj1.a)//2
var baz = new bar(3)
console.log(baz.a)//3
console.log(obj1.a)//2
例子4:
function foo(){console.log(this.a)}
var a = 2
var obj = {"a": 3, "foo": foo}
var p = {"a": 4}
obj.foo()//3
(p.foo = obj.foo)()//2
例子5:
function Fun(name){this.name = name}
var Bind = Fun.bind("window")
var obj = new Bind("bighai")
console.log(obj.name)//"bighai"
console.log(window.name)//undefined
分析,这里是一个硬绑定函数被当作构造函数的方式调用,所以环境对象this就是指向new出来的对象。这是规定呐。
END