33:综合专题之THIS的五种情况2(重写内置的CALL、APPLY、BIND)

THIS5:基于call/apply/bind可以改变函数中this的指向(强行改变)

01.CALL/APPLY
第一个参数就是改变的THIS指向,写谁就是谁(特殊:非严格模式下,传递null/undefined指向的也是window
唯一区别:执行函数,传递的参数方式有区别,call是一个个的传递,apply是把需要传递的参数放到数组中整体传递
func.call([context],10,20)
func.apply([context],[10,20])
02.BIND
call/apply都是改变this的同时直接把函数执行了,而bind不是立即执行函数,属于预先改变this和传递一些内容 =>“柯理化”

Function.prototype={
call
apply
bind
}

重写重写bind

 ~ function anonymous(proto) {
	        // Es5 的方法重写bind 
		 	function bind(context) {
		 		//context may be null or undefined
		 		if (context == undefined) {
		 			context = window;
		 		}
		 		//获取传递的实参集合
		 		var args = [].slice.call(arguments, 1);
		 		//需要最终执行的函数
		 		var _this = this;
		 		return function anonymous() {
		 			var amArg = [].slice.call(arguments, 0);
		 			_this.apply(context, args.concat(amArg));
		 		};
		 	}
            // ES6的方法重写bind
			//经过测试:apply的性能不如call
			function bind(context = window, ...args) {
				return (...amArg) => this.call(context, ...args.concat(amArg));
			}
		   	proto.bind = bind;
		   }(Function.prototype);

重写call

 ~ function anonymous(proto) {
			 function call(context = window, ...args) {
				//=>必须保证context是引用类型
				context.$fn = this;
				let result = context.$fn(...args);
				delete context.$fn;
				return result;
			} 
           //详细版
			function call(context = window, ...args) {
				context === null ? context = window : null;
				let type = typeof context;
				if (type !== "object" && type !== "function" && type !== "symbol") {
					//=>基本类型值
					switch (type) {
						case 'number':
							context = new Number(context);
							break;
						case 'string':
							context = new String(context);
							break;
						case 'boolean':
							context = new Boolean(context);
							break;
					}
				}
				context.$fn = this;
				let result = context.$fn(...args);
				delete context.$fn;
				return result;
			}
		   	proto.call = call;	   
		   }(Function.prototype);

重写apply

 ~ function anonymous(proto) {
            // 重写apply
		   	function apply(context = window, args) {
		   		context.$fn = this;
		   		let result = context.$fn(...args);
		   		delete context.$fn;
		   		return result;
		   	}
		   	proto.apply = apply;
		   }(Function.prototype);

理解

let obj = {
		fn(x, y) {
		console.log(this, x, y);
		}
};
obj.fn.call({}, 10, 20);
obj.fn.apply(window, [10, 20]);
setTimeout(obj.fn.bind(window, 10, 20), 1000);
setTimeout(anonymous, 1000);  1S后先执行bind的返回结果anonymous,在anonymous中再把需要执行的obj.fn执行,把之前存储的context/args传给函数
document.body.onclick = obj.fn.bind(window, 10, 20);
 document.body.onclick = anonymous;

练习题

function fn1() {
console.log(1);
}
function fn2() {
console.log(2);
}

拆分理论

function call(context = window, ...args) {
			context.$fn = this;
			let result = context.$fn(...args);
			delete context.$fn;
			return result;
		} => AAAFFF000
	function fn1() {
			console.log(1);
		}

		function fn2() {
			console.log(2);
		}
		fn1.call(fn2); //=>执行的是FN1 =>1
		/*
		 * call执行
		 *   this=>fn1
		 *   context=>fn2
		 *   args=>[]
		 * fn2.$fn = fn1;  fn2.$fn(...[])
		 */
		fn1.call.call(fn2); //=>执行的是Fn2 =>2
		/*
		 * 先让最后一个CALL执行
		 *   this=>fn1.call=>AAAFFF000
		 *   context=>fn2
		 *   args=>[]
		 * fn2.$fn=AAAFFF000  fn2.$fn(...[])
		 *
		 * 让CALL方法再执行
		 *    this=>fn2
		 *    context=>undefined
		 *    args=>[]
		 * undefined.$fn=fn2  undefined.$fn()
		 * 
		 * 让fn2执行
		 */
		Function.prototype.call(fn1);
		/*
		 * 先让最后一个CALL执行
		 *     this=>Function.prototype(anonymous函数)
		 *     context=>fn1
		 *     args=>[]
		 * fn1.$fn=Function.prototype   fn1.$fn()
		 * 让Function.prototype执行
		 */
		Function.prototype.call.call(fn1); //=>1
		/*
		 * 先让最后一个CALL执行
		 *     this=>Function.prototype.call(AAAFFF000)
		 *     context=>fn1
		 *     args=>[]
		 * fn1.$fn=AAAFFF000   fn1.$fn()
		 * 
		 * 让CALL执行
		 *    this=>fn1
		 *    context=>undefined
		 *    args=>[]
		 * undefined.$fn=fn1   undefined.$fn()
		 * 让fn1执行
		 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值