我的this见解

关于this, 现在应该有很多文章提到了它,它在JavaScript里的作用特别明显,几乎一写到js,基本会用到this了,尤其是面向对象的时候。


在我看来,this往往和原型链、作用域扯上关系,又有所区别。

比方说作用域下访问变量这回事:

var a = 1;
function b(){
  var a = 2;
  console.log(a);// 2
}
b();
console.log(a);//1

这段很简单的代码透露着作用域的信息,在JavaScript里,并没有块作用域这个概念,有别于java等语言(当然es6开始就有了)。

上面代码里如果functionvar a = 2;注释掉,那么里面访问a变量会是这么一个顺序,先看一下function里面有没有声明变量a,有就拿来,没有,那就往上一层看是否有a,没有就继续往上,直到到了global, 浏览器下是window,示例代码就两层,所以会发现a=1,这就是作用域的一个访问过程。

但是,对于this,就不能这么搞了,应该有两个属性要特别注意,即 thisarguments,后者表示function的参数对象(类数组,但具有一些其他方法);


this的概念可以参考 MDN

文章里描述的this有很多情况,但在实际应用中,其实我觉得可以理解为一种情况,即当你使用this的时候,你只要知道这个this是哪个对象调用它的,那它就代表哪个对象了~谁调用谁负责,找TA就对了~

var a = 1;
console.log(this.a);//1
function b(){
  console.log(this.a);
}
b();// 1
var c = {
  a:2
};
b.call(c);//2
b.bind(c)();//2

上述例子,一般而言,但找不到代码的调用对象是谁时,一般是最上层,即浏览器的window,or node下的global(后者我不熟)

一般来在浏览器下,直接var a = 1;其实可以当做是window.a = 1;,而在window下访问this,当然就是window了,所以第一个输出是1;

而我们知道,一般的function,其实它是window.b,自然里面的this指向的是window了。

call以及apply方法,他们将function绑定到某个对象上去使用,相当于这个对象拥有了这个方法,并且调用执行了。那么此时function里面的this就是指向绑定的对象咯,也就是示例里的c.

es5还有个bind方法,可以将function绑定到某个对象上作为一个新方法,差不多跟jqueryproxy方法一样,生成一个新的方法(带绑定对象的),此时新方法里的this就指向了bind的那个对象了。


怎么用?

只要弄清楚this的调用对象,就很好办了。

我以往经常用到,也在各种js代码里看到,比如说类数组 arguments, 它不是数组,但它似数组,那我想用数组的api行不?

可以,如下:

 function d(hello, world){
 	console.log([].slice.call(arguments));
 }

这样就让类数组对象可以用上数组的slice方法了.

还有更妙的,在我看jquery源码的时候, 对promise的链式一知半解。

//promise.done 源码
jQuery.each( tuples, function( i, tuple ) {
	var list = tuple[ 2 ],
		stateString = tuple[ 3 ];

	// promise[ done | fail | progress ] = list.add
	//list指的是Callbacks
	promise[ tuple[1] ] = list.add;
 //省略
 });

//Callbacks的一段代码
self = {
	add: function() {
		//省略
		return this;
	},
	//省略
}

表面上看Callbacks的实现,add方法属于self,但实际上,通过promise[ tuple[1] ] = list.add; 已经将这个方法赋值到promise那边了,当promise在调用done方法的时候,在add方法这边返回的this,指向的其实就是调用方(promise),所以可以继续链式调用。

有了thiscallbind等方法,使得function的自由度更广,我不需要考虑封装的时候把所有方法写死到一个类里,只要活用this, 同样可以共享api~