摘要:前言最近接觸到方法,為了加深理解,自己模擬實現一下。我們模擬的方法參考上的。基本上關于模擬的實現就是這樣。所以不能肯定剛才的就是總結完全重寫構造函數原型對象要放在構造函數后面,如果放在構造函數里面,可能原型鏈會有錯誤。
前言
最近接觸到bind方法,為了加深理解,自己模擬實現一下。
首先,談一下bind()方法的特點:
把調用bind()的函數(以后統稱為初試函數)中的this指向綁定到某個對象上,bind的第二個及其以后的參數作為作為 初始函數的 參數,bind()執行完返回一個新的函數。
新返回的函數如果用 new 字符來調用的話,那么之前this指向綁定到某個對象上 將會失效,并且初始函數中的this指向綁定到 new調用的 函數實例上。函數實例上還可以調用初始函數的原型上的方法
那么先實現第一個特點
// 因為需要所有函數都能執行,所以綁定到Function.prototype上 Function.prototype.bindFn=function(thisArg) { if(typeof this !== "function") { throw new TypeError(this+" is not a function"); } // 調用bindFn方法的函數的引用 var self = this; // 以數組形式保存第二個及其以后的參數 var beforeArg = [].slice.call(arguments,1); var bound = function() { // 以數組形式保存著當前函數的所有參數 var afterArg = [].slice.call(arguments); // bindFn第二個及其以后的參數和當前函數所有參數的 集合 // 全部傳到self函數的參數里 var finalArgs = beforeArg.concat(afterArg); // self中的this指向綁定到 thisArg return self.apply(thisArg, finalArgs); } return bound; } var obj1={sex:23}; function m1(a,b) { console.log(a+b); // 6 console.log(this); // {sex:23} } var bound=m1.bindFn(obj1,2); var result=bound(4);
可見m1中的this指向了obj1對象,2,4分別傳給了形參a,b。
進一步完善bindFn,實現第二個特點
// 因為需要所有函數都能執行,所以綁定到Function.prototype上 Function.prototype.bindFn=function(thisArg) { if(typeof this !== "function") { throw new TypeError(this +" is not a function"); } // 調用bindFn方法的函數的引用 var self = this; // 以數組形式保存第二個及其以后的參數 var beforeArg = [].slice.call(arguments,1); var bound = function() { // 以數組形式保存著當前函數的所有參數 var afterArg = [].slice.call(arguments); // bindFn第二個及其以后的參數和當前函數所有參數的 集合 // 全部傳到self函數的參數里 var finalArgs = beforeArg.concat(afterArg); // 如果new調用的話,this指向實例對象 // 否則this指向需要綁定的對象 // this instanceof bound并不準確,可以用es6中的new.target來解決 return self.apply(this instanceof bound ? this : thisArg, finalArgs); } // new調用的時候有用 // 避免es6中的箭頭函數 // 箭頭函數沒有prototype if(this.prototype) { // 避免修改 bound.prototype 污染到 this.prototype function a(){} a.prototype=this.prototype; bound.prototype=new a(); bound.prototype.constructor=bound; } return bound; } var obj1={sex:23}; function m1(a,b) { this.name="m1"; console.log(a+b); // 6 console.log(this); // {name:"m1"} } m1.prototype.allKey=function() { console.log("this is allkey"); } var bound=m1.bindFn(obj1,2); var result=new bound(4); result.allKey(); // this is allkey
可見,m1中的this指向了result這個實例對象,并且result 通過原型鏈 繼承了m1.prototype上的方法。
那么我們看下官方bind的使用:
// 關鍵部分 function m1(a,b) { this.name="m1"; console.log(a+b); // 6 console.log(this); // {name:"m1"} } var bound=m1.bind(obj1,2); var result=new bound(4); result.allKey(); // this is allkey
由上圖可見,雖然原型鏈上有所不同,但我們模擬的方法還是實現了bind的功能。我們模擬的方法bindFn參考mdn上的Polyfill。基本上關于模擬bind的實現就是這樣。
現在我們在延伸一下關于原型鏈的知識,如果剛才的bound.prototype完全重寫在了bound構造函數內,又會怎樣?
// 因為需要所有函數都能執行,所以綁定到Function.prototype上 Function.prototype.bindFn=function(thisArg) { if(typeof this !== "function") { throw new TypeError(this +": is not a function"); } // 調用bindFn方法的函數的引用 var self = this; // 以數組形式保存第二個及其以后的參數 var beforeArg = [].slice.call(arguments,1); var bound = function() { // 以數組形式保存著當前函數的所有參數 var afterArg = [].slice.call(arguments); // bindFn第二個及其以后的參數和當前函數所有參數的 集合 // 全部傳到self函數的參數里 var finalArgs = beforeArg.concat(afterArg); // 用new 方式調用 if(this instanceof bound) { // 避免es6箭頭函數 // 箭頭函數沒有prototype if(self.prototype) { // 避免修改 bound.prototype 污染到 self.prototype function a(){} a.prototype=self.prototype; bound.prototype=new a(); bound.prototype.constructor=bound; } // self中的this指向 new生成的實例對象 return self.apply(this,finalArgs); } // 無new 調用方式, self中的this指向thisArg return self.apply(thisArg, finalArgs); } bound.prototype.getKey=function() { } return bound; }; var obj1={sex:23}; function m1(a,b) { this.name="m1"; console.log(a+b); // 6 console.log(this); } m1.prototype.allKey=function() { console.log("this is allkey"); } var bound=m1.bindFn(obj1,2); var result=new bound(4); result.allKey(); // 報錯 result.allKey is not a function
按理說 result原型鏈上應該有allKey方法的,結果卻報錯了,我們把m1中的this打印一下看看
這里我們看到原型鏈上并沒有m1.prototype, 所以在構造函數內部 完全重寫 構造函數原型對象的話,原型鏈會與預想的不同。
那么圖上的bound.prototype打個 ? ,因為并不確定這個是bound.prototype,如果真是bound.prototype的話,那么下面的話如何解釋?
console.log(result.__proto__ === bound.prototype ) // false
按理說 result.__proto__ 指向的是bound.prototype,結果卻為false。所以不能肯定剛才的就是bound.prototype
總結: 完全重寫構造函數原型對象 要放在構造函數后面,如果放在構造函數里面,可能原型鏈會有錯誤。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99462.html
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器,提供的值被忽略,同時調用時的參數被提供給模擬函數。 bind() bind() 方法會創建一個新函數,當這個新函數被調用時,它的 this 值是傳遞給 bind() 的第一個參數,傳入bind方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。bind返回的綁定函數也能使用 n...
摘要:但是三作為構造函數時函數其實還有一個非常重要的特點返回的函數如果作為構造函數,搭配關鍵字出現的話,我們的綁定就需要被忽略。其次,當返回的函數作為構造函數時,之前綁定的會失效。 本文共 1100 字,讀完只需 4 分鐘 概述 前一篇文章我們嘗試模擬實現了 call 和 apply 方法,其實 bind 函數也可以用來改變 this 的指向。bind 和 call和 apply 兩者的區別...
摘要:點擊那么面試官可能會問是否想過到底做了什么,怎么模擬實現呢。另外前不久寫過一篇文章面試官問能否模擬實現的操作符。所以相當于調用時,的返回值函數內部要模擬實現實現的操作。文章中的例子和測試代碼放在中模擬實現。 前言 用過React的同學都知道,經常會使用bind來綁定this。 import React, { Component } from react; class TodoItem ...
摘要:也就是說當返回的函數作為構造函數的時候,時指定的值會失效,但傳入的參數依然生效。構造函數效果的優化實現但是在這個寫法中,我們直接將,我們直接修改的時候,也會直接修改函數的。 JavaScript深入系列第十一篇,通過bind函數的模擬實現,帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會創建一個新函數。當這個新函數被調用時,bind() 的第一個參數...
摘要:大致就是這樣所以可以模擬實現和。這些參數作為的第二個參數跟在后面,之后它們會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們的后面。 一個前端知識點匯總綜合了學習過程中的知識點,比如this、閉包、BFC、ES6等,如果大佬們覺得還可以的話,求個star啦! call和apply 每個函數都包含兩個非繼承而來的方法:apply()和call() 用途相同,都是在...
摘要:模擬和模擬一樣,現摘抄下面的代碼添加一個返回值對象然后我們定義一個函數,如果執行下面的代碼能夠返回和函數一樣的值,就達到我們的目的。 原文:https://zhehuaxuan.github.io/... 作者:zhehuaxuan 目的 本文主要用于理解和掌握call,apply和bind的使用和原理,本文適用于對它們的用法不是很熟悉,或者想搞清楚它們原理的童鞋。 好,那我們開始...
閱讀 3427·2021-09-26 09:46
閱讀 2782·2021-09-13 10:23
閱讀 3510·2021-09-07 10:24
閱讀 2388·2019-08-29 13:20
閱讀 2919·2019-08-28 17:57
閱讀 3072·2019-08-26 13:27
閱讀 1175·2019-08-26 12:09
閱讀 505·2019-08-26 10:27