国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[譯]Mixin 函數(shù)

zxhaaa / 2311人閱讀

摘要:函數(shù)通常是面向?qū)ο缶幊田L(fēng)格,具有副作用。因?yàn)樵诤瘮?shù)式編程中,很有可能這些引用指向的并不是同一個(gè)對(duì)象。記住,函數(shù)并不意味著函數(shù)式編程。函數(shù)可以用函數(shù)式編程風(fēng)格編寫,避免副作用并不修改參數(shù),但這并不保證。

軟件構(gòu)建系列

原文鏈接:Functional Mixins
譯者注:在編程中,mixin 類似于一個(gè)固有名詞,可以理解為混合或混入,通常不進(jìn)行直譯,本文也是同樣。

這是“軟件構(gòu)建”系列教程的一部分,該系列主要從 JavaScript ES6+ 中學(xué)習(xí)函數(shù)式編程,以及軟件構(gòu)建技術(shù)。敬請(qǐng)關(guān)注。
上一篇 | 第一篇

Mixin 函數(shù) 是指能夠給對(duì)象添加屬性或行為,并可以通過(guò)管道連接在一起的組合工廠函數(shù),就如同流水線上的工人。Mixin 函數(shù)不依賴或要求一個(gè)基礎(chǔ)工廠或構(gòu)造函數(shù):簡(jiǎn)單地將任意一個(gè)對(duì)象傳入一個(gè) mixin,就會(huì)得到一個(gè)增強(qiáng)之后的對(duì)象。

Mixin 函數(shù)的特點(diǎn):

數(shù)據(jù)封裝

繼承私有狀態(tài)

多繼承

覆蓋重復(fù)屬性

無(wú)需基礎(chǔ)類

動(dòng)機(jī)

現(xiàn)代軟件開發(fā)的核心就是組合:我們將一個(gè)龐大復(fù)雜的問(wèn)題,分解成更小,更簡(jiǎn)單的問(wèn)題,最終將這些問(wèn)題的解決辦法組合起來(lái)就變成了一個(gè)應(yīng)用程序。

組合的最小單位就是以下兩者之一:

函數(shù)

數(shù)據(jù)結(jié)構(gòu)

他們的組合就定義了應(yīng)用的結(jié)構(gòu)。

通常,組合對(duì)象由類繼承實(shí)現(xiàn),其中子類從父類繼承其大部分功能,并擴(kuò)展或覆蓋部分。這種方法導(dǎo)致了 is-a 問(wèn)題,比如:管理員是一名員工,這引發(fā)了許多設(shè)計(jì)問(wèn)題:

高耦合:由于子類的實(shí)現(xiàn)依賴于父類,所以類繼承是面向?qū)ο笤O(shè)計(jì)中最緊密的耦合。

脆弱的子類:由于高耦合,對(duì)父類的修改可能會(huì)破壞子類。軟件作者可能在不知情的情況下破壞了第三方管理的代碼。

層次不靈活:根據(jù)單一祖先分類,隨著長(zhǎng)時(shí)間的演變,最終所有的類都將不適用于新用例。

重復(fù)問(wèn)題:由于層次不靈活,新用例通常是通過(guò)重復(fù)而不是擴(kuò)展來(lái)實(shí)現(xiàn)的,這導(dǎo)致不同的類有著相似的類結(jié)構(gòu)。而一旦重復(fù)創(chuàng)建,在創(chuàng)建其子類時(shí),該繼承自哪個(gè)類以及為什么繼承于這個(gè)類就不清晰了。

大猩猩和香蕉問(wèn)題:“...面向?qū)ο笳Z(yǔ)言的問(wèn)題是他們會(huì)獲得所有與之相關(guān)的隱含環(huán)境。比如你想要一個(gè)香蕉,但你得到的會(huì)是一只拿著香蕉的大猩猩,以及一整片叢林。” - Joe Armstrong(Coders at Work)

假設(shè)管理員是一名員工,你如何處理聘請(qǐng)外部顧問(wèn)暫時(shí)行使管理員職務(wù)的情況?(譯者:木知啊~)如果你事先知道所有的需求,類繼承可能有效,但我從沒有看到過(guò)這種情況。隨著不斷地使用,新問(wèn)題和更有效的流程將會(huì)被發(fā)現(xiàn),應(yīng)用程序和需求不可避免地隨著時(shí)間的推移而發(fā)展和演變。

Mixin 提供了更靈活的方法。

什么是 Mixin?

“組合優(yōu)于繼承。” - 設(shè)計(jì)模式:可重用面向?qū)ο筌浖脑?/p>

Mixin 是對(duì)象組合的一種,它將部分特性混入復(fù)合對(duì)象中,使得這些屬性成為復(fù)合對(duì)象的屬性。

面向?qū)ο缶幊讨械?"mixin" 一詞來(lái)源于冰激凌店。不同于將不同口味的冰激凌預(yù)先混合,每個(gè)顧客可以自由混合各種口味的冰激凌,從而創(chuàng)造出屬于自己的冰激凌口味。

對(duì)象 mixin 與之類似:從一個(gè)空對(duì)象開始,然后一步步擴(kuò)展它。由于 JavaScript 支持動(dòng)態(tài)對(duì)象擴(kuò)展,所以在 JavaScript 中使用對(duì)象 mixin 是非常簡(jiǎn)單的。它也是 JavaScript 中最常見的繼承形式,來(lái)看一個(gè)例子:

const chocolate = {
  hasChocolate: () => true
};
const caramelSwirl = {
  hasCaramelSwirl: () => true
};
const pecans = {
  hasPecans: () => true
};
const iceCream = Object.assign({}, chocolate, caramelSwirl, pecans);
/*
// 支持對(duì)象擴(kuò)展符的話也可以寫成這樣...
const iceCream = {...chocolate, ...caramelSwirl, ...pecans};
*/
console.log(`
  hasChocolate: ${ iceCream.hasChocolate() }
  hasCaramelSwirl: ${ iceCream.hasCaramelSwirl() }
  hasPecans: ${ iceCream.hasPecans() }
`);

/* 輸出
  hasChocolate: true
  hasCaramelSwirl: true
  hasPecans: true
*/
什么是函數(shù)繼承?

函數(shù)繼承是指通過(guò)函數(shù)來(lái)增強(qiáng)對(duì)象實(shí)例實(shí)現(xiàn)特性繼承的過(guò)程。該函數(shù)建立一個(gè)閉包使得部分?jǐn)?shù)據(jù)是私有的,并通過(guò)動(dòng)態(tài)對(duì)象擴(kuò)展使得對(duì)象實(shí)例擁有新的屬性和方法。

來(lái)看一下這個(gè)詞的創(chuàng)造者 Douglas Crockford 所給出的例子。

// 父類
function base(spec) {
    var that = {}; // Create an empty object
    that.name = spec.name; // Add it a "name" property
    return that; // Return the object
}
// 子類
function child(spec) {
    // 調(diào)用父類構(gòu)造函數(shù)
    var that = base(spec); 
    that.sayHello = function() { // Augment that object
        return "Hello, I"m " + that.name;
    };
    return that; // Return it
}
// Usage
var result = child({ name: "a functional object" });
console.log(result.sayHello()); // "Hello, I"m a functional object"

由于 child()base() 緊密耦合在一起,當(dāng)你想添加 grandchild(), greatGrandchild() 等時(shí),你將面對(duì)類繼承中許多常見的問(wèn)題。

什么是 Mixin 函數(shù)?

Mixin 函數(shù)是一系列將新的屬性或行為混入特定對(duì)象的組合函數(shù)。它不依賴或需要一個(gè)基礎(chǔ)工廠方法或構(gòu)造器,只需將任意對(duì)象傳入一個(gè) mixin 方法,它就會(huì)被擴(kuò)展。

來(lái)看下面的例子。

const flying = o => {
  let isFlying = false;
  return Object.assign({}, o, {
    fly () {
      isFlying = true;
      return this;
    },
    isFlying: () => isFlying,
    land () {
      isFlying = false;
      return this;
    }
  });
};
const bird = flying({});
console.log( bird.isFlying() ); // false
console.log( bird.fly().isFlying() ); // true

這里需要注意,當(dāng)調(diào)用 flying() 時(shí)需要傳遞一個(gè)被擴(kuò)展的對(duì)象。Mixin 函數(shù)被設(shè)計(jì)用來(lái)實(shí)現(xiàn)函數(shù)組合,繼續(xù)看下去。

const quacking = quack => o => Object.assign({}, o, {
  quack: () => quack
});
const quacker = quacking("Quack!")({});
console.log( quacker.quack() ); // "Quack!"
組合 Mixin 函數(shù)

通過(guò)簡(jiǎn)單的函數(shù)組合就可以將 mixin 函數(shù)組合起來(lái)。

const createDuck = quack => quacking(quack)(flying({}));
const duck = createDuck("Quack!");
console.log(duck.fly().quack());

但是,這看上去有點(diǎn)丑陋,調(diào)試或重新排列組合順序也有點(diǎn)困難。

當(dāng)然,這只是標(biāo)準(zhǔn)的函數(shù)組合,而我們可以通過(guò)一些好的辦法來(lái)將它們組合起來(lái),比如 compose()pipe()。如果,使用 pipe() 就需反轉(zhuǎn)函數(shù)的調(diào)用順序,才能保持相同的執(zhí)行順序。當(dāng)屬性沖突時(shí),最后的屬性生效。

const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
// OR...
// import pipe from `lodash/fp/flow`;
const createDuck = quack => pipe(
  flying,
  quacking(quack)
)({});
const duck = createDuck("Quack!");
console.log(duck.fly().quack());
Mixin 函數(shù)的使用場(chǎng)景

你應(yīng)當(dāng)總是使用最簡(jiǎn)單的抽象來(lái)解決問(wèn)題。從純函數(shù)開始。如果需要一個(gè)持久化狀態(tài)的對(duì)象,就試試工廠方法。如果你需要構(gòu)建更復(fù)雜的對(duì)象,那就試試 Mixin 函數(shù)。

以下是一些使用 Mixin 函數(shù)很棒的例子:

應(yīng)用狀態(tài)管理,比如,Redux

某些橫向服務(wù),比如,集中日志處理

組件生命周期函數(shù)

功能可組合的數(shù)據(jù)類型,比如,JavaScript Array 類實(shí)現(xiàn)了 Semigroup, Functor, Foldable

一些代數(shù)結(jié)構(gòu)可以根據(jù)其他代數(shù)結(jié)構(gòu)得出,這意味著新的數(shù)據(jù)類型可以通過(guò)某些推導(dǎo)組合而成,而不需要定制。

注意事項(xiàng)

大部分問(wèn)題都可以使用純函數(shù)優(yōu)雅地解決。然而,mixin 函數(shù)同類繼承一樣,會(huì)造成一些問(wèn)題。事實(shí)上,使用 mixin 函數(shù)能夠完全復(fù)制類繼承的優(yōu)缺點(diǎn)。

你應(yīng)當(dāng)遵循以下的建議來(lái)避免這些問(wèn)題。

使用最簡(jiǎn)單的實(shí)現(xiàn)。從左邊開始,根據(jù)需要移到右邊。純函數(shù) > 工廠方法 > mixin 函數(shù) > 類繼承

避免創(chuàng)建對(duì)象,mixin,或數(shù)據(jù)類型之間的 is-a 關(guān)系

避免 mixins 之間的隱含依賴關(guān)系,mixin 函數(shù)應(yīng)當(dāng)是獨(dú)立的

mixin 函數(shù)并不意味著函數(shù)式編程

類繼承

在 JavaScript 中,類繼承在極少情況下(也許永遠(yuǎn)不)會(huì)是最佳方案,但這通常是一些不由你控制的庫(kù)或框架。在這種場(chǎng)景下,類有時(shí)是實(shí)用的。

無(wú)需擴(kuò)展你自己的類(不需要你建立多層次的類結(jié)構(gòu))

無(wú)需使用 new 關(guān)鍵字,也就是說(shuō),框架會(huì)替你實(shí)例化

Angular 2+ 和 React 滿足這些需求,所以你無(wú)需擴(kuò)展你自己的類,而是放心地使用它們的類。在 React 中,你可以不使用類,不過(guò)這樣你的組件將不會(huì)獲得 React 的優(yōu)化,并且你的組件也會(huì)同文檔中的例子不同。但無(wú)論如何,使用函數(shù)構(gòu)建 React 組件總是你的首選。

性能

在一些瀏覽器中,類會(huì)獲得 JavaScript 引擎的優(yōu)化,其他的則無(wú)法直接使用。在幾乎所有情況下,這些優(yōu)化都不會(huì)對(duì)程序產(chǎn)生決定性的影響。事實(shí)上,在接下去的幾年中,你都無(wú)需關(guān)心類在性能上的不同。無(wú)論你如何構(gòu)建對(duì)象,對(duì)象創(chuàng)建和屬性訪問(wèn)總是非常快的(每秒百萬(wàn)次)。

也就是說(shuō),類似 RxJS,Lodash 等公共庫(kù)的作者應(yīng)該研究使用 class 創(chuàng)建對(duì)象實(shí)例可能的性能優(yōu)勢(shì)。除非你能夠證明通過(guò)類能夠解決性能瓶頸,否則,你就應(yīng)當(dāng)使你的代碼保持干凈、靈活,而不必?fù)?dān)心性能。

隱式依賴

你可能打算創(chuàng)建一些計(jì)劃用于一同工作的 mixin 函數(shù)。試想一下,你想要為你的應(yīng)用添加一個(gè)配置管理器,當(dāng)你訪問(wèn)不存在的配置屬性時(shí),它會(huì)提示警告,像這樣:

// log 模塊
const withLogging = logger => o => Object.assign({}, o, {
  log (text) {
    logger(text)
  }
});

// 確認(rèn)配置項(xiàng)存在模塊,同 log 模塊無(wú)關(guān),這里只是確保 log 存在
const withConfig = config => (o = {
  log: (text = "") => console.log(text)
}) => Object.assign({}, o, {
  get (key) {
    return config[key] == undefined ?
      // vvv 隱式依賴! vvv
      this.log(`Missing config key: ${ key }`) :
      // ^^^ 隱式依賴! ^^^
      config[key]
    ;
  }
});
// 模塊封裝
const createConfig = ({ initialConfig, logger }) =>
  pipe(
    withLogging(logger),
    withConfig(initialConfig)
  )({})
;
// 調(diào)用
const initialConfig = {
  host: "localhost"
};
const logger = console.log.bind(console);
const config = createConfig({initialConfig, logger});
console.log(config.get("host")); // "localhost"
config.get("notThere"); // "Missing config key: notThere"

也可以是這樣,

// 引入 log 模塊
import withLogging from "./with-logging";
const addConfig = config => o => Object.assign({}, o, {
  get (key) {
    return config[key] == undefined ? 
      this.log(`Missing config key: ${ key }`) :
      config[key]
    ;
  }
});
const withConfig = ({ initialConfig, logger }) => o =>
  pipe(
    // vvv 明確的依賴! vvv
    withLogging(logger),
    // ^^^ 明確的依賴! ^^^
    addConfig(initialConfig)
  )(o)
;
// 工廠方法
const createConfig = ({ initialConfig, logger }) =>
  withConfig({ initialConfig, logger })({})
;

// 另一模塊
const initialConfig = {
  host: "localhost"
};
const logger = console.log.bind(console);
const config = createConfig({initialConfig, logger});
console.log(config.get("host")); // "localhost"
config.get("notThere"); // "Missing config key: notThere"

選擇隱式還是顯式取決于很多因素。Mixin 函數(shù)作用的數(shù)據(jù)類型必須是有效的,這就需要 API 文檔中的函數(shù)簽名非常清晰。

這就是隱式依賴版本中為 o 添加默認(rèn)值的原因。由于 JavaScript 缺少類型注釋功能,但我們可以通過(guò)默認(rèn)值來(lái)代替它。

const withConfig = config => (o = {
  log: (text = "") => console.log(text)
}) => Object.assign({}, o, {
  // ...

如果你使用 TypeScript 或 Flow,最好為你的對(duì)象參數(shù)定義一個(gè)明確的接口。

Mixin 函數(shù)與函數(shù)式編程

Mixin 函數(shù)并不像函數(shù)式編程那樣純。Mixin 函數(shù)通常是面向?qū)ο缶幊田L(fēng)格,具有副作用。許多 Mixin 函數(shù)會(huì)改變傳入的參數(shù)對(duì)象。注意!

出于同樣的原因,一些開發(fā)者更喜歡函數(shù)式編程風(fēng)格,不修改傳入的對(duì)象。在編寫 mixin 時(shí),你應(yīng)當(dāng)適當(dāng)?shù)厥褂眠@兩種編碼風(fēng)格。

這意味著,如果你要返回對(duì)象的實(shí)例,則始終返回 this,而不是閉包中對(duì)象實(shí)例的引用。因?yàn)樵诤瘮?shù)式編程中,很有可能這些引用指向的并不是同一個(gè)對(duì)象。另外,總是使用 Object.assign(){...object, ...spread} 語(yǔ)法進(jìn)行復(fù)制。但需要注意的是,非枚舉的屬性將不會(huì)存在于最終的對(duì)象上。

const a = Object.defineProperty({}, "a", {
  enumerable: false,
  value: "a"
});
const b = {
  b: "b"
};
console.log({...a, ...b}); // { b: "b" }

出于同樣的原因,如果你使用的 mixin 函數(shù)不是自己構(gòu)建的,就不要認(rèn)為它就是純的。假設(shè)基礎(chǔ)對(duì)象會(huì)被改變,假設(shè)它可能會(huì)產(chǎn)生副作用,不保證參數(shù)不會(huì)改變,即由 mixin 函數(shù)組合而成的記錄工廠通常是不安全的。

結(jié)論

Mixin 函數(shù)是可組合的工廠方法,它能夠?yàn)閷?duì)象添加屬性和行為,就如同裝配線上的站。它是將多個(gè)來(lái)源的功能(has-a, uses-a, can-do)組合成行為的好方法,而不是從一個(gè)類上繼承所有功能(is-a)。

記住,“mixin 函數(shù)” 并不意味著“函數(shù)式編程”。Mixin 函數(shù)可以用函數(shù)式編程風(fēng)格編寫,避免副作用并不修改參數(shù),但這并不保證。第三方 mixin 可能存在副作用和不確定性。

不同于對(duì)象 mixin,mixin 函數(shù)支持正真的私有數(shù)據(jù)(封裝),包括繼承私有數(shù)據(jù)的能力。

不同于單繼承,mixin 函數(shù)還支持繼承多個(gè)祖先的能力,類似于類裝飾器或多繼承。

不同于 C++ 中的多繼承,JavaScript 中很少出現(xiàn)屬性沖突問(wèn)題,當(dāng)屬性沖突發(fā)生時(shí),總是最后添加的 mixin 有效。

不同于類裝飾器或多繼承,不需要基類

總是從最簡(jiǎn)單的實(shí)現(xiàn)方式開始,只根據(jù)需要使用更復(fù)雜的實(shí)現(xiàn)方式:

純函數(shù) > 工廠方法 > mixin 函數(shù) > 類繼承

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/83670.html

相關(guān)文章

  • 』React Mixin 的使用

    摘要:可以說(shuō),相比繼承而已,更喜歡這種組合的方式。需要指出的是,是可以包含在其他的中的程序會(huì)在控制臺(tái)打印出。包含多個(gè)我們的要包裹在數(shù)組當(dāng)中,提醒了我們可以在組件中包含多個(gè)注意事項(xiàng)這里有幾件事需要引起我們的注意,當(dāng)我們使用的時(shí)候。 update: Mixin 只適用于 ES5。如果你的項(xiàng)目里面用的是 ES6 ,可以采用高階組件來(lái)實(shí)現(xiàn) Mixin 的功能。 我使用 React.js 構(gòu)建大型項(xiàng)目...

    張巨偉 評(píng)論0 收藏0
  • [] 為什么原型繼承很重要

    摘要:使用構(gòu)造函數(shù)的原型繼承相比使用原型的原型繼承更加復(fù)雜,我們先看看使用原型的原型繼承上面的代碼很容易理解。相反的,使用構(gòu)造函數(shù)的原型繼承像下面這樣當(dāng)然,構(gòu)造函數(shù)的方式更簡(jiǎn)單。 五天之前我寫了一個(gè)關(guān)于ES6標(biāo)準(zhǔn)中Class的文章。在里面我介紹了如何用現(xiàn)有的Javascript來(lái)模擬類并且介紹了ES6中類的用法,其實(shí)它只是一個(gè)語(yǔ)法糖。感謝Om Shakar以及Javascript Room中...

    xiao7cn 評(píng)論0 收藏0
  • 學(xué)習(xí) underscore 源碼整體架構(gòu),打造屬于自己的函數(shù)式編程類庫(kù)

    摘要:譯立即執(zhí)行函數(shù)表達(dá)式處理支持瀏覽器環(huán)境微信小程序。學(xué)習(xí)整體架構(gòu),利于打造屬于自己的函數(shù)式編程類庫(kù)。下一篇文章可能是學(xué)習(xí)的源碼整體架構(gòu)。也可以加微信,注明來(lái)源,拉您進(jìn)前端視野交流群。 前言 上一篇文章寫了jQuery整體架構(gòu),學(xué)習(xí) jQuery 源碼整體架構(gòu),打造屬于自己的 js 類庫(kù) 雖然看過(guò)挺多underscore.js分析類的文章,但總感覺少點(diǎn)什么。這也許就是紙上得來(lái)終覺淺,絕知此...

    junnplus 評(píng)論0 收藏0
  • 前端利器:SASS基礎(chǔ)與Compass入門

    摘要:在吸取了的一些特性基礎(chǔ)上,有了大幅改進(jìn),也就是現(xiàn)在的。嵌套極大程度上降低了選擇器名稱和屬性的重復(fù)書寫。選擇器嵌套選擇器嵌套是指從一個(gè)選擇器中嵌套子選擇器,來(lái)實(shí)現(xiàn)選擇器的繼承關(guān)系。也已經(jīng)成為的一個(gè)標(biāo)配組件。 SASS是Syntactically Awesome Stylesheete Sass的縮寫,它是css的一個(gè)開發(fā)工具,提供了很多便利和簡(jiǎn)單的語(yǔ)法,讓css看起來(lái)更像是一門...

    娣辯孩 評(píng)論0 收藏0
  • 基于Mixin Network的Go語(yǔ)言比特幣開發(fā)教程 : 用 Mixin Messenger 機(jī)器

    摘要:基于的語(yǔ)言比特幣開發(fā)教程用機(jī)器人接受和發(fā)送比特幣在上一篇教程中我們創(chuàng)建了自動(dòng)回復(fù)消息的機(jī)器人當(dāng)用戶發(fā)送消息時(shí),機(jī)器人會(huì)自動(dòng)回復(fù)同一條消息按本篇教程后學(xué)習(xí)后完成后,你的機(jī)器人將會(huì)接受用戶發(fā)送過(guò)來(lái)的加密貨幣,然后立即轉(zhuǎn)回用戶。 基于Mixin Network的Go語(yǔ)言比特幣開發(fā)教程 : 用 Mixin Messenger 機(jī)器人接受和發(fā)送比特幣 showImg(https://segmen...

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

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

0條評(píng)論

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