<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        在Javascript中如何實現bind

        來源:懂視網 責編:小采 時間:2020-11-27 19:37:27
        文檔

        在Javascript中如何實現bind

        在Javascript中如何實現bind:這篇文章主要介紹了Javascript中從學習bind到實現bind的過程,有興趣的朋友跟著學習下吧。bind是什么bind()方法創建一個新的函數, 當被調用時,將其this關鍵字設置為提供的值,在調用新函數時,在任何提供之前提供一個給定的參數序列。var result
        推薦度:
        導讀在Javascript中如何實現bind:這篇文章主要介紹了Javascript中從學習bind到實現bind的過程,有興趣的朋友跟著學習下吧。bind是什么bind()方法創建一個新的函數, 當被調用時,將其this關鍵字設置為提供的值,在調用新函數時,在任何提供之前提供一個給定的參數序列。var result

        這篇文章主要介紹了Javascript中從學習bind到實現bind的過程,有興趣的朋友跟著學習下吧。

        bind是什么

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

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

        沒看懂沒事接著往下看。

        bind到底做了什么

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

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

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

        this.value = 2
        var 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 = 2
        var 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 = 2
        var 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指向bar
        resultFunc.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.prototype
        o 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出來的實例沒有原型鏈,那么它的意義是什么呢。

        上面是我整理給大家的,希望今后會對大家有幫助。

        相關文章:

        MVVM框架如何解析雙向綁定

        JS運動特效

        JS中鏈式運動(詳細教程)

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        在Javascript中如何實現bind

        在Javascript中如何實現bind:這篇文章主要介紹了Javascript中從學習bind到實現bind的過程,有興趣的朋友跟著學習下吧。bind是什么bind()方法創建一個新的函數, 當被調用時,將其this關鍵字設置為提供的值,在調用新函數時,在任何提供之前提供一個給定的參數序列。var result
        推薦度:
        標簽: 實現 js 捆綁
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 中文字幕乱码系列免费| 另类图片亚洲校园小说区| 大地资源在线资源免费观看| 波多野结衣免费视频观看| 国产精品亚洲va在线观看| 国产美女被遭强高潮免费网站 | 成人免费激情视频| 亚洲成a人片7777| 91成人免费观看网站| 国产成人精品亚洲日本在线| 毛片免费视频播放| 激情无码亚洲一区二区三区| 免费在线精品视频| 免费看成人AA片无码视频吃奶| 亚洲国产成人片在线观看| 无码国产精品一区二区免费模式| 久久久久久亚洲精品成人| 日本免费网站视频www区| 亚洲欧洲日本在线观看| 亚洲AV无码成H人在线观看| aa在线免费观看| 亚洲日本视频在线观看| 最新69国产成人精品免费视频动漫| 国产精品久久亚洲一区二区| 亚洲宅男天堂在线观看无病毒| 日韩精品内射视频免费观看| 亚洲人成网男女大片在线播放 | 亚洲国产婷婷香蕉久久久久久| 精品乱子伦一区二区三区高清免费播放| 久久被窝电影亚洲爽爽爽| 97人妻无码一区二区精品免费| 亚洲人成网站在线播放2019| 久久亚洲AV无码西西人体| 1000部拍拍拍18免费网站| 国产尤物在线视精品在亚洲| 亚洲Av永久无码精品三区在线| 成人免费视频一区二区三区| 精品国产呦系列在线观看免费 | 亚洲av永久中文无码精品| 精品亚洲视频在线观看 | 18禁无遮挡无码国产免费网站|