实现call,apply和bind方法
实现call 和bind
- 改变this指向
- 传入参数
- 返回结果
-
<script> /* 实现call() 思路: 改变this指向:可以将目标函数作为这个对象的属性 利用arguments类数组对象实现参数不定长 不能增加对象的属性,所以在结尾需要delete */ Function.prototype.mycall = function (obj) { obj = obj || window; var args = []; // 参数是从1开始的 for (var i = 1; i < arguments.length; i++) { args.push('arguments[' + i + ']'); //args => [arguments[1], arguments[2], arguments[3], ...] } obj.fn = this;//此时的this就是函数fn let result = eval('obj.fn(' + args + ')');//执行fn delete obj.fn;//删除fn return result; } // 利用ES6实现call() Function.prototype.mycall2 = function (obj) { obj = obj || window; obj.fn = this;//绑定this // 利用拓展运算符直接将arguments转换为数组 let args = [...arguments].slice(1); let result = obj.fn(...args);//执行fn delete obj.fn; return result; } /* 实现apply() 思路: 改变this指向:可以将目标函数作为这个对象的属性 利用arr传入参数 不能增加对象的属性,所以在结尾需要delete */ Function.prototype.myapply = function (obj, arr) { obj = obj ? Object(obj) : window; obj.fn = this;//此时的this就是函数fn var result; if (!arr) { result = obj.fn();//执行fn } else { var args = []; for (var i = 0; i < arr.length; i++) { args.push('arr[' + i + ']'); } result = eval('obj.fn(' + args + ')');//执行fn } delete obj.fn;//删除fn return result; } // es6实现apply() Function.prototype.myapply2 = function (obj, arr) { obj = obj ? Object(obj) : window; obj.fn = this; var result; if (!arr) { result = obj.fn();//执行fn } else { result = obj.fn(...arr);////执行fn } delete obj.fn; return result; } //实例 var obj = { name: 'zpl', fn: function () { console.log("我的名字是" + this.name); } }; //全局 var name = 'zs'; obj.fn();//我的名字是zpl // fn();// fn is not defined var fun = obj.fn; fun();//我的名字是zs obj.fn.mycall({ name: "wcy" });//我的名字是wcy obj.fn.mycall2({ name: "YY" });//我的名字是YY obj.fn.myapply({ name: "影子" });//我的名字是影子 obj.fn.myapply({ name: "CC" });//我的名字是CC </script>
实现bind() 方法
- 改变this
- 传入参数
- 返回函数
-
<script> /* 实现bind() bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数, 而其余参数将作为新函数的参数,供调用时使用。 说的通俗一点,bind与apply/call一样都能改变函数this指向, 但bind并不会立即执行函数,而是返回一个绑定了this的新函数, 你需要再次调用此函数才能达到最终执行。 实现思路: 1. 因为bind方法不是立即执行函数,需要返回一个待执行的函数,所以使用闭包 2. 作用域绑定: 可以使用apply或call方法来实现 3. 参数传递: 由于参数的不确定性,需要使用apply传递数组 */ // 实现简单的bind方法 Function.prototype.mybind2 = function(obj) { var fn = this; var agrs = Array.prototype.slice.call(arguments,1); return function() { // 将回调函数的参数arguments数组化,然后与绑定时传入的参数args合并 var newArgs = Array.prototype.slice.call(arguments); return fn.apply(obj, args.concat(newArgs)); } } // 完整实现bind() Function.prototype.mybind2 = function(obj) { if(typeof this !== 'function') { throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); }; var args = Array.prototype.slice.call(arguments,1); var fn = this; // 创建中介函数 var fn_ = function(){}; var bound = function() { var params = Arrayx.prototype.slice.call(arguments); // 通过constructor判断调用方法,为true ,this指向实例,否则为obj fn.apply(this.constructor === fn ? this : obj, args.concat(params)); console.log(this); }; fn_.prototype = fn.prototype; bound.prototype = new fn_(); return bound; } // 实例 var obj = { name: "zpl", fn: function() { console.log("我的名字是" + this.name); } } var name = "zs"; obj.fn();//我的名字是zpl obj.fn.bind({name: "yz"})();//我的名字是yz var bound = obj.fn.bind({name: "ying"}); var b = new bound();//我的名字是undefined </script>
参考:
https://www.cnblogs.com/echolun/p/12178655.html
https://blog.csdn.net/qq_36367995/article/details/81319852