成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS手寫bind之處理new的情況詳解

3403771864 / 534人閱讀

  你有遇見過給bind返回的函數(shù)做new操作的場景,本篇主要講述的就是實(shí)現(xiàn)一下兼容new操作的bind寫法,順便學(xué)習(xí)一下new操作符,為大家提供下參考。

  大家可以去看下關(guān)于 JS 中 bind 方法的實(shí)現(xiàn)的文章,并給出了實(shí)現(xiàn):

  Function.prototype.myBind = function(thisArg, ...prefixArgs) {
  const fn = this;
  return function(...args) {
  return fn.call(thisArg, ...prefixArgs, ...args);
  }
  }

  但沒有處理通過 new 創(chuàng)建實(shí)例的情況。

  我們沒考慮過給 bind 返回的函數(shù)做 new 操作的場景,主要就是這種情況極少遇見。

  但有時還是會出現(xiàn),在實(shí)現(xiàn)一下兼容 new 操作的 bind 寫法,順便學(xué)習(xí)一下 new 操作符。

  這里我推薦先看下前一篇文章:《前端面試題:手寫 bind》。

  new

  我們先學(xué)習(xí)一下 new 操作符。

  new 用于通過函數(shù)來創(chuàng)建一個對象實(shí)例,在很多語言中都能看到。

  JS 的函數(shù),除了可以是普通函數(shù),比如:

  function sum(a, b) {
  return a + b;
  }

  還可以是構(gòu)造函數(shù),只需要在構(gòu)造時在它前面加一個 new:

  function Person(name, age) {
  this.name = name;
  this.age = age;
  }
  const person = new Person('前端西瓜哥', 100)
  // Person {name: '前端西瓜哥', age: 100}

  new 創(chuàng)建一個新對象,做了下面幾件事:

  創(chuàng)建一個空對象{};

  空對象的原型屬性__proto__指向構(gòu)造函數(shù)的原型對象Person.prototype;

  函數(shù)中的 this 設(shè)置為這個空對象;

  如果該函數(shù)不返回一個對象,就返回這個 this,否則返回這個對象。

  判斷函數(shù)是否通過 new 被調(diào)用

  怎么判斷一個函數(shù)正在被 new 操作符調(diào)用?

  答案是使用 instanceof 判斷 this 是否為當(dāng)前函數(shù)的實(shí)例,即this instanceof Fn為 true,表示在通過 new 構(gòu)建實(shí)例。

  先看下實(shí)例:

  function Person() {
  if (this instanceof Person) {
  console.log('通過 new 構(gòu)建實(shí)例');
  } else {
  console.log('普通調(diào)用')
  }
  }
  Person() // 輸出:普通調(diào)用
  new Person() // 輸出:通過 new 構(gòu)建實(shí)例

  在 Vuejs 的源碼,你會看到下面代碼,這里也用到了這個技巧。

  function Vue(options) {
  if (__DEV__ && !(this instanceof Vue)) {
  warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
  }

  你在開發(fā)環(huán)境如果不通過 new 來使用 Vue 對象,會在控制臺提示你要通過 new 來調(diào)用 Vue。

  new 和 bind

  如果我們 new 的是 Function.prototype.bind 返回的新函數(shù),會發(fā)生什么事情?

  function Person(name, age) {
  this.name = name;
  this.age = age;
  }
  const BoundPerson = Person.bind(null, '前端西瓜哥');
  const boundPerson = new BoundPerson(100);
  // Person {name: '前端西瓜哥', age: 100}
  boundPerson.__proto__ === Person.prototype
  // true

  結(jié)果等價于直接去 new 原始函數(shù)。

  不同的是,仍舊可以進(jìn)行參數(shù)的預(yù)置??梢钥吹剑瑯?gòu)造函數(shù)的第一個參數(shù),在調(diào)用 bind 的時候就提前設(shè)置為 '前端西瓜哥'。

  實(shí)現(xiàn)完整的 bind

  完整實(shí)現(xiàn)如下:

  Function.prototype.myBind = function(thisArg, ...prefixArgs) {
  const fn = this;
  const boundFn = function(...args) {
  // 通過 new 使用當(dāng)前函數(shù)
  if (this instanceof boundFn) {
  return new fn(...prefixArgs, ...args);
  }
  // 普通的方法調(diào)用當(dāng)前函數(shù)
  return fn.call(thisArg, ...prefixArgs, ...args);
  }
  boundFn.prototype = fn.prototype;
  return boundFn;
  }

  這里我通過this instanceof boundFn來判斷是否用了 new,如果是,就直接 new 原始函數(shù)然后返回,記得帶上 bind 預(yù)置好的參數(shù)。

  和原本一樣(參照《前端面試題:手寫 bind》)。

  boundFn.prototype = fn.prototype;這個可寫可不寫,只是讓 bind 返回的新函數(shù)的 prototype 指向原函數(shù)的 prototype。

  如果是原生 bind 返回的函數(shù),它是沒有 protoype 屬性的,可以認(rèn)為它是一種特別的函數(shù),而我們實(shí)現(xiàn)的 bind 返回的卻是一個普通函數(shù),所以并不能完全模擬的。

  如果你追求完美的實(shí)現(xiàn),可以研讀一下Function.prototype.bind的標(biāo)準(zhǔn):

  然后再看看知名的core.js庫中對 bind 的實(shí)現(xiàn):

  其中核心實(shí)現(xiàn)為:

  // `Function.prototype.bind` method implementation
  // https://tc39.es/ecma262/#sec-function.prototype.bind
  module.exports = Function.bind || function bind(that /* , ...args */) {
  var F = aCallable(this);
  var Prototype = F.prototype;
  var partArgs = arraySlice(arguments, 1);
  var boundFunction = function bound(/* args... */) {
  var args = concat(partArgs, arraySlice(arguments));
  return this instanceof boundFunction ? construct(F, args.length, args) : F.apply(that, args);
  };
  if (isObject(Prototype)) boundFunction.prototype = Prototype;
  return boundFunction;
  };

  這里有更多的細(xì)節(jié):

  這里判斷了 this 是否為函數(shù)類型,不是函數(shù)會報錯;

  F.prototype 需要是一個對象或函數(shù),才能賦值給新函數(shù);

  使用了普通函數(shù)和 arguments,這是為了兼容 ES5。

  結(jié)尾

  手寫 bind,需要我們學(xué)習(xí)更多知識:

  bind 的詳盡用法:包括改變 this、預(yù)置參數(shù)、new 的表現(xiàn);

  閉包的使用:保存一些私有變量;

  通過原型鏈的方式(this instanceof boundFn)判斷是否通過 new 調(diào)用當(dāng)前函數(shù);

  使用 call 在執(zhí)行時改變函數(shù)的 this 指向。

  以上就是全部內(nèi)容,歡迎大家繼續(xù)關(guān)注后續(xù)更多精彩內(nèi)容。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/128375.html

相關(guān)文章

  • 22道JavaScript高頻手寫面試題

    JavaScript筆試部分 點(diǎn)擊關(guān)注本公眾號獲取文檔最新更新,并可以領(lǐng)取配套于本指南的 《前端面試手冊》 以及最標(biāo)準(zhǔn)的簡歷模板. 實(shí)現(xiàn)防抖函數(shù)(debounce) 防抖函數(shù)原理:在事件被觸發(fā)n秒后再執(zhí)行回調(diào),如果在這n秒內(nèi)又被觸發(fā),則重新計(jì)時。 那么與節(jié)流函數(shù)的區(qū)別直接看這個動畫實(shí)現(xiàn)即可。 showImg(https://segmentfault.com/img/remote/146000002...

    Alan 評論0 收藏0
  • 「中高級前端面試」JavaScript手寫代碼無敵秘籍

    摘要:第一種直接調(diào)用避免在不必要的情況下使用,是一個危險的函數(shù),他執(zhí)行的代碼擁有著執(zhí)行者的權(quán)利。來自于此外,實(shí)現(xiàn)需要考慮實(shí)例化后對原型鏈的影響。函數(shù)柯里化的主要作用和特點(diǎn)就是參數(shù)復(fù)用提前返回和延遲執(zhí)行。手寫路徑導(dǎo)航 實(shí)現(xiàn)一個new操作符 實(shí)現(xiàn)一個JSON.stringify 實(shí)現(xiàn)一個JSON.parse 實(shí)現(xiàn)一個call或 apply 實(shí)現(xiàn)一個Function.bind 實(shí)現(xiàn)一個繼承 實(shí)現(xiàn)一個J...

    Zhuxy 評論0 收藏0
  • 面試題里那些各種手寫

    摘要:最近準(zhǔn)備初級前端面試,發(fā)現(xiàn)有很多手寫實(shí)現(xiàn)什么的,例如什么手寫實(shí)現(xiàn),。后面以這道題為引線面試官可能會追問什么是執(zhí)行上下文的判斷,的區(qū)別手寫一個函數(shù)實(shí)現(xiàn)斐波那契數(shù)列首先拷一個阮神在他教程里的一個寫法。 最近準(zhǔn)備初級前端面試,發(fā)現(xiàn)有很多手寫實(shí)現(xiàn)什么的,例如什么手寫實(shí)現(xiàn)bind,promise。手寫ajax,手寫一些算法。翻閱了很多書籍和博客。 這里做一個總結(jié)改進(jìn),算是對我后面大概為期一個月找...

    wh469012917 評論0 收藏0
  • 2019-我前端面試題

    摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關(guān)問題,其他公司壓根沒問。我自己回答的是自己開發(fā)組件面臨的問題。完全不用擔(dān)心對方到時候打電話核對的問題。 2019的5月9號,離發(fā)工資還有1天的時候,我的領(lǐng)導(dǎo)親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經(jīng)是第2個月沒工資了。 公...

    iKcamp 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<