对于js基础不是很好的我,一直不太懂this的指向问题。要搞懂这个还是得多动手。
首先,我们知道
1.函数被调用时可以确定该函数内this的指向。因为函数中的this和arguments时两个特殊的变量,在函数被调用时才会取得他们,而搜索着两个变量时只会在活动变量中找。
2.确定函数被调用的位置,从而确定函数中this的指向。
以下是常见的几种形式
第一种
var i=1;
function test(){
console.log(this.i);
}
test(); //直接调用,指向window
在控制台输出:1。
这种不带任何对象去调用test()函数的,指向全局变量,即是默认下this指向全局对象(浏览器的window)。
第二种
var i = 1;
function test(){
console.log(this.i);
}
var obj = {
i:2,
test()
}
obj.test(); //obj调用函数,指向obj
在控制台输出:2.
这时在test()函数前有对象,很显然this已经嫁给这个obj了,所以输出obj里i的2。也就是谁去调用这个函数,这个函数的this就绑定在谁的身上。多级调用的话就指向直属对象,eg:obj1.obj.test();this也是绑定obj的。
但是如果这样:var test1 = obj.test; test1();这时候神奇的输出了i为1。为什么呢?
我们知道函数的调用有1.func(x1,x2),2.obj.func(x1,x2),3.func.call(contsex,x1,x2)这三种。其实前两种都可以转换为第三种
func(x1,x2)转换为func.call(undefined,x1,x2),abj.function(x1,x2)转换obj.func.call(obj,x1,x2)。可以看出this其实就是你call一个函数传入的第一个参数。而第一种时传入undefined,浏览器默认下会把undefined和null都转为window。
所以test1()转成test1.call();这时候可以把上面提到的test1()调用改为test1.call(obj);这时候又会输出i为2。
一开始我也很疑惑,不是obj.test赋给test1了吗?可以console.log(test1)看一下,它输出了test这个函数体,那直接test1()就是直接test()。
test.call(x)/test.apply(x)/test.bind(x)三种函数调用是有点区别的
call和apply的时候输出没什么区别,只是传参有点区别,而当我改成bind时,我用谷歌调试就不输出了,好似是bind直接把参数改了。
第三种
var i = 1;
function test (i){
this.i = i; //这里的this指将要被new出来的新对象
}
var j = new test(2);
console.log(j.i);
这种采用new操作符,创建了一个新的对象,而被new的test(),称之为构造函数,而构造函数可以定义一下将要到来的新对象的一些属性,而这个将要到来的新对象就是用this来指示。
这里输出j,console.log(j)会得到
test {i: 2}
i: 2
可以看出j就是这个新对象。
第四种
可以说是普通函数和箭头函数的区别。
上面说到对象调用函数时,this指向对象(obj.test())。
但在箭头函数中这个不适用。
var i = 1;
var test = () =>{
console.log(this.i); //this指向它的外层作用域的this的指向,即window
}
var obj = {
i:2,
test
}
obj.test();
上面代码输出i的值为1。
箭头函数在定义的时候就已经确定,它this指向的是它外层作用域的this的指向。
至此,写完。