方法與實(shí)例方法(static vs instance methods))
教程文檔【免費(fèi)下載鏈接】30-seconds-of-codeCoding articles to level up your development skills項(xiàng)目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code點(diǎn)擊查看免費(fèi)下載在 JavaScript 的 ES6 Class 體系中靜態(tài)方法static methods與實(shí)例方法instance methods是兩類用途截然不同的方法前者掛載在類構(gòu)造函數(shù)自身上服務(wù)于類型層面的工具操作后者掛載在類的prototype上被所有實(shí)例繼承并直接作用于具體對(duì)象。本文以 30 seconds of code 倉(cāng)庫(kù)的 static-instance-methods.md 為骨架結(jié)合倉(cāng)庫(kù)內(nèi)矩陣數(shù)據(jù)結(jié)構(gòu)、單位換算器、Stack 等真實(shí) snippet講透兩者的定義、區(qū)別、this綁定差異、典型實(shí)戰(zhàn)場(chǎng)景與選擇準(zhǔn)則讀完你即可在自己的類設(shè)計(jì)中準(zhǔn)確決策「該方法該不該加static」。核心概念靜態(tài)方法與實(shí)例方法在 ES6 Class 出現(xiàn)之前JavaScript 開發(fā)者通過(guò)構(gòu)造函數(shù) 原型鏈模擬面向?qū)ο驟S6 之后class語(yǔ)法糖讓兩類方法的表達(dá)變得直觀靜態(tài)方法屬于類本身不作用于類的實(shí)例。它們不能被實(shí)例調(diào)用只能通過(guò)類名調(diào)用。最常見的用途是工具函數(shù)例如創(chuàng)建對(duì)象、克隆對(duì)象、類型判斷等與「某個(gè)具體實(shí)例的狀態(tài)」無(wú)關(guān)的操作。實(shí)例方法屬于類的原型prototype被所有實(shí)例通過(guò)原型鏈繼承。它們作用于實(shí)例通常需要讀寫實(shí)例自身的屬性因此必須通過(guò)實(shí)例調(diào)用。原文檔用數(shù)組這一最熟悉的例子做出了最直白的區(qū)分const arr [1, 2, 3]; // An Array instance Array.isArray(arr); // Static method of Array arr.push(4); // Instance method of ArrayArray.isArray(arr)是Array的靜態(tài)方法它判斷某個(gè)值是否為數(shù)組與「哪個(gè)數(shù)組」無(wú)關(guān)只需要類型本身因此掛在Array上、通過(guò)類名調(diào)用arr.push(4)是Array.prototype上的實(shí)例方法它要修改arr這個(gè)具體實(shí)例的內(nèi)部狀態(tài)因此必須由實(shí)例調(diào)用。在 ES6 類中用static關(guān)鍵字聲明靜態(tài)方法而沒有static修飾的方法默認(rèn)就是實(shí)例方法class MyClass { static staticMethod() { return I live on the class itself; } instanceMethod() { return I live on MyClass.prototype and act on instances; } } MyClass.staticMethod(); // I live on the class itself new MyClass().instanceMethod(); // I live on MyClass.prototype and act on instances MyClass.instanceMethod(); // TypeError: MyClass.instanceMethod is not a function new MyClass().staticMethod(); // TypeError: (intermediate value).staticMethod is not a function兩個(gè)TypeError恰好印證了原文檔的論斷實(shí)例方法不可通過(guò)類名調(diào)用靜態(tài)方法不可通過(guò)實(shí)例調(diào)用。底層原理類、構(gòu)造函數(shù)與原型鏈要真正理解兩類方法的差異需要回到 JavaScript 的機(jī)制本身。倉(cāng)庫(kù)中的 classical-vs-prototypal-inheritance.md 對(duì)此有系統(tǒng)講解經(jīng)典繼承以「類」為抽象單元原型繼承以「對(duì)象」為抽象單元而 ES6class本質(zhì)上是基于原型鏈的語(yǔ)法糖。從源碼結(jié)構(gòu)看一個(gè) ES6 類經(jīng)過(guò)運(yùn)行時(shí)處理后類的名字本身就是一個(gè)構(gòu)造函數(shù)函數(shù)對(duì)象用static聲明的方法作為自有屬性直接掛載到這個(gè)構(gòu)造函數(shù)對(duì)象上因此只能通過(guò)ClassName.method()訪問(wèn)普通方法則被寫入ClassName.prototype對(duì)象實(shí)例通過(guò)內(nèi)部[[Prototype]]即__proto__鏈?zhǔn)讲檎乙虼怂衝ew ClassName()出來(lái)的實(shí)例都能訪問(wèn)到同一份方法定義而不會(huì)為每個(gè)實(shí)例復(fù)制一份。這也解釋了原文檔中「實(shí)例方法屬于類原型、被所有實(shí)例繼承」的表述實(shí)例自身不擁有方法副本方法查找沿原型鏈進(jìn)行。Stack 數(shù)據(jù)結(jié)構(gòu)的 snippet>class Stack { constructor() { this.items []; } push(item) { this.items.unshift(item); } pop() { return this.items.shift(); } peek() { return this.items[0]; } isEmpty() { return this.items.length 0; } } const stack new Stack(); stack.push(apples); stack.push(oranges); stack.push(pears); stack.isEmpty(); // false stack.peek(); // pears stack.pop(); // pears關(guān)鍵區(qū)別速查表維度靜態(tài)方法實(shí)例方法定義位置類構(gòu)造函數(shù)自身ES6 中用static聲明類的prototype對(duì)象上無(wú)需修飾符調(diào)用方式ClassName.method()instance.method()能否被實(shí)例調(diào)用不能通過(guò)實(shí)例訪問(wèn)會(huì)報(bào)錯(cuò)可以能否通過(guò)類名調(diào)用可以不能通過(guò)類名訪問(wèn)會(huì)報(bào)錯(cuò)是否作用于實(shí)例狀態(tài)否與具體實(shí)例無(wú)關(guān)是通常讀寫實(shí)例屬性典型用途工具函數(shù)、工廠方法、類型判斷、常量配置操作實(shí)例數(shù)據(jù)、實(shí)現(xiàn)實(shí)例行為this指向類本身構(gòu)造函數(shù)調(diào)用該方法的實(shí)例深入兩類方法中的this綁定差異兩類方法在this語(yǔ)義上的差異是理解其行為邊界的關(guān)鍵。倉(cāng)庫(kù)中的 this.md 系統(tǒng)梳理了this的綁定規(guī)則其中與本文直接相關(guān)的有兩條對(duì)象方法中this指向被調(diào)用的對(duì)象構(gòu)造調(diào)用中this綁定到新構(gòu)造的對(duì)象。套用到類上調(diào)用實(shí)例方法時(shí)this指向調(diào)用它的那個(gè)實(shí)例這一點(diǎn)同樣適用于定義在原型鏈上任意位置的方法this.md原文「This applies to methods defined anywhere in the objects prototype chain」調(diào)用靜態(tài)方法時(shí)this指向類構(gòu)造函數(shù)本身——不過(guò)靜態(tài)方法通常不依賴this它們更像「命名空間下的純函數(shù)」。一個(gè)直接推論靜態(tài)方法內(nèi)部不能直接訪問(wèn)this.someInstanceField因?yàn)閷?shí)例字段只存在于實(shí)例上反過(guò)來(lái)實(shí)例方法內(nèi)部也不該試圖通過(guò)this做類級(jí)別的工作。如果確實(shí)需要在實(shí)例方法內(nèi)調(diào)用靜態(tài)方法應(yīng)顯式使用類名例如ClassName.staticMethod()而不是this.staticMethod()后者會(huì)被當(dāng)成實(shí)例方法查找而失敗。實(shí)戰(zhàn)一靜態(tài)工廠方法——Matrix 數(shù)據(jù)結(jié)構(gòu)的from/zeroes/identity靜態(tài)方法最常見的實(shí)戰(zhàn)場(chǎng)景之一是工廠方法不直接new而是通過(guò)語(yǔ)義化的靜態(tài)方法創(chuàng)建并初始化實(shí)例。倉(cāng)庫(kù)中的 matrix-data-structure.md 給出了教科書式的例子——Matrix類的構(gòu)造函數(shù)接受二維數(shù)組或維度對(duì)象而三個(gè)靜態(tài)方法負(fù)責(zé)按不同語(yǔ)義生成矩陣class Matrix { constructor(data) { if (Array.isArray(data)) { this.rows data.length; this.cols data[0].length; this.data data; } else { this.rows data.rows; this.cols data.cols; this.fill(0); } } static from({ rows, cols }) { return new Matrix({ rows, cols }); } static zeroes({ rows, cols }) { return new Matrix({ rows, cols }); } static identity({ size }) { return new Matrix( Array.from({ length: size }, (_, i) Array.from({ length: size }, (_, j) (i j ? 1 : 0)) ) ); } } Matrix.from({ rows: 3, cols: 3 }); // 3x3 全 0 矩陣 Matrix.zeroes({ rows: 2, cols: 4 }); // 2x4 全 0 矩陣 Matrix.identity({ size: 3 }); // 3x3 單位矩陣對(duì)角線為 1注意這三個(gè)靜態(tài)方法都通過(guò)new Matrix(...)返回全新實(shí)例這正是原文檔所說(shuō)「靜態(tài)方法常用于創(chuàng)建或克隆對(duì)象」的落地形態(tài)調(diào)用者無(wú)需關(guān)心構(gòu)造細(xì)節(jié)from、zeroes、identity從語(yǔ)義上就把「以維度初始化」「全零」「單位矩陣」區(qū)分開了。而fill、copy等則作為實(shí)例方法操作已經(jīng)存在的矩陣數(shù)據(jù)。實(shí)戰(zhàn)二動(dòng)態(tài)生成靜態(tài)方法——單位換算器的fromMeters/fromFeet…靜態(tài)方法不一定要手寫。倉(cāng)庫(kù)中的 unit-converter-data-structure.md 展示了用Object.defineProperty()依據(jù)單位表批量生成靜態(tài)方法與實(shí)例 getter 的技巧每個(gè)單位同時(shí)生成一個(gè)fromXxx靜態(tài)工廠方法把外部值換算成內(nèi)部基準(zhǔn)單位厘米和一個(gè)同名實(shí)例 getter把內(nèi)部厘米值換算成目標(biāo)單位class Distance { static conversions { inches: 2.54, feet: 30.48, yards: 91.44, miles: 160934.4, centimeters: 1, meters: 100, kilometers: 100000, }; constructor(cm) { this.cm cm; } } Object.entries(Distance.conversions).forEach(([unit, conversion]) { Object.defineProperty( Distance, from${unit.charAt(0).toUpperCase() unit.slice(1)}, { get: function () { return value new Distance(value * conversion); }, } ); Object.defineProperty(Distance.prototype, unit, { get: function () { return this.cm / conversion; }, }); }); const distance Distance.fromMeters(10); distance.feet; // 32.808398950131235 distance.centimeters; // 1000這個(gè)例子同時(shí)呈現(xiàn)了兩類方法的經(jīng)典配合Distance.fromMeters(10)、Distance.fromFeet(...)等靜態(tài)方法是入口工廠負(fù)責(zé)「從外部單位創(chuàng)建實(shí)例」distance.feet、distance.meters等實(shí)例 getter是出口負(fù)責(zé)「讀取實(shí)例在當(dāng)前單位下的數(shù)值」。conversions靜態(tài)字段static class field同樣屬于類自身可被靜態(tài)方法及外部直接讀取體現(xiàn)了靜態(tài)成員作為「類型級(jí)配置/常量」的定位。實(shí)戰(zhàn)三實(shí)例方法操作內(nèi)部狀態(tài)——Stack、Linked List 等數(shù)據(jù)結(jié)構(gòu)當(dāng)方法必須讀寫「這一個(gè)實(shí)例」的數(shù)據(jù)時(shí)實(shí)例方法是唯一正確的選擇。除上文 Stack 外倉(cāng)庫(kù)中的>贊分享教程文檔【免費(fèi)下載鏈接】30-seconds-of-codeCoding articles to level up your development skills項(xiàng)目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code點(diǎn)擊查看免費(fèi)下載相關(guān)推薦30 Seconds of Interviews 深度解析JavaScript 靜態(tài)方法Static Method與實(shí)例方法Instance Method的區(qū)別與實(shí)戰(zhàn)30 Seconds of Interviews 深度解析JavaScript 靜態(tài)方法Static Method與實(shí)例方法Instance Metho教程前端30 seconds of code 深入解讀JavaScript 函數(shù)方法 call()、apply() 與 bind() 完整指南30 seconds of code 深入解讀JavaScript 函數(shù)方法 call 、apply 與 bind 完整指南 Function.prototy教程文檔Civitai 事件引擎 Redis 緩存排查指南redis-inspect 技能全解析Civitai 事件引擎 Redis 緩存排查指南redis inspect 技能全解析 本文圍繞 apps/event engine/.claude/ski教程文檔上一篇NavigationTabBar完全指南打造炫酷Android導(dǎo)航標(biāo)簽欄下一篇井字棋Tic Tac Toe低層設(shè)計(jì)全解析從 NxN 棋盤建模到策略/狀態(tài)/觀察者模式實(shí)戰(zhàn)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考