this到底指向哪里?
当然,大多数人都是对“this”的字面意思有些误解,例如,通常会理解成this指向函数自身,毕竟英语解释是如此。
下面我们看个例子:
function foo(num){ console.log("foo:" + num); this.count++; } foo.count = 0; for(i = 0;i<5;i++){ if(i>2){ foo(i); // foo:3; foo:4; } } console.log(foo.count); //0
console.log语句产生了 foo:3 foo:4 两条语句,被调用了两次,为什么打印输出 foo.count仍然为0?
首先要明白,this既不指向函数自身也不指向函数的词法作用域;实际上是在函数被调用时发生的绑定,它指向什么只取决于在哪里调用函数。
在控制台打印便知:
function foo(num){ console.log(this);//Window console.log(this.count);//2 } foo.count = 0; var count = 2 foo();
在全局变量里定义了一个count = 2;在foo()里打印this.count输出结果为2;同时也打印了this,输出为window,也就说this绑定在window(全局里)下面,为什么?
这样我们就需要讨论一下函数的调用位置如果决定this的绑定对象
如何找调用位置呢?想要找到调用位置,就需要先分析调用栈(从开始到执行位置所调用的所有函数) 我来引用下《你不知道的JavaScript》里的例子
var a = "vv"; var baz = function(){ //当前调用栈:baz //当前的调用位置时全局作用域 var a = "aa"; console.log(this.a); //vv bar(); } var bar = function(){ //当前调用栈:baz--> bar //当前的调用位置是baz中 var a = "bb"; console.log(this.a);//vv foo(); } var foo = function(){//当前调用栈:baz--> bar -->foo //当前的调用位置是bar中 var a = "cc"; console.log(this.a);//vv } baz(); //baz调用位置
分析出真正的调用位置,就能照出this的绑定位置,所以这个例子中this的指向是全局变量中的a,而不是函数里的a。
默认绑定规则方式我们上面说的好多,简单地将,就是foo()直接使用而不带任何修饰的函数引用进行调用时,无法应用其他规则。
什么叫做不带任何修饰的函数引用调用?
别急...看到下面就知道了
希望不要晕了。
对象函数调用时,那个函数调用this就指向那个对象
var name = "window"; var obj = { "name":"john", "sayHello":function(){ console.log(this); //指向obj console.log(this.name+":Hello world!"); //john:Hello world! } } obj.sayHello();
sayHello()这个函数被obj引用,当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象中,所有调用sayHello()函数时被绑定到obj。
是不是觉得函数写在对象里,obj肯定绑定的啦~
var name = "window"; var sayHello = function(){ console.log(this); //指向obj console.log(this.name+":Hello world!"); //john:Hello world! } var obj = { "name":"john", sayHello:sayHello, } obj.sayHello();
注意,是对象函数,而不是函数,在函数里是需要找到this的绑定位置,而在对象属性引用链中,只有最后一次的调用位置中起作用
不多说,例子奉上
var name = "window"; var sayHello = function(){ console.log(this); //指向obj2 {name: "john", sayHello: ƒ} console.log(this.name+":Hello world!"); //john:Hello world! } var obj2 = { "name":"john", sayHello:sayHello, } var obj1 = { "name":"jack", obj2:obj2, } obj1.obj2.sayHello();
在刚才几个例子中,你们肯定疑惑,在对象里面包含一个指向函数的属性,为什么?
因为需要这个属性间接引用函数,然后利用隐式规则间接的绑定到这个函数上,在调用函数时前面会有obj进行"修饰",可以说函数被obj对象引用或调用。
如果你喜欢强制调用函数的,不想这么麻烦的在对象里引用或者调用的话,那你就需要用到一个方法 call()
function sayHello(){ console.log(this.name); //john } var obj = { name:"john" }; sayHello.call(obj);
这样,我么就可以调用 函数的时候流氓的把它的this绑定到obj上
ES6中的箭头函数并不会使用以上的绑定规则,而是根据当前的词法作用域来觉得this。
简单地说,就是箭头函数里的this是指向外层函数调用的this绑定,如果没有外层函数,就指向window
例子:箭头函数常用于定时器
var name = "window"; var sayHello = function(){ console.log(this); //指向Object setInterval(()=>{console.log(this.name)},1000);//john } var obj = { "name":"john", } sayHello.call(obj);
箭头函数的外层函数被绑定到obj中,this指向也随之指向obj;
var name = "window"; var sayHello = ()=>{ console.log(this); //指向window setInterval(()=>{console.log(this.name)},1000);//window } var obj = { "name":"john", } sayHello.call(obj);
这段代码中,箭头函数没有外层函数,即使绑定在对象里,this仍然指向window,因为箭头函数是根据外层(函数或者全局)作用域决定this的指向。
以上是我对this的理解,如有不对,请您指出,一起学习,共同进步,谢谢!
学习中···ES5和ES6this的用法(先记录,有新的收获再补充)
原文:https://www.cnblogs.com/kongVv/p/11283746.html