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

資訊專欄INFORMATION COLUMN

MobX詳解(二):ES7 裝飾器 decorator

Keagan / 581人閱讀

摘要:在學習裝飾器語法之前,需要先溫習一下的一些基礎知識。函數最后必須返回。使用時也很簡單,如下在方法前面加上,就是裝飾器語法。裝備了,攻擊更強了。職業的基本攻擊穿上了,移動速度更快了。

在學習ES7裝飾器語法之前,需要先溫習一下ES5的一些基礎知識。

假設有對象如下:(便于理解)

var person = {
    name: "TOM"
}

在ES5中,對象中的每個屬性都有一個特性值來描述這個屬性的特點,他們分別是:

configurable: 屬性是否能被delete刪除,當值為false時,其他特性值也不能被改變,默認值為true

enumerable: 屬性是否能被枚舉,也就是是否能被for in循環遍歷。默認為true

writable: 是否能修改屬性值。默認為true

value:具體的屬性值是多少,默認為undefined

get:當我們通過person.name訪問name的屬性值時,get將被調用。該方法可以自定義返回的具體值是多少。get默認值為undefined

set:當我們通過person.name = "Jake"設置name屬性值時,set方法將被調用,該方法可以自定義設置值的具體方式,set默認值為undefined

需要注意的是,不能同時設置value,writeableget set

我們可以通過Object.defineProperty(操作單個)與Object.defineProperties(操作多個)來修改這些特性值。

// 三個參數分別為  target, key, descriptor(特性值的描述對象)
Object.defineProperty(person, "name", {
  value: "TOM"
})

// 新增
Object.defineProperty(person, "age", {
  value: 20
})

裝飾器語法與此類似,當我們想要自定義一個裝飾器時,可以這樣寫:

function nameDecorator(target, key, descriptor) {
    descriptor.value = () => {
        return "jake";
    }
    return descriptor;
}

函數nameDecorator的定義會重寫被他裝飾的屬性(getName)。方法的三個參數與Object.defineProperty一一對應,分別指當前的對象Person,被作用的屬性getName,以及屬性特性值的描述對象descriptor。函數最后必須返回descriptor

使用時也很簡單,如下:

class Person {
    constructor() {
        this.name = "jake"
    }
    @nameDecorator
    getName() {
        return this.name;
    }
}

let p1 = new Person();
console.log(p1.getName())

getName方法前面加上@nameDecorator,就是裝飾器語法。

自定義函數nameDecorator的參數中,target,就是裝飾的對象Person,key就是被裝飾的具體方法getName

不能使用裝飾器對構造函數進行更改,如果要修改構造函數,則可以通過如下的方式來完成

function initDecorator(target, key, descriptor) {
    const fn = descriptor.value;
    // 改變傳入的參數值
    descriptor.value = (...args) => {
        args[0] = "TOM";
        return fn.apply(target, args);
    }
    return descriptor;
}

class Person {
    constructor(name, age) {
        this.init(name, age)
    }
    @initDecorator
    init(name, age) {
        this.name = name;
        this.age = age;
    }
    getName() {
        return this.name;
    }
    getAge() {
        return this.age;
    }
}

console.log(new Person("alex", 20).getName()); // TOM

如何希望裝飾器傳入一個指定的參數,可以如下做。

// 注意這里的差別
function initDecorator(name) {
    return function(target, key, descriptor) {
        const fn = descriptor.value;
        descriptor.value = (...args) => {
            args[0] = name;
            return fn.apply(target, args);
        }
        return descriptor;
    }
}

class Person {
    constructor(name, age) {
        this.init(name, age)
    }
    @initDecorator("xiaoming")
    init(name, age) {
        this.name = name;
        this.age = age;
    }
    getName() {
        return this.name;
    }
    getAge() {
        return this.age;
    }
}

console.log(new Person("alex", 20).getName());  // xiaoming

這里利用了閉包的原理,將裝飾器函數外包裹一層函數,以閉包的形式緩存了傳入的參數。

我們也可以對整個class添加裝飾器

function personDecorator(target) {
    // 修改方法
    target.prototype.getName = () => {
        return "hahahahaha"
    }
    // 新增方法,因為內部使用了this,因此一定不能使用箭頭函數
    target.prototype.getAge = function() {
        return this.age
    }
    return target;
}

@personDecorator
class Person {
    constructor(name, age) {
        this.init(name, age)
    }
    init(name, age) {
        this.name = name;
        this.age = age;
    }
    getName() {
        return this.name;
    }
}

var p = new Person("alex", 30);
console.log(p.getName(), p.getAge());  // hahahahaha 30

也可以傳參數

var xiaom = {
    name: "xiaom",
    age: 22
}
function stuDecorator(person) {
    return function(target) {
        // 修改方法
        target.prototype.getAge = () => {
            return person.age;
        }
        // 添加方法
        target.prototype.getOther = () => {
            return "other info."
        }
        return target;
    }
}

function initDecorator(person) {
    return function(target, key, descriptor) {
        var method = descriptor.value;
        descriptor.value = () => {
            var ret = method.call(target, person.name);
            return ret;
        }
    }
}

@stuDecorator(xiaom)
class Student {
    constructor(name, age) {
        this.init(name, age);
    }
    @initDecorator(xiaom)
    init(name, age) {
        this.name = name;
        this.age = age;
    }
    getAge() {
        return this.age;
    }
    getName() {
        return this.name;
    }
}

var p = new Student("hu", 18);
console.log(p.getAge(), p.getName(), p.getOther()); // 22 "xiaom" "other info."

那么用ES7 的decorator來實現最開始的需求,則可以這樣做

import { cloth, weapon, shoes, defaultRole } from "./config";

// 基礎角色
class Role {
    constructor(role) {
        this.hp = role.hp;
        this.atk = role.atk;
        this.speed = role.speed;
        this.cloth = role.cloth;
        this.weapon = role.weapon;
        this.shoes = role.shoes;
    }
    run() {}
    attack() {}
}


function ClothDecorator(target) {
    target.prototype.getCloth = function(cloth) {
        this.hp += cloth.hp;
        this.cloth = cloth.name;
    }
}

function WeaponDecorator(target) {
    target.prototype.getWeapon = function(weapon) {
        this.atk += weapon.attack;
        this.weapon = weapon.name;
    }
    target.prototype.attack = function() {
        if (this.weapon) {
            console.log(`裝備了${this.weapon},攻擊更強了`);
        } else {
            console.log("戰士的基礎攻擊");
        }
    }
}

function ShoesDecorator(target) {
    target.prototype.getShoes = function(shoes) {
        this.speed += shoes.speed;
        this.shoes = shoes.name;
    }
    target.prototype.run = function() {
        if (this.shoes) {
            console.log(`穿上了${this.shoes},移動速度更快了`);
        } else {
            console.log("戰士的奔跑動作");
        }
    }
}


@ClothDecorator
@WeaponDecorator
@ShoesDecorator
class Soldier extends Role {
    constructor(role) {
        const o = Object.assign({}, defaultRole, role);
        super(o);
        this.nickname = role.nickname;
        this.gender = role.gender;
        this.career = "戰士";
        if (role.hp == defaultRole.hp) {
            this.hp = defaultRole.hp + 20;
        }
        if (role.speed == defaultRole.speed) {
            this.speed = defaultRole.speed + 5;
        }
    }
    run() {
        console.log("戰士的奔跑動作");
    }
    attack() {
        console.log("戰士的基礎攻擊");
    }
}

const base = {
    ...defaultRole,
    nickname: "alex",
    gender: "man"
}

const s = new Soldier(base);
s.getCloth(cloth);
console.log(s);

s.getWeapon(weapon);
s.attack();
console.log(s);

s.getShoes(shoes);
s.run();
console.log(s);

這里需要注意的是,裝飾者模式與直接使用瀏覽器支持的語法在實現上的一些區別。

ES7 Decorator重點在于對裝飾器的封裝,因此我們可以將上栗中的裝飾器多帶帶封裝為一個模塊。在細節上做了一些調整,讓我們封裝的裝飾器模塊不僅僅可以在創建戰士對象的時候使用,在我們創建其他職業例如法師,射手的時候也能夠正常使用。

export function ClothDecorator(target) {
    target.prototype.getCloth = function(cloth) {
        this.hp += cloth.hp;
        this.cloth = cloth.name;
    }
}

export function WeaponDecorator(target) {
    target.prototype.getWeapon = function(weapon) {
        this.atk += weapon.attack;
        this.weapon = weapon.name;
    }
    target.prototype.attack = function() {
        if (this.weapon) {
            console.log(`${this.nickname}裝備了${this.weapon},攻擊更強了。職業:${this.career}`);
        } else {
            console.log(`${this.career}的基本攻擊`);
        }
    }
}

export function ShoesDecorator(target) {
    target.prototype.getShoes = function(shoes) {
        this.speed += shoes.speed;
        this.shoes = shoes.name;
    }
    target.prototype.run = function() {
        if (this.shoes) {
            console.log(`${this.nickname}穿上了${this.shoes},移動速度更快了。職業:${this.career}`);
        } else {
            console.log(`${this.career}的奔跑動作`);
        }
    }
}

可以利用該例子,感受Decorator與繼承的不同。

整理之后,Soldier的封裝代碼將會變得非常簡單

import { cloth, weapon, shoes, defaultRole } from "./config";
import { ClothDecorator, WeaponDecorator, ShoesDecorator } from "./equip";
import Role from "./Role";

@ClothDecorator
@WeaponDecorator
@ShoesDecorator
class Soldier extends Role {
    constructor(roleInfo) {
        const o = Object.assign({}, defaultRoleInfo, roleInfo);
        super(o);
        this.nickname = roleInfo.nickname;
        this.gender = roleInfo.gender;
        this.career = "戰士";
        if (roleInfo.hp == defaultRoleInfo.hp) {
            this.hp = defaultRoleInfo.hp + 20;
        }
        if (roleInfo.speed == defaultRoleInfo.speed) {
            this.speed = defaultRoleInfo.speed + 5;
        }
    }
    run() {
        console.log("戰士的奔跑動作");
    }
    attack() {
        console.log("戰士的基礎攻擊");
    }
}

那么繼續上一篇文章的思考題,利用裝飾器可以怎么做呢?

補充:如何在構建環境中支持ES7 Decorator語法

https://technologyadvice.gith...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107064.html

相關文章

  • 【用故事解讀 MobX 源碼(四)】裝飾 和 Enhancer

    摘要:所以這是一篇插隊的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據入參返回具體的描述符。其次局部來看,裝飾器具體應用表達式是,其函數簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價的。 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...

    maybe_009 評論0 收藏0
  • 寫 React 組件的最佳實踐

    摘要:本文介紹了,我們團隊寫組件的最佳實踐。這樣可以避免類似之類的錯誤避免使用函數表達式的方式來定義組件,如下這看起來非常酷,但是在這里,通過函數表達式定義的函數卻是匿名函數。匿名函數也可能會導致測試庫出問題。 本文為譯文,已獲得原作者允許,原文地址:http://scottdomes.com/blog/ou... 當我第一次開始寫 React 時,我發現多少個 React 教程,就有多少種...

    lakeside 評論0 收藏0
  • react+mobx+thrift學習demo

    摘要:安裝等相關依賴。通過啟動項目,進行后續操作。自定義執行狀態的改變。任何不在使用狀態的計算值將不會更新,直到需要它進行副作用操作時。強烈建議始終拋出錯誤,以便保留原始堆棧跟蹤。 2018-08-14 learning about work begin:2018-08-13 step 1 熟悉react 寫法 step 2 mobx 了解&使用 step 3 thrift接口調用過程 Re...

    xcc3641 評論0 收藏0
  • Mobx4.X狀態管理入門

    摘要:前言原本說接下來會專注學但是最新工作又學習了一些有意思的庫於是就再寫下來做個簡單的入門之前我寫過一篇文章這個也算是作為一個補充吧這次無非就是類似筆記把認為的一些關鍵點記下來有些地方還沒用到就衹是描述一下代碼有些自己寫的有些文檔寫的很好就搬下 前言 原本說接下來會專注學nodejs,但是最新工作又學習了一些有意思的庫,於是就再寫下來做個簡單的入門,之前我寫過一篇文章,這個也算是作為一個補...

    CKJOKER 評論0 收藏0
  • 【用故事解讀 MobX 源碼(五)】 Observable

    摘要:前言初衷以系列故事的方式展現源碼邏輯,盡可能以易懂的方式講解源碼本系列文章用故事解讀源碼一用故事解讀源碼二用故事解讀源碼三用故事解讀源碼四裝飾器和用故事解讀源碼五文章編排每篇文章分成兩大段,第一大段以簡單的偵探系列故事的形式講解所涉及人物場 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式...

    leeon 評論0 收藏0

發表評論

0條評論

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