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

資訊專欄INFORMATION COLUMN

如何寫一個(gè)實(shí)用的bind?

zhaofeihao / 464人閱讀

摘要:方法創(chuàng)建一個(gè)新的函數(shù)當(dāng)被調(diào)用時(shí),它的關(guān)鍵字被設(shè)置為提供的值。語(yǔ)法簡(jiǎn)單地看一下這些參數(shù)的含義當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的指向當(dāng)使用操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無(wú)效。結(jié)尾文章很簡(jiǎn)短,知道怎么實(shí)現(xiàn)一個(gè)原生的就行。

前言

這是underscore.js源碼分析的第五篇,如果你對(duì)這個(gè)系列感興趣,歡迎點(diǎn)擊

underscore-analysis/ watch一下,隨時(shí)可以看到動(dòng)態(tài)更新。

事情要從js中的this開(kāi)始說(shuō)起,你是不是也經(jīng)常有種無(wú)法掌控和知曉它的感覺(jué),對(duì)于初學(xué)者來(lái)說(shuō),this簡(jiǎn)直如同回調(diào)地獄般,神乎其神,讓人無(wú)法捉摸透。但是通過(guò)原生js中的bind方法,我們可以顯示綁定函數(shù)的this作用域,而無(wú)需擔(dān)心運(yùn)行時(shí)是否會(huì)改變而不符合自己的預(yù)期。當(dāng)然了下劃線中的bind也是模仿它的功能同樣可以達(dá)到類似的效果。

bind簡(jiǎn)單回顧

我們從mdn上的介紹來(lái)回顧一下bind的使用方法。

bind方法創(chuàng)建一個(gè)新的函數(shù), 當(dāng)被調(diào)用時(shí),它的this關(guān)鍵字被設(shè)置為提供的值。

語(yǔ)法

fun.bind(thisArg[, arg1[, arg2[, ...]]])

簡(jiǎn)單地看一下這些參數(shù)的含義

thisArg

當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的this指向,當(dāng)使用new 操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無(wú)效。

arg1, arg2, ...

當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法。

綁定this作用域示例

window.name = "windowName"

let obj = {
  name: "qianlongo",
  showName () {
    console.log(this.name)
  }
}

obj.showName() // qianlongo

let showName = obj.showName
  showName() // windowName

let bindShowName = obj.showName.bind(obj)
  bindShowName() // qianlongo

通過(guò)以上簡(jiǎn)單示例,我們知道了第一個(gè)參數(shù)的作用就是綁定函數(shù)運(yùn)行時(shí)候的this指向

第二個(gè)參數(shù)開(kāi)始起使用示例

let sum = (num1, num2) => {
  console.log(num1 + num2)
}

let bindSum = sum.bind(null, 1)
bindSum(2) // 3

bind可以使一個(gè)函數(shù)擁有預(yù)設(shè)的初始參數(shù)。這些參數(shù)(如果有的話)作為bind的第二個(gè)參數(shù)跟在this(或其他對(duì)象)后面,之后它們會(huì)被插入到目標(biāo)函數(shù)的參數(shù)列表的開(kāi)始位置,傳遞給綁定函數(shù)的參數(shù)會(huì)跟在它們的后面。

參數(shù)的使用基本上明白了,我們?cè)賮?lái)看看使用new去調(diào)用bind之后的函數(shù)是怎么回事。

function Person (name, sex) {
  console.log(this) // Person {}
  this.name = name
  this.sex = sex
}
let obj = {
  age: 100
}
let bindPerson = Person.bind(obj, "qianlongo")

let p = new bindPerson("boy")

console.log(p) // Person {name: "qianlongo", sex: "boy"}

有沒(méi)有發(fā)現(xiàn)bindPerson內(nèi)部的this不再是bind的第一個(gè)參數(shù)obj,此時(shí)obj已經(jīng)不再起效了。

實(shí)際上bind的使用是有一定限制的,在一些低版本瀏覽器下不可用,你想不想看看下劃線中是如何實(shí)現(xiàn)一個(gè)兼容性好的bind呢?。。ome on

下劃線中bind實(shí)現(xiàn)

源碼

 _.bind = function(func, context) {
  // 如果原生支持bind函數(shù),就用原生的,并將對(duì)應(yīng)的參數(shù)傳進(jìn)去
  if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
  // 如果傳入的func不是一個(gè)函數(shù)類型 就拋出異常
  if (!_.isFunction(func)) throw new TypeError("Bind must be called on a function");
  // 把第三個(gè)參數(shù)以后的值存起來(lái),接下來(lái)請(qǐng)看executeBound
  var args = slice.call(arguments, 2);
  var bound = function() {
    return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
  };
  return bound;
};

executeBound實(shí)現(xiàn)

var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
  // 如果調(diào)用方式不是new func的形式就直接調(diào)用sourceFunc,并且給到對(duì)應(yīng)的參數(shù)即可
  if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); 
  // 處理new調(diào)用的形式
  var self = baseCreate(sourceFunc.prototype);
  var result = sourceFunc.apply(self, args);
  if (_.isObject(result)) return result;
  return self;
};

上面的源碼都做了相應(yīng)的注釋,我們著重來(lái)看一下executeBound的實(shí)現(xiàn)

先看一下這些參數(shù)都代表什么含義

sourceFunc:原函數(shù),待綁定函數(shù)

boundFunc: 綁定后函數(shù)

context:綁定后函數(shù)this指向的上下文

callingContext:綁定后函數(shù)的執(zhí)行上下文,通常就是 this

args:綁定后的函數(shù)執(zhí)行所需參數(shù)

ok,我們來(lái)看一下第一句

if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); 

這句話是為了判斷綁定后的函數(shù)是以new關(guān)鍵字被調(diào)用還是普通的函數(shù)調(diào)用的方式,舉個(gè)例子

function Person () {
  if (!(this instanceof Person)) {
    return console.log("非new調(diào)用方式")
  }

  console.log("new 調(diào)用方式")
}

Person() // 非new調(diào)用方式
new Person() // new 調(diào)用方式

所以如果你希望自己寫的構(gòu)造函數(shù)無(wú)論是new還是沒(méi)用new都起效的話可以用下面的代碼

function Person (name, sex) {
  if (!(this instanceof Person)) {
    return new Person(name, sex)
  }

  this.name = name
  this.sex = sex
}

new Person("qianlongo", "boy") // Person {name: "qianlongo", sex: "boy"}

Person("qianlongo", "boy") // Person {name: "qianlongo", sex: "boy"}

我們回到executeBound的解析

if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); 

callingContext是被綁定后的函數(shù)的this作用域,boundFunc就是那個(gè)被綁定后的函數(shù),那么通過(guò)這個(gè)if判斷,當(dāng)為非new調(diào)用形式的時(shí)候,直接利用apply處理即可。

但是如果是用new調(diào)用的呢?我們看下面這段代碼,別看短短的四行代碼里面知識(shí)點(diǎn)挺多的呢!

// 這里拿到的是一個(gè)空對(duì)象,且其繼承于原函數(shù)的原型鏈prototype
var self = baseCreate(sourceFunc.prototype);
// 構(gòu)造函數(shù)執(zhí)行之后的返回值
// 一般情況下是沒(méi)有返回值的,也就是undefined
// 但是有時(shí)候?qū)憳?gòu)造函數(shù)的時(shí)候會(huì)顯示地返回一個(gè)obj
var result = sourceFunc.apply(self, args);
// 所以去判斷結(jié)果是不是object,如果是那么返回構(gòu)造函數(shù)返回的object
if (_.isObject(result)) return result;
// 如果沒(méi)有顯示返回object,就返回原函數(shù)執(zhí)行結(jié)束后的實(shí)例
return self;

好,到這里,我有一個(gè)疑問(wèn),baseCreate是個(gè)什么鬼?

var Ctor = function(){};

var baseCreate = function(prototype) {
  // 如果prototype不是object類型直接返回空對(duì)象
  if (!_.isObject(prototype)) return {};
  // 如果原生支持create則用原生的
  if (nativeCreate) return nativeCreate(prototype); 
  // 將prototype賦值為Ctor構(gòu)造函數(shù)的原型
  Ctor.prototype = prototype; 
  // 創(chuàng)建一個(gè)Ctor實(shí)例對(duì)象
  var result = new Ctor; 
  // 為了下一次使用,將原型清空
  Ctor.prototype = null; 
  // 最后將實(shí)例返回
  return result; 
};

是不是好簡(jiǎn)單,就是實(shí)現(xiàn)了原生的Object.create用來(lái)做一些繼承的事情。

結(jié)尾

文章很簡(jiǎn)短,知道怎么實(shí)現(xiàn)一個(gè)原生的bind就行。如果你對(duì)apply、call和this感興趣,歡迎查看

js中call、apply、bind那些事

[this-想說(shuō)愛(ài)你不容易](https://qianlongo.github.io/2...
)

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

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

相關(guān)文章

  • 如何一個(gè)實(shí)用bind?

    摘要:方法創(chuàng)建一個(gè)新的函數(shù)當(dāng)被調(diào)用時(shí),它的關(guān)鍵字被設(shè)置為提供的值。語(yǔ)法簡(jiǎn)單地看一下這些參數(shù)的含義當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的指向當(dāng)使用操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無(wú)效。結(jié)尾文章很簡(jiǎn)短,知道怎么實(shí)現(xiàn)一個(gè)原生的就行。 前言 這是underscore.js源碼分析的第五篇,如果你對(duì)這個(gè)系列感興趣,歡迎點(diǎn)擊 underscore-analysis/ watch一下,隨時(shí)可以看到動(dòng)態(tài)...

    Prasanta 評(píng)論0 收藏0
  • 一行代碼看懂bind,call

    摘要:代碼方法返回一個(gè)新的數(shù)組對(duì)象原數(shù)組的淺拷貝,常用于動(dòng)態(tài)解析參數(shù)??催^(guò)的童鞋,對(duì)這行代碼不會(huì)陌生。所以筆者覺(jué)得,從理解角度來(lái)看,新創(chuàng)建的函數(shù)命名為更便于理解??偨Y(jié)乍一看,函數(shù)有點(diǎn)繞,一經(jīng)推敲還是很好理解的。 代碼 var slice = Function.prototype.call.bind(Array.prototype.slice); slice() 方法返回一個(gè)新的數(shù)組對(duì)象(原數(shù)...

    Lavender 評(píng)論0 收藏0
  • Android開(kāi)源架構(gòu)

    摘要:音樂(lè)團(tuán)隊(duì)分享數(shù)據(jù)綁定運(yùn)行機(jī)制分析一個(gè)項(xiàng)目搞定所有主流架構(gòu)單元測(cè)試一個(gè)項(xiàng)目搞定所有主流架構(gòu)系列的第二個(gè)項(xiàng)目。代碼開(kāi)源,展示了的用法,以及如何使用進(jìn)行測(cè)試,還有用框架對(duì)的進(jìn)行單元測(cè)試。 Android 常用三方框架的學(xué)習(xí) Android 常用三方框架的學(xué)習(xí) likfe/eventbus3-intellij-plugin AS 最新可用 eventbus3 插件,歡迎品嘗 簡(jiǎn)單的 MVP 模...

    sutaking 評(píng)論0 收藏0
  • 實(shí)用模式之中介者模式

    摘要:好,師傅我們要學(xué)習(xí)帝吧人民,進(jìn)能打,退能刷淘寶。恩,大致過(guò)程就是這樣,我們使用中介者模式想一想。首先,數(shù)據(jù)需要放在中介者模式內(nèi),用戶的一切操作,都會(huì)傳遞給中介者模式,由他來(lái)選擇是哪一個(gè)部分發(fā)生改變。 俗話說(shuō),一個(gè)模式三個(gè)坑。 中介者模式應(yīng)該算最坑的一個(gè)模式,坑不在于他的原理。而在于他的名字和其他模式的使用,真尼瑪像。首先,中介者 好像是一切模式里面都有的一個(gè)東西,比如,享元模式中-元對(duì)...

    AlexTuan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<