apply 和 call 都是爲了解決改變 this 的指向。做用都是相同的,只是傳參的方式不一樣。
第一個參數都是改變this的指向,apply 接收一個數組做爲參數,call 接收一個參數列表。
而bind 則返回一個函數。數組
let obj = { value: 1 } function getValue(name, age){ console.log(name, age, this.value) } getValue.apply(obj, ['zhangsan', '18']) // zhangsan 18 1 getValue.call(obj, 'lisi', '20') // lisi 20 1 getValue.bind(obj, 'wangwu', '20')() // wangwu 20 1 getValue.bind(obj)('wangwu', '20') // wangwu 20 1 //使用apply實現二維數組降維 [].concat.apply([], [1,2,[3,4,5],[6,7]]) //使用call將參數列表轉爲數組 function fn(){return [].slice.call(arguments)} function fn(...args){return arg} //一個通用的事件綁定函數,call實現代理 function bindEvent(elem, type, selector, fn) { if (fn == null) { fn = selector selector = null } elem.addEventListener(type, function (e) { var target if (selector) { target = e.target if (target.matches(selector)) { //改變指向到目標元素 fn.call(target, e) } } else { fn(e) } }) } //使用代理 var div1 = document.getElementById('div') bindEvent(div1, 'click', 'a.class', function (e) { console.log(this.innerHTML) }) //兼容IE8的寫法 var addEvent = (function() { if(window.addEventListener) { return function(el, type, fn, capture) { el.addEventListener(type, function(e) { fn.call(el, e); }, capture); } }else { return function(ele, type, fn) { el.attachEvent('on' + type, function(e) { fn.call(el, e); }) } } })()
Function.prototype.myApply = function(context){ context = context || window context.foo = this; //判斷第二個參數是否存在且是數組 let result = arguments[1] ? ( Array.isArray(arguments[1]) ? context.foo(...arguments[1]) : context.foo(arguments[1])) : context.foo() delete context.foo return result }
Function.prototype.myCall = function(context){ context = context || window // 第一個參數爲函數的執行上下文,就把函數賦值給foo context.foo = this; //將剩餘參數取出 let args = [...arguments].slice(1); let result = context.foo(...args); // 執行完畢須要刪除foo屬性 delete context.foo; return result; }
Function.prototype.myCall = function(context){ context = context || window let _this = this; let args = [...arguments].slice(1); return fcuntion(){ _this.apply(context, args.concat(...arguments)) } }