亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

Javascript中從學習bind到實現bind的過程

2024-05-06 16:41:49
字體:
來源:轉載
供稿:網友

bind是什么

bind()方法創建一個新的函數, 當被調用時,將其this關鍵字設置為提供的值,在調用新函數時,在任何提供之前提供一個給定的參數序列。

var result = fun.bind(thisArg[, arg1[, arg2[, ...]]]) result(newArg1, newArg2...)

沒看懂沒事接著往下看。

bind到底做了什么

從上面的介紹中可以看出三點。首先調用bind方法會返回一個新的函數(這個新的函數的函數體應該和fun是一樣的)。同時bind中傳遞兩個參數,第一個是this指向,即傳入了什么this就等于什么。如下代碼所示:

this.value = 2var foo = {  value: 1}var bar = function() { console.log(this.value)}var result = bar.bind(foo)bar() // 2result() // 1,即this === foo

第二個參數為一個序列,你可以傳遞任意數量的參數到其中。并且會預置到新函數參數之前。

this.value = 2var foo = {  value: 1};var bar = function(name, age, school) { console.log(name) // 'An' console.log(age) // 22 console.log(school) // '家里蹲大學'}var result = bar.bind(foo, 'An') //預置了部分參數'An'result(22, '家里蹲大學') //這個參數會和預置的參數合并到一起放入bar中

我們可以看出在最后調用 result(22, '家里蹲大學') 的時候,其內部已經包含了在調用bind的時候傳入的 'An'。

一句話總結:調用bind,就會返回一個新的函數。這個函數里面的this就指向bind的第一個參數,同時this后面的參數會提前傳給這個新的函數。調用該新的函數時,再傳遞的參數會放到預置的參數后一起傳遞進新函數。

自己實現一個bind

實現一個bind需要實現以下兩個功能

返回一個函數,綁定this,傳遞預置參數

bind返回的函數可以作為構造函數使用。故作為構造函數時應使得this失效,但是傳入的參數依然有效

1、返回一個函數,綁定this,傳遞預置參數

this.value = 2var foo = {  value: 1};var bar = function(name, age, school) {  console.log(name) // 'An'  console.log(age) // 22  console.log(school) // '家里蹲大學'  console.log(this.value) // 1}Function.prototype.bind = function(newThis) {  var aArgs  = Array.prototype.slice.call(arguments, 1) //拿到除了newThis之外的預置參數序列  var that = this  return function() {    return that.apply(newThis, aArgs.concat(Array.prototype.slice.call(arguments)))    //綁定this同時將調用時傳遞的序列和預置序列進行合并  }}var result = bar.bind(foo, 'An')result(22, '家里蹲大學')

這里面有一個細節就是Array.prototype.slice.call(arguments, 1) 這句話,我們知道arguments這個變量可以拿到函數調用時傳遞的參數,但不是一個數組,但是其具有一個length屬性。為什么如此調用就可以將其變為純數組了呢。那么我們就需要回到V8的源碼來進行分析。#這個版本的源碼為早期版本,內容相對少一些。

function ArraySlice(start, end) { var len = ToUint32(this.length);  //需要傳遞this指向對象,那么call(arguments), //便可將this綁定到arguments,拿到其length屬性。 var start_i = TO_INTEGER(start); var end_i = len; if (end !== void 0) end_i = TO_INTEGER(end); if (start_i < 0) {  start_i += len;  if (start_i < 0) start_i = 0; } else {  if (start_i > len) start_i = len; } if (end_i < 0) {  end_i += len;  if (end_i < 0) end_i = 0; } else {  if (end_i > len) end_i = len; } var result = []; if (end_i < start_i)  return result; if (IS_ARRAY(this))  SmartSlice(this, start_i, end_i - start_i, len, result); else   SimpleSlice(this, start_i, end_i - start_i, len, result); result.length = end_i - start_i; return result;};

從源碼中可以看到通過call將arguments下的length屬性賦給slice后,便可通過 start_i & end_i來獲得最后的數組,所以不需要傳遞進slice時就是一個純數組最后也可以得到一個數組變量。

2、bind返回的函數可以作為構造函數使用

被用作構造函數時,this應指向new出來的實例,同時有prototype屬性,其指向實例的原型。

this.value = 2var foo = { value: 1};var bar = function(name, age, school) { ... console.log('this.value', this.value)}Function.prototype.bind = function(newThis) { var aArgs  = Array.prototype.slice.call(arguments, 1) var that = this //that始終指向bar var NoFunc = function() {} var resultFunc = function() {  return that.apply(this instanceof that ? this : newThis, aArgs.concat(Array.prototype.slice.call(arguments))) }  NoFunc.prototype = that.prototype //that指向bar resultFunc.prototype = new NoFunc() return resultFunc}var result = bar.bind(foo, 'An')result.prototype.name = 'Lsc' // 有prototype屬性var person = new result(22, '家里蹲大學')console.log('person', person.name) //'Lsc'

上面這段模擬代碼做了兩件重要的事。

1.給返回的函數模擬一個prototype屬性。,因為通過構造函數new出來的實例可以查詢到原型上定義的屬性和方法

var NoFunc = function() {}...NoFunc.prototype = that.prototype //that指向barresultFunc.prototype = new NoFunc()return resultFunc

通過上面代碼可以看出,that始終指向bar。同時返回的函數已經繼承了that.prototype即bar.prototype。為什么不直接讓返回的函數的prototype屬性resultFunc.prototype 等于為bar(that).prototype呢,這是因為任何new出來的實例都可以訪問原型鏈。如果直接賦值那么new出來的對象可以直接修改bar函數的原型鏈,這也就是是原型鏈污染。所以我們采用繼承的方式(將構造函數的原型鏈賦值為父級構造函數的實例),讓new出來的對象的原型鏈與bar脫離關系。

2.判斷當前被調用時,this是用于普通的bind還是用于構造函數從而更改this指向。

如何判斷當前this指向了哪里呢,通過第一點我們已經知道,通過bind方法返回的新函數已經有了原型鏈,剩下需要我們做的就是改變this的指向就可以模擬完成了。通過什么來判斷當前被調用是以何種姿勢呢。答案是instanceof 。

instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。

// 定義構造函數function C(){} function D(){} var o = new C();// true,因為 Object.getPrototypeOf(o) === C.prototypeo instanceof C; // false,因為 D.prototype不在o的原型鏈上o instanceof D; 

從上面可以看出,instanceof可以判斷出一個對象是否是由這個函數new出來的,如果是new出來的,那么這個對象的原型鏈應為該函數的prototype.

所以我們來看這段關鍵的返回的函數結構:

var resultFunc = function() {  return that.apply(this instanceof that ?     this :     newThis,     aArgs.concat(Array.prototype.slice.call(arguments))) } 

在這其中我們要先認清this instanceof that 中的this是bind函數被調用后,返回的新函數中的this。所以這個this可能執行在普通的作用域環境,同時也可能被new一下從而改變自己的指向。再看that,that始終指向了bar,同時其原型鏈that.prototype是一直存在的。所以如果現在這個新函數要做new操作,那么this指向了新函數,那么 this instanceof that === true, 所以在apply中傳入this為指向,即指向新函數。如果是普通調用,那么this不是被new出來的,即新函數不是作為構造函數,this instanceof that === false就很顯而易見了。這個時候是正常的bind調用。將調用的第一個參數作為this的指向即可。

完整代碼(MDN下的實現)

if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) {  if (typeof this !== 'function') {   // closest thing possible to the ECMAScript 5   // internal IsCallable function   throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');  }  var aArgs  = Array.prototype.slice.call(arguments, 1),    fToBind = this,    fNOP  = function() {},    fBound = function() {     return fToBind.apply(this instanceof fNOP         ? this         : oThis,         aArgs.concat(Array.prototype.slice.call(arguments)));    };  if (this.prototype) {   // Function.prototype doesn't have a prototype property   fNOP.prototype = this.prototype;   }  fBound.prototype = new fNOP();  return fBound; };}

可以看到,其首先做了當前是否支持bind的判定,不支持再實行兼容。同時判斷調用這個方法的對象是否是個函數,如果不是則報錯。

同時這個模擬的方法也有一些缺陷,可關注MDN上的Polyfill部分

小結

模擬bind實現最大的一個缺陷是,模擬出來的函數中會一直存在prototype屬性,但是原生的bind作為構造函數是沒有prototype的,這點打印一下即可知。不過這樣子new出來的實例沒有原型鏈,那么它的意義是什么呢。

大家在學習的時候如果還有任何問題,可以在下面的留言區討論,感謝你的支持。

 

注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一本色道久久88亚洲综合88| 久久久最新网址| 亚洲天堂开心观看| 国产成人中文字幕| 亚洲黄色有码视频| 97在线视频免费| 深夜福利一区二区| 成人免费观看a| 成人美女免费网站视频| 久久91精品国产91久久跳| 日韩免费看的电影电视剧大全| 日韩欧美在线播放| 欧美激情手机在线视频| 欧美日韩亚洲91| 自拍偷拍亚洲精品| 亚洲欧美国产精品va在线观看| 日韩电视剧在线观看免费网站| 国产亚洲成精品久久| 亚洲天堂精品在线| 国产精品自拍偷拍| 欧美国产第二页| 日韩av黄色在线观看| 久久久久久亚洲精品不卡| 久久精品国产欧美亚洲人人爽| 欧美视频在线观看免费网址| 日韩亚洲精品视频| 久久精品国产亚洲| 97在线视频免费| 亚洲精品久久久久久下一站| 亚洲国产91色在线| 亚洲区中文字幕| 国产一区二区三区在线观看视频| 色播久久人人爽人人爽人人片视av| 亚洲女在线观看| 亚洲精品日韩久久久| 国产视频久久网| 欧美日韩亚洲系列| 久久久视频免费观看| 在线色欧美三级视频| 精品福利一区二区| 国产精品大陆在线观看| 亚洲人成电影网站色xx| 亚洲男人天堂古典| 91免费国产网站| 中文字幕在线看视频国产欧美| 91精品啪在线观看麻豆免费| 欧洲精品久久久| xxx欧美精品| 97精品久久久中文字幕免费| 国内伊人久久久久久网站视频| 成人午夜高潮视频| 亚洲r级在线观看| 国产欧美精品一区二区三区-老狼| 亚洲精品久久久一区二区三区| 中文字幕一区二区精品| 欧美激情高清视频| 亚洲第一网中文字幕| 91精品国产91久久| 国产成人涩涩涩视频在线观看| 欧美日韩亚洲精品一区二区三区| 欧美午夜视频在线观看| 亚洲成人亚洲激情| 中文字幕综合在线| 日韩黄色高清视频| 久久久亚洲网站| 日韩视频在线观看免费| 日韩欧美成人网| 欧美大片va欧美在线播放| 欧美视频中文在线看| 久久久久久久电影一区| 欧美一区二三区| 啊v视频在线一区二区三区| 久久久精品久久| 97久久超碰福利国产精品…| 国产精品久久91| 欧日韩不卡在线视频| 中文字幕av一区二区三区谷原希美| 久久人人爽人人爽爽久久| 亚洲白虎美女被爆操| 欧美日韩性生活视频| 热久久视久久精品18亚洲精品| 欧美激情一区二区三区成人| 久久综合久久美利坚合众国| 欧美国产一区二区三区| 欧洲美女7788成人免费视频| 亚洲天堂成人在线| 亚洲成人精品久久久| 精品国产91久久久| 亚洲缚视频在线观看| 日本一本a高清免费不卡| 欧美成人精品一区二区三区| 中文字幕亚洲色图| 国产精品自拍小视频| 欧美麻豆久久久久久中文| 日韩欧美黄色动漫| 亚洲福利视频专区| 亚洲日本aⅴ片在线观看香蕉| 国产精品美女主播在线观看纯欲| 免费91麻豆精品国产自产在线观看| 日韩av手机在线观看| 精品国偷自产在线视频99| 欧美专区在线播放| 国产成人高清激情视频在线观看| 美女视频黄免费的亚洲男人天堂| 欧美成人三级视频网站| 狠狠躁夜夜躁人人爽天天天天97| 国产精品中文久久久久久久| 最好看的2019年中文视频| 欧美午夜精品久久久久久久| 97视频在线观看免费高清完整版在线观看| 26uuu亚洲国产精品| 97成人精品区在线播放| 亚洲精选一区二区| 欧美性高跟鞋xxxxhd| 黄色成人av在线| 欧美黑人国产人伦爽爽爽| 亚洲www视频| 国产在线播放91| 欧美噜噜久久久xxx| 黄色一区二区在线| 日韩精品视频中文在线观看| 亚洲人成五月天| 激情亚洲一区二区三区四区| 国产一区二区动漫| 精品成人av一区| 欧美激情视频一区二区三区不卡| 国产原创欧美精品| 亚洲丁香婷深爱综合| 欧亚精品中文字幕| 91成人免费观看网站| 日韩精品有码在线观看| 97久久久免费福利网址| 亚洲视频自拍偷拍| 亚洲天堂网站在线观看视频| 91av视频在线免费观看| 人人爽久久涩噜噜噜网站| 国产一区二区黑人欧美xxxx| 久久精品视频免费播放| 97久久精品人人澡人人爽缅北| 亚洲bt欧美bt日本bt| 久久99精品久久久久久青青91| 欧美激情一二区| 在线电影中文日韩| 久久久国产一区二区三区| 亚洲一区精品电影| 国产精品久久久久久久久久新婚| 美女扒开尿口让男人操亚洲视频网站| 欧美激情亚洲视频| 国产日本欧美视频| 久热精品视频在线观看一区| 欧美性色xo影院| 91精品国产综合久久香蕉的用户体验| 性欧美视频videos6一9| 精品精品国产国产自在线| 亚洲永久免费观看| 日韩精品福利在线| 久久伊人精品一区二区三区| 6080yy精品一区二区三区| 91网站在线免费观看| 国产精品入口夜色视频大尺度| 亚洲伊人第一页| 91香蕉嫩草神马影院在线观看| 亚洲久久久久久久久久| 欧美片一区二区三区|