方法與實例方法(static vs instance methods))
教程文檔【免費下載鏈接】30-seconds-of-codeCoding articles to level up your development skills項目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code點擊查看免費下載在 JavaScript 的 ES6 Class 體系中靜態(tài)方法static methods與實例方法instance methods是兩類用途截然不同的方法前者掛載在類構(gòu)造函數(shù)自身上服務(wù)于類型層面的工具操作后者掛載在類的prototype上被所有實例繼承并直接作用于具體對象。本文以 30 seconds of code 倉庫的 static-instance-methods.md 為骨架結(jié)合倉庫內(nèi)矩陣數(shù)據(jù)結(jié)構(gòu)、單位換算器、Stack 等真實 snippet講透兩者的定義、區(qū)別、this綁定差異、典型實戰(zhàn)場景與選擇準(zhǔn)則讀完你即可在自己的類設(shè)計中準(zhǔn)確決策「該方法該不該加static」。核心概念靜態(tài)方法與實例方法在 ES6 Class 出現(xiàn)之前JavaScript 開發(fā)者通過構(gòu)造函數(shù) 原型鏈模擬面向?qū)ο驟S6 之后class語法糖讓兩類方法的表達變得直觀靜態(tài)方法屬于類本身不作用于類的實例。它們不能被實例調(diào)用只能通過類名調(diào)用。最常見的用途是工具函數(shù)例如創(chuàng)建對象、克隆對象、類型判斷等與「某個具體實例的狀態(tài)」無關(guān)的操作。實例方法屬于類的原型prototype被所有實例通過原型鏈繼承。它們作用于實例通常需要讀寫實例自身的屬性因此必須通過實例調(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)方法它判斷某個值是否為數(shù)組與「哪個數(shù)組」無關(guān)只需要類型本身因此掛在Array上、通過類名調(diào)用arr.push(4)是Array.prototype上的實例方法它要修改arr這個具體實例的內(nèi)部狀態(tài)因此必須由實例調(diào)用。在 ES6 類中用static關(guān)鍵字聲明靜態(tài)方法而沒有static修飾的方法默認就是實例方法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兩個TypeError恰好印證了原文檔的論斷實例方法不可通過類名調(diào)用靜態(tài)方法不可通過實例調(diào)用。底層原理類、構(gòu)造函數(shù)與原型鏈要真正理解兩類方法的差異需要回到 JavaScript 的機制本身。倉庫中的 classical-vs-prototypal-inheritance.md 對此有系統(tǒng)講解經(jīng)典繼承以「類」為抽象單元原型繼承以「對象」為抽象單元而 ES6class本質(zhì)上是基于原型鏈的語法糖。從源碼結(jié)構(gòu)看一個 ES6 類經(jīng)過運行時處理后類的名字本身就是一個構(gòu)造函數(shù)函數(shù)對象用static聲明的方法作為自有屬性直接掛載到這個構(gòu)造函數(shù)對象上因此只能通過ClassName.method()訪問普通方法則被寫入ClassName.prototype對象實例通過內(nèi)部[[Prototype]]即__proto__鏈?zhǔn)讲檎乙虼怂衝ew ClassName()出來的實例都能訪問到同一份方法定義而不會為每個實例復(fù)制一份。這也解釋了原文檔中「實例方法屬于類原型、被所有實例繼承」的表述實例自身不擁有方法副本方法查找沿原型鏈進行。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)方法實例方法定義位置類構(gòu)造函數(shù)自身ES6 中用static聲明類的prototype對象上無需修飾符調(diào)用方式ClassName.method()instance.method()能否被實例調(diào)用不能通過實例訪問會報錯可以能否通過類名調(diào)用可以不能通過類名訪問會報錯是否作用于實例狀態(tài)否與具體實例無關(guān)是通常讀寫實例屬性典型用途工具函數(shù)、工廠方法、類型判斷、常量配置操作實例數(shù)據(jù)、實現(xiàn)實例行為this指向類本身構(gòu)造函數(shù)調(diào)用該方法的實例深入兩類方法中的this綁定差異兩類方法在this語義上的差異是理解其行為邊界的關(guān)鍵。倉庫中的 this.md 系統(tǒng)梳理了this的綁定規(guī)則其中與本文直接相關(guān)的有兩條對象方法中this指向被調(diào)用的對象構(gòu)造調(diào)用中this綁定到新構(gòu)造的對象。套用到類上調(diào)用實例方法時this指向調(diào)用它的那個實例這一點同樣適用于定義在原型鏈上任意位置的方法this.md原文「This applies to methods defined anywhere in the objects prototype chain」調(diào)用靜態(tài)方法時this指向類構(gòu)造函數(shù)本身——不過靜態(tài)方法通常不依賴this它們更像「命名空間下的純函數(shù)」。一個直接推論靜態(tài)方法內(nèi)部不能直接訪問this.someInstanceField因為實例字段只存在于實例上反過來實例方法內(nèi)部也不該試圖通過this做類級別的工作。如果確實需要在實例方法內(nèi)調(diào)用靜態(tài)方法應(yīng)顯式使用類名例如ClassName.staticMethod()而不是this.staticMethod()后者會被當(dāng)成實例方法查找而失敗。實戰(zhàn)一靜態(tài)工廠方法——Matrix 數(shù)據(jù)結(jié)構(gòu)的from/zeroes/identity靜態(tài)方法最常見的實戰(zhàn)場景之一是工廠方法不直接new而是通過語義化的靜態(tài)方法創(chuàng)建并初始化實例。倉庫中的 matrix-data-structure.md 給出了教科書式的例子——Matrix類的構(gòu)造函數(shù)接受二維數(shù)組或維度對象而三個靜態(tài)方法負責(zé)按不同語義生成矩陣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 單位矩陣對角線為 1注意這三個靜態(tài)方法都通過new Matrix(...)返回全新實例這正是原文檔所說「靜態(tài)方法常用于創(chuàng)建或克隆對象」的落地形態(tài)調(diào)用者無需關(guān)心構(gòu)造細節(jié)from、zeroes、identity從語義上就把「以維度初始化」「全零」「單位矩陣」區(qū)分開了。而fill、copy等則作為實例方法操作已經(jīng)存在的矩陣數(shù)據(jù)。實戰(zhàn)二動態(tài)生成靜態(tài)方法——單位換算器的fromMeters/fromFeet…靜態(tài)方法不一定要手寫。倉庫中的 unit-converter-data-structure.md 展示了用Object.defineProperty()依據(jù)單位表批量生成靜態(tài)方法與實例 getter 的技巧每個單位同時生成一個fromXxx靜態(tài)工廠方法把外部值換算成內(nèi)部基準(zhǔn)單位厘米和一個同名實例 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這個例子同時呈現(xiàn)了兩類方法的經(jīng)典配合Distance.fromMeters(10)、Distance.fromFeet(...)等靜態(tài)方法是入口工廠負責(zé)「從外部單位創(chuàng)建實例」distance.feet、distance.meters等實例 getter是出口負責(zé)「讀取實例在當(dāng)前單位下的數(shù)值」。conversions靜態(tài)字段static class field同樣屬于類自身可被靜態(tài)方法及外部直接讀取體現(xiàn)了靜態(tài)成員作為「類型級配置/常量」的定位。實戰(zhàn)三實例方法操作內(nèi)部狀態(tài)——Stack、Linked List 等數(shù)據(jù)結(jié)構(gòu)當(dāng)方法必須讀寫「這一個實例」的數(shù)據(jù)時實例方法是唯一正確的選擇。除上文 Stack 外倉庫中的>贊分享教程文檔【免費下載鏈接】30-seconds-of-codeCoding articles to level up your development skills項目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code點擊查看免費下載相關(guān)推薦30 Seconds of Interviews 深度解析JavaScript 靜態(tài)方法Static Method與實例方法Instance Method的區(qū)別與實戰(zhàn)30 Seconds of Interviews 深度解析JavaScript 靜態(tài)方法Static Method與實例方法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è)計全解析從 NxN 棋盤建模到策略/狀態(tài)/觀察者模式實戰(zhàn)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考