var ary = [12, 23, 34]; ary.slice();
以上两行简单的代码的执行过程为:ary
这个实例通过原型链的查找机制找到array.prototype
上的slice
方法,让找到的slice
方法执行,在执行slice
方法的过程中才把ary
数组进行了截取。
注意:slice
方法执行之前有一个在原型上查找的过程(当前实例中没有找到,再根据原型链查找)。
当知道了一个对象调用方法会有一个查找过程之后,我们再看:
var obj = {name:'iceman'}; function fn() { console.log(this); console.log(this.name); } fn(); // this --> window // obj.fn(); // uncaught typeerror: obj.fn is not a function fn.call(obj);
call方法的作用:首先寻找call
方法,最后通过原型链在function
的原型中找到call
方法,然后让call
方法执行,在执行call
方法的时候,让fn
方法中的this
变为第一个参数值obj
,最后再把fn
这个函数执行。
知道这个原型上的原理后,咱们就可以动手分析实现这三个方法了。
call
和 apply
都是为了解决改变 this
的指向。作用都是相同的,只是传参的方式不同。call
可以接收一个参数列表,apply
只接受一个参数数组let a = { value: 1 } function getvalue(name, age) { console.log(name) console.log(age) console.log(this.value) } getvalue.call(a, 'yck', '24') getvalue.apply(a, ['yck', '24'])
bind
和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过bind
实现柯里化
对于实现以下几个函数,可以从几个方面思考
window
this
指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?当然是肯定的,于是我们可以这样写:
function.prototype.mybind = function (context) { if (typeof this !== 'function') { throw new typeerror('error') } var _this = this var args = [...arguments].slice(1) // 返回一个函数 return function f() { // 因为返回了一个函数,我们可以 new f(),所以需要判断 if (this instanceof f) { return new _this(...args, ...arguments) } return _this.apply(context, args.concat(...arguments)) } }
function.prototype.mycall = function (context,...arg) { var context = context || window // 给 context 添加一个属性 // getvalue.call(a, 'yck', '24') => a.fn = getvalue //使用symbol 选择一个独一无二的值作为新添加的属性 let symbol = new symbol(); context[symbol] = this; let result = context[symbol](...arg) // 删除添加的函数 delete context[symbol] return result }
apply实现原理与call实现基本类似,只有传值的方式不一样。
function.prototype.myapply = function (context,arg) { var context = context || window // 给 context 添加一个属性 // getvalue.call(a, 'yck', '24') => a.fn = getvalue //使用symbol 选择一个独一无二的值作为新添加的属性 let symbol = new symbol(); context[symbol] = this; let result = context[symbol](arg) // 删除添加的函数 delete context[symbol] return result }
经过对以上的函数进行检测 , 完美通过。
const obj = { name : 'xiaoxiao', getname : function (arg) { console.log(`我是${this.name}里面的,我里面有${arg}`); } } obj.getname([0,0,0,0,0]); // 我是xiaoxiao里面的 const obj2 = { name : 'huahua' } //传值不一样 obj.getname.mycall(obj2,1,1,1,1,1,1); obj.getname.mybind(obj2)(2,2,2,2,2,2); obj.getname.myapply(obj2,[3,3,3,3,3,3]);
更多关于js中call、apply三个方法的区别与使用方式请查看下面的相关链接
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。