语法 func.call(obj, param1, param2, ...)
func.apply(obj, [param1,param2,...])
func.bind(obj, param1, param2, ...)
返回值 call / apply:返回func 执行的结果 ; bind:返回func的拷贝,并拥有指定的this值和初始参数。
作用 借助已实现的方法,改变函数执行时的this指向,减少重复代码,节省内存。
call与apply的唯一区别:给func传参的方式不同 apply是第2个参数,这个参数是一个类数组对象。 call从第 2~n 的参数都是传给func的。
call/apply 与 bind 的区别 call/apply改变了函数的this的指向并马上执行该函数; bind则是返回改变了this指向后的函数,不执行该函数。
原生JavaScript实现call()
需要设置一个参数obj,也就是this的指向;
将obj封装为一个Object;
为obj创建一个临时方法,这样obj就是调用该临时方法的对象了,临时方法的this隐式指向到obj上
执行obj的临时方法,并传参
删除临时方法,返回方法的执行结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Function .prototype.myCall = function (obj, ...args ) { if (obj === null || obj === undefined ) { obj = window ; } else { obj = Object (obj); } const specialMethod = Symbol (); obj[specialMethod] = this ; let result = obj[specialMethod](...args); delete obj[specialMethod]; return result; };
测试:
1 2 3 4 5 6 7 8 9 10 11 let obj = { name: "hello" }; function func ( ) { console .log(this .name); } func.myCall(obj);
原生JavaScript实现apply()
可以通过索引(index)调用,如 array[0];
具有长度属性length;
可以通过 for 循环或forEach方法,进行遍历。 eg.
1 2 3 4 5 6 7 8 let arrayLike = { 0 : 1 , 1 : 2 , 2 : 3 , length: 3 };
实现思路 只有传递给函数的参数处理,不太一样,第二个参数为类数组对象。其他部分跟call一样;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Function .prototype.myApply = function (obj ) { if (obj === null || obj === undefined ) { obj = window ; } else { obj = Object (obj); } function isArrayLike (o ) { if ( o && typeof o === "object" && isFinite (o.length) && o.length >= 0 && o.length === Math .floor(o.length) && o.length < 2 **32 ) return true ; else return false ; } const specialMethod = Symbol (); obj[specialMethod] = this ; let args = arguments [1 ]; let result; if (args) { if (!Array .isArray(args) && !isArrayLike(args)) { throw new TypeError ( "第二个参数既不是数组,也不是类数组对象。抛出错误" ); } else { args = Array .from(args); result = obj[specialMethod](...args); } } else { result = obj[specialMethod](); } delete obj[specialMethod]; return result; };
原生Javascript实现bind()
被函数调用
返回一个新函数
可以给新函数传递参数
修改函数运行时this的指向
新函数作为构造函数时,this 指向实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Function .prototype.myBind = function (obj, ...params ) { if (typeof this !== "function" ) { throw new TypeError ( "Function.prototype.bind was called on which is not a function" ); } const tempFn = this ; let copiedFunc = function (...secondParams ) { const isNew = this instanceof copiedFunc; const thisArg = isNew ? this : Object (obj); return tempFn.call(thisArg, ...params, ...secondParams); }; copiedFunc.prototype = Object .create(tempFn.prototype); return copiedFunc; };
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function func (name ) { console .log(this ); this .name = name; } func.prototype.hello = function ( ) { console .log(this .name); } let newFunc = func.myBind({a :1 });let o = new newFunc('lily' );o.hello();