亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

TypeScript 動態或以編程方式鏈接函數

TypeScript 動態或以編程方式鏈接函數

慕萊塢森 2023-07-20 14:37:35
TypeScript 函數鏈接,但我想以編程方式鏈接它們。示例類:chain.tsclass MyChain {? value: number = 0;? constructor() {? ? this.value = 0;? }? sum(args: number[]) {? ? this.value = args.reduce((s, c) => s + c, 0);? ? return this;? }? add(v: number) {? ? this.value = this.value + v;? ? return this;? }? subtract(v: number) {? ? this.value = this.value - v;? ? return this;? }}const mc = new MyChain();console.log(mc.sum([1, 2, 3, 4]).subtract(5).value);5我在控制臺上看到了這個數字。現在,我對 JavaScript 和 TypeScript 還很陌生,所以我發現這個類中的函數實際上是該類實例數組的元素。因此,我可以這樣做:console.log(mc["sum"]([1,?2,?3,?4]).value);這確實返回了數字10?,F在,我對如何以編程方式鏈接它感到困惑。例如(無論如何,這顯然不是我想做的,并且表明我對 JavaScript 缺乏理解:console.log(mc["sum"]([1,?2,?3,?4]).mc["subtract"](5).value);錯誤:類型“MyChain”上不存在屬性“mc”。ts(2339)好吧,老實說,我直覺地知道這是行不通的。但是,想一想,我將如何以任何合理的語言訪問多維數組的元素?console.log(mc["sum"]([1,?2,?3,?4])["subtract"](5).value);答對了。這可以解決問題。但是,這并不是我真正需要的解決方案。我需要的是這樣的:interface IChainObject {? action: string;? operand: number | number[];}const chainObj: IChainObject[] = [? { action: "sum", operand: [1, 2, 3, 4] },? { action: "subtract", operand: 5 },];首先,我想嘗試一下:console.log(mc[chainObj[0].action](chainObj[0].operand).value);因此,生成一種機制,最終構建如下內容:console.log(? mc[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](? ? chainObj[1].operand? ).value);因此,在我看來,我想要的是某種方式來生成它:[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](chainObj[1].operand)由此,我的鏈對象具有一個或多個操作/操作數對象集:const chainObj: IChainObject[] = [? { action: "sum", operand: [1, 2, 3, 4] },? { action: "subtract", operand: 5 },];現在,這就是我的大腦或多或少關閉的地方。我認為我需要生成一串字符串值,但它們只是字符串,并且不會真正按照我想要的方式作為函數的數組索引。我為什么要這樣做?最終,我想從 JSON 對象構建一個復雜的 Yup 模式對象。
查看完整描述

3 回答

?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

讓我們從我發現的第一個誤解開始:

現在,我對 JavaScript 和 TypeScript 還很陌生,所以我發現這個類中的函數實際上是該類實例數組的元素。

不是這種情況。Javascript 中的方括號用于所有屬性查找,而不僅僅是數組索引。x.foo實際上相當于x["foo"], 并且相同的語法適用于數組,因為數組只是對象。Javascript 中的類只是具有原型屬性的對象,原型屬性本身就是一個對象。它包含默認屬性列表,如果您實例化一個類并查找對象中不存在的屬性,它將在原型中搜索它。那么,看一下代碼:

mc["sum"]([1,?2,?3])

它在 中搜索“sum”屬性mc,但找不到任何屬性,因為您尚未定義該屬性,因此它在 of 中搜索prototype,MyChain并找到該mc方法。因此,mc["sum"]就是sum的方法mc?,F在,這段代碼:

console.log(mc["sum"]([1,?2,?3,?4]).mc["subtract"](5).value);

不起作用,而且看起來很不對勁是有原因的。mc["sum"]([1, 2, 3, 4])返回mc,那么為什么您必須訪問該mc屬性(并不是該mc屬性甚至存在)?subtract這就是為什么你的第二個例子(直接調用的例子)有效:

console.log(mc["sum"]([1,?2,?3,?4])["subtract"](5).value);

現在,讓我們看看工作代碼:

const mc = new MyChain();


interface IChainObject {

? action: string;

? operand: number | number[];

}


const chainObj: IChainObject[] = [

? { action: "sum", operand: [1, 2, 3, 4, 5] },

? { action: "subtract", operand: 5 },

];


let myChain = {};

chainObj.forEach((o) => {

? myChain = mc[o.action](o.operand);

});

console.log("myChain is", myChain["value"]);

實際上您不需要很多這樣的代碼。它可以簡化為:


const mc = new MyChain();


interface IChainObject {

? action: keyof MyChain;

? operand: number | number[];

}


const chainObj: IChainObject[] = [

? { action: "sum", operand: [1, 2, 3, 4, 5] },

? { action: "subtract", operand: 5 },

];


chainObj.forEach((o) => {

? // bypass typescript type checking with cast

? (mc[o.action] as Function)(o.operand);

});

console.log("myChain is", mc.value);

本質上,按順序forEach循環遍歷元素chainObj。元素的值存儲在變量 中o。mc[o.action]獲取存儲在 中的方法名稱o.action,并使用方括號訪問它。這基本上就是查方法了。然后,該方法被調用(o.operand)(在Javascript中,函數只是值,你可以像函數一樣調用任何值,但如果它不是函數,則會出錯)。mc然后修改自身,然后繼續下一個循環。如果我們debugger在函數中插入一條語句,然后在第一個循環中中斷,我們可以檢查變量:

http://img1.sycdn.imooc.com/64b8d68e0001272d04950364.jpg

正如您所看到的,該值從 0 開始,o.action是“sum”,并且mc[o.action]是 sum 方法。然后我們可以使用 調用 sum 方法o.operand,它將元素相加并將值設置為 15。然后,在第二個循環中:

http://img4.sycdn.imooc.com/64b8d6990001160603490298.jpg

mc[o.action]是減法,我們用 來調用它o.operand,即 5,將值降低到 10。



查看完整回答
反對 回復 2023-07-20
?
汪汪一只貓

TA貢獻1898條經驗 獲得超8個贊

Javascript 中的大多數東西classes基本上都是objects.?1

這意味著可以通過點符號或方括號符號來訪問屬性(或者在本例中為函數) 。

讓我們看一個可能有助于解釋的示例:

class MyClass {

? myFunction(x) {

? ? console.log(x);

? }

}

const x = new MyClass();

// attribute accessed via the dot notation

x.myFunction("Hello World!");

// attribute accessed via the bracket notation and a string?

x['myFunction']("Hello World, again!");

// attribute accessed via a variable that is a string?

const functionName = 'myFunction';

x[functionName]("Well uh, Hello World again?");

// attribute accessed via a variable that is a string, and passing in an argument

const argument = "This is " + "an argument";

x[functionName](argument);

為了進一步說明這一點:


class MyClass {

? myFunction(x) {

? ? console.log(x);

? }

}

const x = new MyClass();

console.log(x.myFunction) // returns a function

console.log(x["myFunction"]) // returns a function


// executing the function

x.myFunction("Method One");

x["myFunction"]("Method Two")

我們可以看到返回的函數可以被調用。

讓我們回到你的例子

chainObj.forEach((o)?=>?{
??myChain?=?mc[o.action](o.operand);
});
  • o.action是函數名

  • o.operand因此,is 大致翻譯為:

chainObj.forEach((o)?=>?{
??myChain?=?mc[functionName](arugment);
});

就像我們之前的例子一樣。

1?“類基本上只是對象”


查看完整回答
反對 回復 2023-07-20
?
紫衣仙女

TA貢獻1839條經驗 獲得超15個贊

這方面的內容有很多;我只想關注“讓代碼正常工作的秘訣是什么forEach()? ”


“秘密”在于 的實例MyChain有一個名為 的屬性value,該屬性在調用每個方法后都會更新。代碼并forEach()沒有真正將調用鏈接在一起;它只是對每次命名的原始MyChain變量進行操作。mc


MyChain由于該更新的所有方法this.value也返回this,因此您是否真的鏈接調用(對每個方法調用的返回值進行操作)并不重要:


const chaining = new MyChain();

console.log(chaining.add(3).subtract(1).value); // 2

或者如果您只是連續調用原始對象上的方法:


const notChaining = new MyChain();

notChaining.add(3);

notChaining.subtract(1);

console.log(notChaining.value) // 2

如果您希望它們之間存在差異,您可以通過制作兩個版本來顯示它MyChain;一種只能通過鏈接起作用,一種只能連續起作用。


以下內容需要鏈接,因為它永遠不會更新原始對象,并且方法調用會返回帶有方法調用結果的新對象:


class RealChain {

  constructor(public value: number = 0) { }


  sum(args: number[]) {

    return new RealChain(args.reduce((s, c) => s + c, 0));

  }


  add(v: number) {

    return new RealChain(this.value + v);

  }


  subtract(v: number) {

    return new RealChain(this.value - v);

  }

}

    

const realChaining = new RealChain();

console.log(realChaining.add(3).subtract(1).value); // 2


const notRealChaining = new RealChain();

notRealChaining.add(3);

notRealChaining.subtract(1);

console.log(notRealChaining.value) // 0

并且以下內容禁止鏈接,因為它只更新原始對象并且其方法不返回任何內容:


class NotChain {

  value: number = 0;

  constructor() {

    this.value = 0;

  }


  sum(args: number[]) {

    this.value = args.reduce((s, c) => s + c, 0);

  }


  add(v: number) {

    this.value = this.value + v;

  }


  subtract(v: number) {

    this.value = this.value - v;

  }

}


const realNotChaining = new NotChain();

realNotChaining.add(3);

realNotChaining.subtract(1);

console.log(realNotChaining.value) // 2


const badNotChaining = new NotChain();

console.log(badNotChaining.add(3).subtract(1).value); // error! 

// badNotChaining.add(3) is undefined so you can't call subtract() on it

代碼forEach()僅適用于NotChain實例,不適用于RealChain實例。


如果您想要一個類似編程循環的東西,它實際上可以與鏈接一起使用,而不是在原始對象上調用方法,那么您可能應該使用reduce()而不是forEach():


const realChainReduced = chainObj.reduce(

  (mc, o) => mc[o.action](o.operand), 

  new RealChain() // or MyChain, doesn't matter

);

console.log("realChainReduced is", realChainReduced.value); // 10

請注意,我沒有介紹任何其他部分,包括 TypeScript 細節(此處使用的類型會產生一些編譯器錯誤),因此請注意。

Playground 代碼鏈接


查看完整回答
反對 回復 2023-07-20
  • 3 回答
  • 0 關注
  • 203 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號