我使用以下內容創建了一個函式和原型:
function Range(from, to) {
if (new.target === undefined) {
throw new Error("Range must be invoked with new.")
}
Object.assign(this, {from, to});
}
Range.prototype = {
includes: function(x) {
return x >= this.from && x <= this.to;
},
toString: function() {
return `[${this.from}, ${this.to}]`;
}
}
這是它在 Chrome 控制臺中顯示的內容:

如果我們以includes函式為例,name是函式名,length是函式的數量。并且[[FunctionLocation]]似乎是 JS 引擎底層實作的一部分,因此對于實際的 js 除錯并不重要。但接下來是什么:
- 呼叫者?什么是非空的例子。
- 論據?同樣,什么時候非空的例子是什么
uj5u.com熱心網友回復:
這兩個屬性僅在函式執行時填寫。所以要在除錯器中看到它們,你需要用斷點停止函式。
如果你這樣做,Range.arguments將包含有關引數的資訊,Range.caller并將包含呼叫的函式Range()(這將是null如果Range()從頂層呼叫)。
function Range(from, to) {
if (new.target === undefined) {
throw new Error("Range must be invoked with new.")
}
Object.assign(this, {from, to});
debugger;
}
Range.prototype = {
includes: function(x) {
return x >= this.from && x <= this.to;
},
toString: function() {
return `[${this.from}, ${this.to}]`;
}
}
function callRange() {
x = new Range(1, 10);
console.log(x);
}
callRange();

uj5u.com熱心網友回復:
適合 ES6 初學者
如果您使用推薦的class語法,您將獲得自動錯誤,而無需手動檢查this或new.target-
class Range {
constructor(from, to) {
Object.assign(this, {from, to})
}
}
// with `new`
const p = new Range(1,2)
console.log(p)
// without `new`
const q = Range(1,2)
console.log(q)
{ from: 1, to: 2 }
TypeError: Cannot call a class constructor without |new|
您可以直接在-Range.prototype中定義所謂的實體方法,而不是用手寫物件覆寫class
class Range {
constructor(from, to) {
Object.assign(this, {from, to})
}
includes(x) {
return x >= this.from && x <= this.to
}
toString() {
return `[${this.from}, ${this.to}]`
}
}
const p = new Range(3,6)
console.log(`p: ${p}`)
console.log(`p includes 4: ${p.includes(4)}`)
console.log(`p includes 9: ${p.includes(9)}`)
p: [3, 6]
p includes 4: true
p includes 9: false
ES2020 及以后
我會提到,對大型類的模塊化設計的支持越來越多。如果Range要包含 20 個方法,但呼叫者只使用其中的 1 或 2 個,則 18 個方法將捆綁到最終應用程式中,但仍未使用。洗掉這些死代碼需要極其復雜的編譯器,這個程序稱為搖樹。下面我們看到range寫成一個模塊而不是一個類。請注意,只有公共方法可以使用 訪問export,允許模塊作者在她/他希望的任何地方限制對私有方法的訪問 -
// range.js
const tag = Symbol()
const range = (from, to) => ({ tag, from, to })
const isRange = (t) => t.tag === tag
const includes = (t, x) => x >= t.from && x <= t.to
const toString = (t) => `[${t.from}, ${t.to}]`
export { range, isRange, includes, toString }
在main模塊中,呼叫者只import需要什么,允許編譯器有效地修剪匯入模塊的任何未使用部分 -
// main.js
import { range, includes, toString } from "./range.js"
const p = range(3,6)
console.log(`p: ${toString(p)}`)
console.log(`p includes 4: ${includes(p,4)}`)
console.log(`p includes 9: ${includes(p,9)}`)
p: [3, 6]
p includes 4: true
p includes 9: false
有關 的更多資訊import,請參閱Alex Rauschmayer 的動態匯入 ES 模塊。
有關不斷發展的 ES 模塊計劃的更多資訊,請參閱Google Firebase 的新 API v9 等專案。
- 第 8 版。這是 Firebase 多年來一直維護的 JavaScript 界面,并且對于使用現有 Firebase 應用程式的 Web 開發人員來說是熟悉的。由于 Firebase 將在一個主要發布周期后取消對該版本的支持,因此新應用應改為采用版本 9。
- 模塊化版本 9 . 此 SDK 引入了一種模塊化方法,可通過webpack或Rollup等現代 JavaScript 構建工具提供更小的 SDK 大小和更高的效率。
版本 9 與構建工具很好地集成了,這些工具可以去除您的應用程式中未使用的代碼,這一程序稱為“tree-shaking”。使用此 SDK 構建的應用程式受益于大大減少的尺寸足跡。第 8 版雖然可作為模塊使用,但沒有嚴格的模塊化結構,也沒有提供相同程度的尺寸縮減。...
吃你的蛋糕,也吃
使用一種簡單的技術,我們可以撰寫基于模塊化的代碼,如果需要,仍然可以提供面向物件的介面。下面我們撰寫一個Range類作為上面模塊函式的簡單包裝器 -
// range.js
// ...
class Range {
constructor(t) { this.t = t }
isRange() { return isRange(this.t) }
includes(x) { return includes(this.t, x) }
toString() { return toString(this.t) }
static new(a,b) { return new Range(range(a,b)) }
}
export { Range, ... }
在您的主模塊中,您可以匯入Range類以通過面向物件的介面訪問模塊的所有功能 -
// main.js
import { Range } from "./range"
const p = Range.new(3,6)
console.log(`p: ${p}`)
console.log(`p includes 4: ${p.includes(4)}`)
console.log(`p includes 9: ${p.includes(9)}`)
現在您的模塊可以用于功能風格或面向物件的風格。請注意,當以這種方式使用面向物件的介面時,其代價是無法對這部分代碼進行樹搖動。但是,希望利用死代碼消除的程式可以改用函式式介面。
我在其他答案中寫過這種技術 -
- 可以在沒有輔助方法的情況下執行鏈式階乘方法
- 在 BST Python 中洗掉節點
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/459650.html
標籤:javascript 谷歌浏览器
