490 JS中关于THIS的五种情况分析

* THIS:
    全局上下文中的THIS是WINDOW;
    块级上下文中没有自己的THIS,它的THIS是继承所在上下文中的THIS的;【和箭头函数类似。】
    在函数的私有上下文中,THIS的情况会多种多样,也是接下重点研究的.
 *
 * THIS不是执行上下文(EC才是执行上下文),THIS是执行主体
 *    例如:刘德华拿着加了五个鸡蛋的鸡蛋灌饼去北京大饭店吃早餐(事情本身是吃早餐,刘德华吃早餐,这件事情的主体是刘德华【THIS】,在北京饭店吃,北京饭店是事情发生所在的上下文【EC】)
 *
 *
 * 如何区分执行主体?
 *    1. 事件绑定:给元素的某个事件行为绑定方法,当事件行为触发,方法执行,方法中的THIS是当前元素本身(特殊:IE6~8中基于attachEvent方法实现的DOM2事件绑定,事件触发,方法中的THIS是WINDOW,而不是元素本身)。
 * 
 *    2. 普通方法执行(包含自执行函数执行、普通函数执行、对象成员访问调取方法执行等):只需要看函数执行的时候,方法名前面是否有“点”,有“点”,“点”前面是谁,THIS就是谁,没有“点”,THIS就是WINDOW[非严格模式]/UNDEFINED[严格模式]。
 * 
 *    3. 构造函数执行(NEW XXX):构造函数体中的THIS是当前类的实例。
 * 
 *    4. ES6中提供了ARROW FUNCTION(箭头函数): 箭头函数没有自己的THIS,它的THIS是继承所在上下文中的THIS。
 * 
 *    5. 可以基于CALL/APPLY/BIND等方式,强制手动改变函数中的THIS指向:这三种模式是很直接很暴力的(前三种情况在使用这三个方法的情况后,都以手动改变的为主)。
// 事件绑定 DOM0  DOM2
let body = document.body;
body.onclick = function () {
	// 事件触发,方法执行,方法中的THIS是BODY
	console.log(this);
};
body.addEventListener('click', function () {
	console.log(this); // => BODY
});


// IE6~8中的DOM2事件绑定
box.attachEvent('onclick', function () {
	console.log(this); // => WINDOW
});


// ----------------------------------


// IIFE
(function () {
	console.log(this); // => window
})();


// ----------------------------------


let obj = {
	fn: (function () {
		console.log(this); // => window
		return function () {}
	})() //把自执行函数执行的返回值赋值给OBJ.FN
};


// ----------------------------------


function func() {
	console.log(this);
}
let obj = {
	func: func
};
func(); // => 方法中的THIS: WINDOW 【前面没有点,window调用func】
obj.func(); // => 方法中的THIS: OBJ【前面有点,obj调用func】


// ----------------------------------


// => 数组实例基于原型链机制,找到ARRAY原型上的SLICE方法([].slice),然后再把SLICE方法执行,此时SLICE方法中的THIS是当前的空数组
[].slice(); 
Array.prototype.slice(); // => SLICE方法执行中的THIS:Array.prototype
[].__proto__.slice(); // => SLICE方法执行中的THIS:[].__proto__ === Array.prototype


// ----------------------------------


function func() {
	// THIS  =>  WINDOW
	console.log(this);
}
document.body.onclick = function () {
	// THIS  =>  BODY
	func();
};


// ----------------------------------



function Func() {
    this.name = "F";
    // => 构造函数体中的THIS在“构造函数执行”的模式下,是当前类的一个实例,并且THIS.XXX = XXX是给当前实例设置的私有属性
	console.log(this); 
}

Func.prototype.getNum = function getNum() {
	// 而原型上的方法中的THIS不一定都是实例,主要看执行的时候,“点”前面的内容
	console.log(this);
};
let f = new Func; // Func {name: "F"}
f.getNum(); // Func {name: "F"}
f.__proto__.getNum(); // {getNum: ƒ, constructor: ƒ}
Func.prototype.getNum(); // {getNum: ƒ, constructor: ƒ}


// ----------------------------------


let obj = {
	func: function () {
		console.log(this);
	},
	sum: ()  =>  {
		console.log(this);
	}
};
obj.func(); // => THIS:OBJ
obj.sum(); // => THIS是所在上下文(EC(G))中的THIS: WINDOW
obj.sum.call(obj); // => THIS:WINDOW,箭头函数是没有THIS,所以哪怕强制改也没用  


// ----------------------------------


let obj = {
	i: 0,
	// func:function(){}
	func() {
		// THIS: OBJ
		let _this = this;
		setTimeout(function () {
			// THIS:WINDOW 回调函数中的THIS一般都是WINDOW(但是有特殊情况)
			_this.i++;
			console.log(_this);
		}, 1000);
	}
};
obj.func();


// ----------------------------------


let obj = {
	i: 0,
	func() {
		setTimeout(function () {
			// 基于BIND把函数中的THIS预先处理为OBJ
			this.i++;
			console.log(this);
		}.bind(this), 1000);
	}
};
obj.func();


// ----------------------------------


// 建议不要乱用箭头函数(部分需求用箭头函数还是很方法便的)
let obj = {
	i: 0,
	func() {
		setTimeout(()  =>  {
			// 箭头函数中没有自己的THIS,用的THIS是上下文中的THIS,也就是OBJ
			this.i++;
			console.log(this);
		}, 1000);
	}
};
obj.func();

猜你喜欢

转载自www.cnblogs.com/jianjie/p/13208292.html