this指向

104 阅读3分钟

概念

在红宝书描述:“this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this执行window,而当函数作为某个对象的方法调用时,this表示那个对象”。加粗的文字相对来说有点抽象,下面来介绍下this在不同的情境下都表示啥。

this分类

我把this指向情况大致可以分为以下7种:

  • 普通函数的this
  • 作为对象的this
  • 构造器调用
  • DOM事件的this
  • 箭头函数的this
  • 严格模式下的this
  • call和apply修改的this

普通函数的this

当函数不作为对象的属性被调用时,这个函数我们就说是普通函数。在普通函数里,this总是指向全局变量(window)。

var name = 'zs';
var fn = function(){
    return this.name;
}
console.log(fn());   //zsvar obj = {
    name:"ls",
    getName:function(){
        return this.name
    }
}
var getName = obj.getName;
console.log(getName());   //zs
/*
	通过fn和getName函数来解析下“this对象是在运行时基于函数的执行环境绑定的”这句话:
	fn执行时调用fn函数的执行环境时window,所以this执行window,这个相信大家没问题
	var getName = obj.getName这句执行实际是把obj对象里面的函数复制一份给getName变量,此时等于
	var getName = function(){return this.name},这时getName是一个普通函数。getName函数的实际调用是window(console.log(getName()))。所以此时this应该执行window,所以打印出来是zs
*/

紧扣上面的概念,下面在来看些其他例子

//假设有个div,给div添加一个点击事件
<div id="div1"></div>
________________________
window.id = "window"
document.getElementById("div1").onclick = function(){
	console.log(this.id);  //此时表示调用的对象,既div元素
    //假设事件函数里面还有个函数
    var callback = function(){
    	console.log(this.id);   //window
    }
    callback()
}
//callback()被当作普通函数来执行,在普通函数中,this总是指向window的
——————————————————
//假设不想callback函数里里面的this指向全局,我们可以这样做
document.getElementById("div1").onclick = function(){
	console.log(this.id);  //此时表示调用的对象,既div元素
	var that = thisl;  //保存this
    //假设事件函数里面还有个函数
    var call = function(){
    	console.log(that.id);   //div1
    }
    call()
}

作为对象的this

当函数作为对象的方法调用时,this表示这个对象的实例

let obj = {
	name:'zs',
	getName:function(){
		console.log(this);  //obj
	}
}

构造器中的this

当我们使用new创建一个对象时,函数被当做构造器使用,默认情况下,构造器返回一个对象,这个对象就是this

let Obj = function(){
	this.name = 'zs';
	//return this;
}
let o = new Obj(); 
console.log(o.name) //zs

那么我们可不可以修改构造器的返回值呢,答案是可以的。当返回值是一个对象时,这时this并不是我们期待的this了

function Obj(){
	this.name = 'zs';
	return {
		name:'ls'
	}
}
let o = new Obj();
console.log(o.name);   //ls

但是如果构造器返回的不是一个对象呢,那么this还是我们期待的值,实例对象还是指向this

function Obj(){
	this.name = 'zs'
	return 'aaaa';
}
let o = new Obj()
console.log(o.name);  //zs

DOM事件的this

在onclick和addEventerListener中 this 默认指向绑定事件的元素,但是IE比较奇异,使用attachEvent,里面的this默认指向window。

箭头函数的this

箭头函数是没有this的,在箭头函数里面的this,当前最近的非箭头函数的this,如果都没有找到,最终指向window,严格模式下undefined

let obj = {
    a: function() {
        let b = ()=>{
            console.log(this)  
        }
        b();
    }
}
obj.a()
 // 找到最近的非箭头函数a,a现在绑定着obj, 因此箭头函数中的this是obj

严格模式下this

"use strict";
function fn(){
	console.log(this) //undefined
}
fn()

call和apply的this

call和apply的作用是用来修改this的指向的。这两者的区别在于传递的参数时不一样,call传递的参数必须是一个个展开的,apply传递的参数是用一个数组封装的

let obj = {
	name:"zs",
	getName:function(){
		console.log(this.name)
	}
}
let obj2 = {
	name:"ls"
}
obj.getName();  //zs
obj.getName.call(obj2);  //ls
obj.getName.apply(obj2);  //ls

参考

三元博客

曾探 JavaScript设计模式与开发实践