3 回答

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超9個(gè)贊
讓我們從我發(fā)現(xiàn)的第一個(gè)誤解開始:
現(xiàn)在,我對(duì) JavaScript 和 TypeScript 還很陌生,所以我發(fā)現(xiàn)這個(gè)類中的函數(shù)實(shí)際上是該類實(shí)例數(shù)組的元素。
不是這種情況。Javascript 中的方括號(hào)用于所有屬性查找,而不僅僅是數(shù)組索引。x.foo
實(shí)際上相當(dāng)于x["foo"]
, 并且相同的語法適用于數(shù)組,因?yàn)閿?shù)組只是對(duì)象。Javascript 中的類只是具有原型屬性的對(duì)象,原型屬性本身就是一個(gè)對(duì)象。它包含默認(rèn)屬性列表,如果您實(shí)例化一個(gè)類并查找對(duì)象中不存在的屬性,它將在原型中搜索它。那么,看一下代碼:
mc["sum"]([1,?2,?3])
它在 中搜索“sum”屬性mc
,但找不到任何屬性,因?yàn)槟形炊x該屬性,因此它在 of 中搜索prototype
,MyChain
并找到該mc
方法。因此,mc["sum"]
就是sum
的方法mc
?,F(xiàn)在,這段代碼:
console.log(mc["sum"]([1,?2,?3,?4]).mc["subtract"](5).value);
不起作用,而且看起來很不對(duì)勁是有原因的。mc["sum"]([1, 2, 3, 4])
返回mc
,那么為什么您必須訪問該mc
屬性(并不是該mc
屬性甚至存在)?subtract
這就是為什么你的第二個(gè)例子(直接調(diào)用的例子)有效:
console.log(mc["sum"]([1,?2,?3,?4])["subtract"](5).value);
現(xiàn)在,讓我們看看工作代碼:
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"]);
實(shí)際上您不需要很多這樣的代碼。它可以簡(jiǎn)化為:
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);
本質(zhì)上,按順序forEach循環(huán)遍歷元素chainObj。元素的值存儲(chǔ)在變量 中o。mc[o.action]獲取存儲(chǔ)在 中的方法名稱o.action,并使用方括號(hào)訪問它。這基本上就是查方法了。然后,該方法被調(diào)用(o.operand)(在Javascript中,函數(shù)只是值,你可以像函數(shù)一樣調(diào)用任何值,但如果它不是函數(shù),則會(huì)出錯(cuò))。mc然后修改自身,然后繼續(xù)下一個(gè)循環(huán)。如果我們debugger在函數(shù)中插入一條語句,然后在第一個(gè)循環(huán)中中斷,我們可以檢查變量:
正如您所看到的,該值從 0 開始,o.action
是“sum”,并且mc[o.action]
是 sum 方法。然后我們可以使用 調(diào)用 sum 方法o.operand
,它將元素相加并將值設(shè)置為 15。然后,在第二個(gè)循環(huán)中:
mc[o.action]
是減法,我們用 來調(diào)用它o.operand
,即 5,將值降低到 10。

TA貢獻(xiàn)1898條經(jīng)驗(yàn) 獲得超8個(gè)贊
Javascript 中的大多數(shù)東西classes
基本上都是objects
.?1
這意味著可以通過點(diǎn)符號(hào)或方括號(hào)符號(hào)來訪問屬性(或者在本例中為函數(shù)) 。
讓我們看一個(gè)可能有助于解釋的示例:
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);
為了進(jìn)一步說明這一點(diǎn):
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")
我們可以看到返回的函數(shù)可以被調(diào)用。
讓我們回到你的例子
chainObj.forEach((o)?=>?{ ??myChain?=?mc[o.action](o.operand); });
o.action
是函數(shù)名o.operand
因此,is 大致翻譯為:
chainObj.forEach((o)?=>?{ ??myChain?=?mc[functionName](arugment); });
就像我們之前的例子一樣。
1?“類基本上只是對(duì)象”

TA貢獻(xiàn)1839條經(jīng)驗(yàn) 獲得超15個(gè)贊
這方面的內(nèi)容有很多;我只想關(guān)注“讓代碼正常工作的秘訣是什么forEach()? ”
“秘密”在于 的實(shí)例MyChain有一個(gè)名為 的屬性value,該屬性在調(diào)用每個(gè)方法后都會(huì)更新。代碼并forEach()沒有真正將調(diào)用鏈接在一起;它只是對(duì)每次命名的原始MyChain變量進(jìn)行操作。mc
MyChain由于該更新的所有方法this.value也返回this,因此您是否真的鏈接調(diào)用(對(duì)每個(gè)方法調(diào)用的返回值進(jìn)行操作)并不重要:
const chaining = new MyChain();
console.log(chaining.add(3).subtract(1).value); // 2
或者如果您只是連續(xù)調(diào)用原始對(duì)象上的方法:
const notChaining = new MyChain();
notChaining.add(3);
notChaining.subtract(1);
console.log(notChaining.value) // 2
如果您希望它們之間存在差異,您可以通過制作兩個(gè)版本來顯示它MyChain;一種只能通過鏈接起作用,一種只能連續(xù)起作用。
以下內(nèi)容需要鏈接,因?yàn)樗肋h(yuǎn)不會(huì)更新原始對(duì)象,并且方法調(diào)用會(huì)返回帶有方法調(diào)用結(jié)果的新對(duì)象:
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
并且以下內(nèi)容禁止鏈接,因?yàn)樗桓略紝?duì)象并且其方法不返回任何內(nèi)容:
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實(shí)例,不適用于RealChain實(shí)例。
如果您想要一個(gè)類似編程循環(huán)的東西,它實(shí)際上可以與鏈接一起使用,而不是在原始對(duì)象上調(diào)用方法,那么您可能應(yīng)該使用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
請(qǐng)注意,我沒有介紹任何其他部分,包括 TypeScript 細(xì)節(jié)(此處使用的類型會(huì)產(chǎn)生一些編譯器錯(cuò)誤),因此請(qǐng)注意。
添加回答
舉報(bào)