js中this的理解
关于this
- this并不是指向函数本身。
- this在任何情况下都不指向函数的词法作用域。
- this是在运行时进行绑定的,而并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。
- this的绑定和函数声明的位置没有任何关系,只取决与函数的调用方法。
this的绑定规则
this到底绑定或者引用的是哪个对象环境决定于函数被调用的地方。而函数的调用有不同的方式,在不同的方式中调用决定this引用的是哪个对象是由四种规则确定的。
1、默认绑定
这条规则是最常见的,也是默认的。当函数被单独定义和调用的时候,应用的规则就是绑定全局变量window(严格模式下是undefined)。即没有其他绑定规则存在时的默认规则。
function fn() { console.log( this.a ); } var a = 2; fn(); // 2 -- fn单独调用,this引用window
为什么说这里应用了默认绑定呢?
因为fn()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。
2、隐式绑定
隐式调用的意思是,函数调用时拥有一个上下文对象,就好像这个函数是属于该对象的一样。必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接(隐式)绑定到这个对象上。
function fn() { console.log( this.a ); } var obj = { a: 2, fn: fn }; obj.fn(); // 2 -- this引用obj。
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
需要说明的一点是,最后一个调用该函数的对象是传到函数的上下文对象,对象属性引用链中只有上一层或者说最后一层在调用位置中起作用,如下:
function fn() { console.log( this.a ); } var obj2 = { a: 42, fn: fn }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.fn(); // 42 -- this引用的是obj2.
如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
隐式丢失问题:被隐式绑定的函数会丢失绑定对象,也就是说它会默认绑定,从而把this绑定到全局对象或undefined上,取决于是否是严格模式。如下:
function fn() { console.log( this.a ); } var obj = { a: 2, fn: fn }; var bar = obj.fn; // 函数引用传递,只是函数的别名,而不是调用这个函数 var a = "全局"; // 定义全局变量 bar(); // "全局"
3、显式绑定
使用bind()\apply()\call()函数:它接收的第一个参数即是上下文对象并将其赋给this
function fn() { console.log( this.a ); } var obj = { a: 2 }; fn.call( obj ); // 2
如果我们传递第一个值为简单值,那么后台会自动转换为对应的封装对象。如果传递为null,那么结果就是在绑定默认全局变量,如:
function fn() { console.log( this.a ); } var obj = { a: 2 }; var a = 10; fn.call( null); // 10
4、new绑定
如果是一个构造函数,那么用new来调用,那么绑定的是新创建的对象,如下:
function fn(a) { this.a = a; } var bar = new fn( 2 ); console.log( bar.a );// 2
当this碰到return时
如下代码:
function fn() { this.user = '追梦子'; return {}; } var a = new fn; console.log(a.user); //undefined
function fn() { this.user = '追梦子'; return function(){}; } var a = new fn; console.log(a.user); //undefined
再如:
function fn() { this.user = '追梦子'; return 1; } var a = new fn; console.log(a.user); //追梦子
function fn() { this.user = '追梦子'; return undefined; } var a = new fn; console.log(a.user); //追梦子
总结:
- 如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
- 还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
function fn() { this.user = '追梦子'; return null; } var a = new fn; console.log(a.user); //追梦子