您好,登錄后才能下訂單哦!
JavaScript
JavaScript(縮寫為JS)是一種高級的、多范式、解釋型的編程語言,是一門基于原型、函數(shù)先行的語言,它支持面向?qū)ο缶幊?、命令式編程以及函?shù)式編程。它提供語法來操控文本、數(shù)組、日期以及正則表達(dá)式,不支持I/O(比如網(wǎng)絡(luò)、存儲(chǔ)和圖形等),但可以由它的宿主環(huán)境提供支持。它已經(jīng)由ECMA(歐洲計(jì)算機(jī)制造商協(xié)會(huì))通過ECMAScript實(shí)現(xiàn)語言的標(biāo)準(zhǔn)化。它被世界上的絕大多數(shù)網(wǎng)站所使用,也被世界主流瀏覽器支持。
bind函數(shù)
bind() 方法會(huì)創(chuàng)建一個(gè)新函數(shù),當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),它的this值是傳遞給 bind() 的第一個(gè)參數(shù), 它的參數(shù)是bind()的其他參數(shù)和其原本的參數(shù)。
語法是這樣樣子的:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg 當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的 this 指向。當(dāng)使用 new 操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無效。
arg1, arg2, … (可選)當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)加上綁定函數(shù)本身的參數(shù)會(huì)按照順序作為原函數(shù)運(yùn)行時(shí)的參數(shù)。
參數(shù)
bind的第一個(gè)參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的this指向,不多說;而第二個(gè)開始的參數(shù)是可選的,當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)加上綁定函數(shù)本身的參數(shù)會(huì)按照順序作為原函數(shù)運(yùn)行時(shí)的參數(shù)。怎么理解?
function fn(a, b, c) { return a + b + c; } var _fn = fn.bind(null, 10); var ans = _fn(20, 30); // 60
fn 函數(shù)需要三個(gè)參數(shù),_fn 函數(shù)將 10 作為默認(rèn)的第一個(gè)參數(shù),所以只需要傳入兩個(gè)參數(shù)即可,如果你不小心傳入了三個(gè)參數(shù),放心,也只會(huì)取前兩個(gè)。
function fn(a, b, c) { return a + b + c; } var _fn = fn.bind(null, 10); var ans = _fn(20, 30, 40); // 60
這有啥用呢?如果某些函數(shù),前幾個(gè)參數(shù)已經(jīng) “內(nèi)定” 了,我們便可以用 bind 返回一個(gè)新的函數(shù)。也就是說,bind() 能使一個(gè)函數(shù)擁有預(yù)設(shè)的初始參數(shù)。這些參數(shù)(如果有的話)作為 bind() 的第二個(gè)參數(shù)跟在 this 后面,之后它們會(huì)被插入到目標(biāo)函數(shù)的參數(shù)列表的開始位置,傳遞給綁定函數(shù)的參數(shù)會(huì)跟在它們的后面。
function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset leading argument var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
new
使用 bind 返回的結(jié)果還是個(gè) function,是個(gè) function 就可以被 new 運(yùn)算符調(diào)用,那么結(jié)果呢?規(guī)范中說的很清楚了,當(dāng)使用 new 操作符調(diào)用綁定函數(shù)時(shí),bind 的第一個(gè)參數(shù)無效。
function Person(name, age) { this.name = name; this.age = age; } var _Person = Person.bind({}); var p = new _Person('hanzichi', 30); // Person {name: "hanzichi", age: 30}
一般我們不會(huì)去這么用,但是如果要寫個(gè) bind 的 polyfill( http://caniuse.com/#search=bind ),還是需要考慮用 new 調(diào)用的情況。
我們也可以設(shè)置默認(rèn)值(參考上一小節(jié)),原先提供的那些參數(shù)仍然會(huì)被前置到構(gòu)造函數(shù)調(diào)用的前面。
function Person(name, age) { this.name = name; this.age = age; } var _Person = Person.bind(null, 'hanzichi'); var p = new _Person(30); // Person {name: "hanzichi", age: 30}
配合 setTimeout
什么時(shí)候容易丟失 this 指向?恩,setTimeout 是一個(gè)場景,很容易把 this 指向 window,當(dāng)然,setInterval 也是一樣。當(dāng)使用對象的方法時(shí),需要 this 引用對象,你可能需要顯式地把 this 綁定到回調(diào)函數(shù)以便繼續(xù)使用對象。
var canvas = { render: function() { this.update(); this.draw(); }, update: function() { // ... }, draw: function() { // ... } }; window.setInterval(canvas.render, 1000 / 60);
用 canvas 寫特效或者做游戲時(shí)經(jīng)常會(huì)碰到類似的問題。上面的代碼是有問題的,render 方法中的 this 其實(shí)被指向了 window!我們可以用 bind, 顯式地把 this 綁定到回調(diào)函數(shù)以便繼續(xù)使用該對象。
window.setInterval(canvas.render.bind(canvas), 1000);
類似的情況還有 dom 的事件監(jiān)聽,一不小心可能 this 就被指向了 dom 元素??梢詤⒖枷乱郧白?bigrender 時(shí)寫的這部分代碼 https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js#L179-L184 。
tip
bind還能做一些有意思的事情。
通常來說,將一個(gè)類數(shù)組轉(zhuǎn)為數(shù)組,我們會(huì)用 slice(ie9- 不支持)。參考#14
var slice = Array.prototype.slice; // slice.apply(arguments); // slice(arguments, 1); bind 能讓調(diào)用變的更加簡單。 // same as "slice" in the previous example var unboundSlice = Array.prototype.slice; var slice = Function.prototype.call.bind(unboundSlice); // ... slice(arguments); // slice(arguments, 1);
再舉個(gè)類似的例子,比如說我們要添加事件到多個(gè)節(jié)點(diǎn),for 循環(huán)當(dāng)然沒有任何問題,我們還可以 “剽竊” forEach 方法:
Array.prototype.forEach.call(document.querySelectorAll('input[type="button"]'), function(el){ el.addEventListener('click', fn); });
更進(jìn)一步,我們可以用 bind 將函數(shù)封裝的更好:
var unboundForEach = Array.prototype.forEach , forEach = Function.prototype.call.bind(unboundForEach); forEach(document.querySelectorAll('input[type="button"]'), function (el) { el.addEventListener('click', fn); });
同樣類似的,我們可以將 x.y(z) 變成 y(x,z) 的形式:
var obj = { num: 10, getCount: function() { return this.num; } }; var unboundBind = Function.prototype.bind , bind = Function.prototype.call.bind(unboundBind); var getCount = bind(obj.getCount, obj); console.log(getCount()); // 10
再舉個(gè)栗子。每隔一秒在控制臺打印 1-5,看起來是道考察閉包的經(jīng)典題目。
for(var i = 1; i <= 5; i++) { !function(i) { setTimeout(function() { console.log(i); }, i * 1000); }(i); }
ES6 下能用 let :
for(let i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); }
也可以用 bind,瞬間逼格提升:
for(var i = 1; i <= 5; i++) { setTimeout(console.log.bind(console, i), i * 1000); }
以上就是javascript里的bind()函數(shù)的詳細(xì)內(nèi)容,更多請關(guān)注億速云其它相關(guān)文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。