視頻教程-call&&applyhtml
call、apply、bind三者均來自Function.prototype,被設計用來用於改變函數體內this的指向。前端
舉個例子node
// 有隻貓叫小黑,小黑會吃魚 const cat = { name: '小黑', eatFish(...args) { console.log('this指向=>', this); console.log('...args', args); console.log(this.name + '吃魚'); }, } // 有隻狗叫大毛,大毛會吃骨頭 const dog = { name: '大毛', eatBone(...args) { console.log('this指向=>', this); console.log('...args', args); console.log(this.name + '吃骨頭'); }, } console.log('=================== call ========================='); // 有一天大毛想吃魚了,但是它不知道怎麼吃。怎麼辦?小黑說我吃的時候餵你吃 cat.eatFish.call(dog, '汪汪汪', 'call') // 大毛爲了表示感謝,決定下次吃骨頭的時候也喂小黑吃 dog.eatBone.call(cat, '喵喵喵', 'call') console.log('=================== apply ========================='); cat.eatFish.apply(dog, ['汪汪汪', 'apply']) dog.eatBone.apply(cat, ['喵喵喵', 'apply']) console.log('=================== bind ========================='); // 有一天他們以爲每次吃的時候再喂太麻煩了。乾脆直接教對方怎麼吃 const test1 = cat.eatFish.bind(dog, '汪汪汪', 'bind') const test2 = dog.eatBone.bind(cat, '喵喵喵', 'bind') test1() test2()
apply() 方法調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數。func.apply(thisArg, [argsArray])
thisArg 可選的參數。在 func 函數運行時使用的 this 值。注意,不必定是該函數執行時真正的 this 值:若是這個函數處於非嚴格模式下,則指定爲 null 或 undefined 時會自動指向全局對象(瀏覽器中就是window對象),當值爲原始值(1,‘string’,true)時 this 會指向該原始值的自動包裝對象(Number,String,Boole)。
argsArray 可選的參數。一個數組或者類數組對象(NodeList),其中的數組元素的每一項將做爲單獨的參數傳給 func 函數。若是該參數的值爲 null 或 undefined,則表示不須要傳入任何參數。從ECMAScript 5 開始可使用類數組對象。segmentfault
妙用一:數組拼接數組
var array = ['a', 'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.info(array); // ["a", "b", 0, 1, 2]
解決了想修改原數組,不想用循環,還想傳遞一個數組的問題瀏覽器
妙用二:數組求最值app
/* 找出數組中最大/小的數字 */ var numbers = [5, 6, 2, 3, 7]; /* 應用(apply) Math.min/Math.max 內置函數完成 */ var max = Math.max.apply(null, numbers); /* 基本等同於 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */ var min = Math.min.apply(null, numbers); console.log(max,min)
妙用三:僞數組轉換ide
var arrayLike = { 0: 'xiaobai', 1: 'xiaohei', 2: 'xiaohong', length: 3 } var arr = Array.prototype.slice.call(arrayLike); console.log(arr)
妙用四:變量類型判斷函數
function isArray(obj) { return Object.prototype.toString.call(obj) == '[object Array]'; } console.log(isArray([])) console.log(isArray('qianduan'))
妙用五:構造繼承this
function Animal(name, age) { this.name = name; this.age = age; } function Dog() { Animal.apply(this,['cat','5']); // Animal.call(this, 'cat', '5'); this.say = function() { console.log(this.name + ":" + this.age); } } var dog = new Dog(); dog.say(); //cat:5
new的過程Dog中的this指向了建立的dog對象,而後執行構造函數中的代碼,執行了關鍵的apply,apply將當前環境的this(dog對象)指定給Animal,因此Animal中的this指向的就是dog對象,Animal中定義了name和age屬性,就至關於在dog中定義了這些屬性,所以dog對象便擁有了Animal中定義的屬性,從而達到了繼承的目的
call() 方法調用一個函數, 其具備一個指定的this值和分別地提供的參數(參數的列表)。apply的語法糖。fun.call(thisArg, arg1, arg2, ...)
妙用一:調用匿名函數
妙用一:調用匿名函數
兼容嚴格模式,嚴格模式下,匿名函數裏this會報錯。也實現了匿名函數針對不一樣的this,作不一樣的處理。
妙用二:字符串分隔鏈接
var temp = Array.prototype.join.call('hellow!', ','); console.log(temp)
字符串沒有join方法,借用Array
妙用三:字符串取每一項
Array.prototype.map.call('foo', (item) => { console.log(item) }).join('');
字符串沒有join方法,借用Array
bind()方法建立一個新的函數,在調用時設置this關鍵字爲提供的值。並在調用新函數時,將給定參數列表做爲原函數的參數序列的前若干項。
function.bind(thisArg[, arg1[, arg2[, ...]]])
解釋一下:
ES6新增的方法,這個方法會返回一個新的函數(函數調用的方式),調用新的函數,會將原始函數的方法當作傳入對象的方法使用,傳入新函數的任何參數也會一併傳入原始函數。
基本
function f(x) { console.log(this.a + x); //原始函數 } var obj = { a: 1 //傳入對象 } var newFn = f.bind(obj) //會將原始函數的方法當作傳入對象的方法使用 newFn(2) //調用新的函數 setTimeout(function() { console.log(this.name + ": Got it!") }.bind(this), 30) daily() { this.enjoy(function() { this.eat() this.drink() this.sleep() }.bind(this)) }
若是使用new運算符構造生成的綁定函數,則忽略綁定的this。
返回函數用做構造函數
function f(x) { this.a = 1; this.b = function() { return this.a + x } } var obj = { a: 10 } var newObj = new(f.bind(obj, 2)) //傳入了一個實參2 console.log(newObj.a) //輸出 1, 說明返回的函數用做構造函數時obj(this的值)被忽略了 console.log(newObj.b()) //輸出3 ,說明傳入的實參2傳入了原函數original
不傳值
window.color = 'red'; function sayColor(){ console.log(this.color); } var func2 = sayColor.bind();//this同理 // 輸出 "red", 由於傳的是'',全局做用域中this表明window。等於傳的是window。 func2();
屢次bind會發生什麼?
在Javascript中,屢次 bind() 是無效的。更深層次的緣由, bind() 的實現,至關於使用函數在內部包了一個 call / apply ,第二次 bind() 至關於再包住第一次 bind() ,故第二次之後的 bind 是沒法生效的。
屢次綁定
function say() { console.log(this.x); }; var a = say.bind({x: 1}); var b = a.bind({x: 2}); b() var a = function() { return say.apply({x: 1}); //改變say的this }; var b = function() { return a.apply({x: 2}); //改變了a的this };
妙用一:偏函數(使一個函數擁有預設的初始參數)
//在綁定this的同事傳入幾個值做爲默認參數,以後執行時再傳入的參數排在默認參數後面。 const obj = {} function f(...args) {console.log(args)} const newFn = f.bind(obj, '1', '2') newFn('3', '4') function add(arg1, arg2) { return arg1 + arg2 } // 建立一個函數,它擁有預設的第一個參數 var addThirtySeven = add.bind(null, 37); var result3 = addThirtySeven(5, 10); console.log(result3) // 37 + 5 = 42 ,第二個參數被忽略
妙用二:快捷調用
<div class="test">hello</div> <div class="test">hello</div> <div class="test">hello</div> <div class="test">hello</div> <script> function log() { console.log("hello") } //const forEach = Array.prototype.forEach //forEach.call(document.querySelectorAll(".test"), (test) => test.addEventListener("click", log)) const unbindForEach = Array.prototype.forEach, forEach = Function.prototype.call.bind(unbindForEach) forEach(document.querySelectorAll(".test"), (test) => test.addEventListener("click", log)) </script>
何時是用什麼方法
原始高清視頻下載
QQ答疑交流羣:
600633658
咱們的連接: