如何手写一个call,apply以及bind
首先我们对于call,apply以及bind三个函数的区别已经做了分析,具体请查看前文
函数
参数形式
返回值
call
第一个参数为this要指向的对象,后面的参数同函数保持一致即可。
立即执行,返回值即函数返回值。
apply
第一个参数为this要指向的对象,第二个参数为组织成数组形式的函数参数列表。
立即执行,返回值即函数返回值。
bind
第一个参数为this要指向的对象,后面的参数同函数保持一致即可。
返回一个绑定好第一个参数和后序参数的函数,需要接收然后再执行。
1.手写call
改变this的核心思想在于:谁调用函数,this指向谁。 所以我们需要为传入的对象绑定上一个fn属性,这个fn属性指向要执行的函数。 然后通过obj.fn()的形式调用,这样this也就指向了当前传入的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 27
| Function.prototype.myCall = function (context) { if (typeof this !== "function") { throw new TypeError("this isn't function"); } context = context window; context.fn = this; let args = Array.from(arguments).slice(1); let result = context.fn(...args); delete context.fn; return result; } let obj = { name: "ax" } function print(...args) { console.log(this); console.log(...args) console.log(this.name); } print.myCall(obj, "name", "mydear");
|
结果:
2.手写apply
apply和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
| Function.prototype.myApply = function (context) { if (typeof this !== "function") { throw new TypeError("this is not function") } context = context window; let args = null; if (arguments[1] != null) { args = arguments[1]; } else { args = []; } context.fn = this; let result = context.fn(...args); delete context.fn; return result; } let obj = { name: "ax" } function print(...args) { console.log(this); console.log(...args) console.log(this.name); } print.myApply(obj, "ok", "test");
|
结果:
3.手写bind
bind的返回结果是一个函数,而函数的调用有两种方式: 一种是直接调用,另一种则是通过new调用,这里需要进行不同的处理
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 50 51 52 53 54 55 56 57 58 59
|
Function.prototype.myBind = function (context) { if (typeof this !== "function") { throw new TypeError("this is not a function"); } const args = Array.from(arguments).slice(1); context = context window; const _this = this; return function F() { if (this instanceof F) { return _this(...args); } else { return _this.apply(context, args); } } }
function print(name, age) { if (name && age) { this.name = name; this.age = age; } console.log(`hi,I am ${this.name},I am ${this.age} years old!`); } let obj = { name: "ax", age: 20 } let obj2 = { name: "kime", age: 19 } console.log( obj) let f1 = print.myBind(obj); f1(); f2 = print.myBind(obj, "AX", 21); f2(); console.log(obj);
let f3 = print.myBind(obj, "AX", 30); let funcObj = new f3(); console.log(funcObj)
|