公众号【执鸢者】提早解锁3斩
写该系列文章的初衷是“让每位前端工程师掌握高频知识点,为工做助力”。这是前端百题斩的第15斩,但愿朋友们关注公众号“执鸢者”,用知识武装本身的头脑。
在百题斩【014】中已经简要概述了call、apply、bind三个方法,这三者做用是相同的,都可以改变this指向,从而让某对象能够调用自身不具有的方法,本节将深刻理解这三者的实现原理。javascript
call()
方法使用一个指定的this
值和单独给出的一个或多个参数来调用一个函数。其返回值是使用调用者提供的this值和参数调用该函数的返回值,若该方法没有返回值,则返回undefined。前端基本用法:java
function.call(thisArg, arg1, arg2, ...)
小试牛刀
function method(val1, val2) { return this.a + this.b + val1 + val2; } const obj = { a: 1, b: 2 }; console.log(method.call(obj, 3, 4)); // 10
实现一个call函数,将经过如下几个步骤:
Function.prototype.myCall = function (context, ...args) { // 获取第一个参数(注意第一个参数为null或undefined时,this指向window),构建对象 context = context ? Object(context) : window; // 将对应函数传入该对象中 context.fn = this; // 获取参数并执行相应函数 let result = context.fn(...args); // 消除反作用 delete context.fn; // 返回结果 return result; } // …… console.log(method.myCall(obj, 3, 4)); // 10
apply()
方法调用一个具备给定this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。其返回值是指定this值和参数的函数的结果。call()
和apply()
的区别是call()
方法接受的是参数列表,而apply()
方法接受的是一个参数数组;数组基本用法前端工程师
func.apply(thisArg, [argsArray])
小试牛刀
function method(val1, val2) { return this.a + this.b + val1 + val2; } const obj = { a: 1, b: 2 }; console.log(method.apply(obj, [3, 4])); // 10
apply和call的区别主要是参数的不一样,因此其实现步骤的call大致相似,以下所示:
Function.prototype.myApply = function (context, arr) { context = context ? Object(context) : window; context.fn = this; let result = arr ? context.fn(...arr) : context.fun(); delete context.fn; return result; } // …… console.log(method.myApply(obj, [3, 4])); // 10
bind()
方法建立一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其他参数将做为新函数的参数,供调用时使用。该函数的返回值是一个原函数的拷贝,并拥有指定的this值和初始参数。app基本用法函数
function.bind(thisArg[, arg1[, arg2[, ...]]])
小试牛刀
function method(val1, val2) { return this.a + this.b + val1 + val2; } const obj = { a: 1, b: 2 }; const bindMethod = method.bind(obj, 3, 4); console.log(bindMethod()); // 10
实现一个bind函数相对较复杂一些,应该注意如下几点:
Function.prototype.myBind = function (context, ...args) { if (typeof(this) !== 'function') { throw new TypeError('The bound object needs to be a function'); } const self = this; // 定义一个中装函数 const fNOP = function() {}; const fBound = function(...fBoundArgs) { // 利用apply改变this指向 // 接受多个参数+支持柯里化形式传参 // 当返回值经过new调用时,this指向当前实例 (由于this是当前实例,实例的隐士原型上有fNOP的实例(fnop);fnop instanceof fNOP为true) return self.apply(this instanceof fNOP ? this : context, [...args, ...fBoundArgs]); } // 将调用函数的原型赋值到中转函数的原型上 if (this.prototype) { fNOP.prototype = this.prototype; } // 经过原型的方式继承调用函数的原型 fBound.prototype = new fNOP(); return fBound; }
1.若是以为这篇文章还不错,来个分享、点赞吧,让更多的人也看到this
2.关注公众号执鸢者,与号主一块儿斩杀前端百题spa