文章目錄 js 常用擴(kuò)展方法總結(jié) 擴(kuò)展方法應(yīng)用選擇 大型項(xiàng)目 中擴(kuò)展方法應(yīng)用選擇 小型項(xiàng)目中 擴(kuò)展應(yīng)用
js 常用擴(kuò)展方法總結(jié)
函數(shù)原型(prototype
)擴(kuò)展方法 介紹 :在JavaScript中,通過修改函數(shù)的prototype
屬性可以為該函數(shù)創(chuàng)建的所有對(duì)象添加共享的方法。這是一種基于原型鏈的擴(kuò)展方式,所有通過該構(gòu)造函數(shù)創(chuàng)建的對(duì)象都可以訪問這些擴(kuò)展的方法。示例 :
function Person ( name ) { this . name = name;
}
Person . prototype. sayHello = function ( ) { console. log ( ` Hello, my name is ${ this . name} ` ) ;
} ;
const person1 = new Person ( "Alice" ) ;
person1. sayHello ( ) ;
對(duì)象字面量擴(kuò)展方法(直接在對(duì)象上添加方法) 介紹 :對(duì)于單個(gè)對(duì)象,可以直接在對(duì)象字面量定義中添加方法。這種方法簡(jiǎn)單直接,適用于創(chuàng)建一次性的、具有特定行為的對(duì)象。示例 :
const myObject = { property : "value" , myMethod : function ( ) { console. log ( "This is my method" ) ; }
} ;
myObject. myMethod ( ) ;
Object.assign()
方法擴(kuò)展(合并對(duì)象并添加方法) 介紹 :Object.assign()
方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象??梢岳盟鼇頂U(kuò)展一個(gè)對(duì)象,添加新的方法或覆蓋現(xiàn)有屬性。示例 :
const baseObject = { existingProperty : "existing value"
} ;
const newMethods = { newMethod : function ( ) { console. log ( "This is a new method" ) ; }
} ;
const extendedObject = Object. assign ( { } , baseObject, newMethods) ;
extendedObject. newMethod ( ) ;
class
語法擴(kuò)展方法(在類中添加方法) 介紹 :在ES6的class
語法中,可以在類定義內(nèi)部通過添加方法來擴(kuò)展類的功能。類的方法會(huì)被所有類的實(shí)例共享,這種方式更符合面向?qū)ο缶幊痰慕Y(jié)構(gòu)。示例 :
class Shape { constructor ( name ) { this . name = name; } area ( ) { console. log ( "The area method needs to be implemented in sub - classes" ) ; }
}
class Circle extends Shape { constructor ( radius ) { super ( "Circle" ) ; this . radius = radius; } area ( ) { return Math. PI * this . radius * this . radius; }
}
const myCircle = new Circle ( 5 ) ;
console. log ( myCircle. area ( ) ) ;
使用Function.prototype.bind()
間接擴(kuò)展方法(改變函數(shù)的this
指向來擴(kuò)展功能) 介紹 :bind()
方法會(huì)創(chuàng)建一個(gè)新函數(shù),當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),它的this
值會(huì)被綁定到指定的對(duì)象上。這可以用于在特定的上下文環(huán)境中擴(kuò)展函數(shù)的行為。例如,將一個(gè)通用的函數(shù)綁定到特定的對(duì)象上,使其能夠訪問該對(duì)象的屬性。示例 :
const obj = { value : 42
} ;
function showValue ( ) { console. log ( this . value) ;
}
const boundShowValue = showValue . bind ( obj) ;
boundShowValue ( ) ;
使用裝飾器模式(在函數(shù)外層包裝新功能)擴(kuò)展方法 介紹 :裝飾器模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,在JavaScript中可以用來在不修改原函數(shù)的基礎(chǔ)上,動(dòng)態(tài)地給函數(shù)添加新的功能。它通過創(chuàng)建一個(gè)包裝函數(shù),在包裝函數(shù)內(nèi)部調(diào)用原函數(shù),并在調(diào)用前后添加額外的邏輯。示例 :
function withLogging ( func ) { return function ( ) { console. log ( "Function is about to be called" ) ; const result = func . apply ( this , arguments) ; console. log ( "Function has been called" ) ; return result; } ;
}
function addNumbers ( a, b ) { return a + b;
}
const loggedAddNumbers = withLogging ( addNumbers) ;
console. log ( loggedAddNumbers ( 3 , 5 ) ) ;
使用Proxy
對(duì)象擴(kuò)展方法(攔截操作并添加自定義行為) 介紹 :Proxy
對(duì)象用于定義基本操作的自定義行為(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)??梢岳盟鼇頂r截對(duì)對(duì)象方法的調(diào)用,并在調(diào)用前后添加擴(kuò)展的邏輯,例如記錄方法調(diào)用次數(shù)、添加權(quán)限驗(yàn)證等。示例 :
const target = { myMethod : function ( ) { console. log ( "Original method called" ) ; }
} ;
const handler = { apply : function ( target, thisArg, argumentsList ) { console. log ( "Before method call" ) ; const result = target. myMethod . apply ( thisArg, argumentsList) ; console. log ( "After method call" ) ; return result; }
} ;
const proxiedObject = new Proxy ( target, handler) ;
proxiedObject. myMethod ( ) ;
擴(kuò)展方法應(yīng)用選擇
考慮代碼的組織和維護(hù)性 基于原型(prototype
)擴(kuò)展 適用場(chǎng)景 :當(dāng)你在構(gòu)建面向?qū)ο蟮腏avaScript代碼,并且希望在多個(gè)對(duì)象實(shí)例之間共享方法時(shí),使用prototype
擴(kuò)展是很好的選擇。例如,在創(chuàng)建自定義對(duì)象類型(如Person
、Car
等)時(shí),通過prototype
為所有實(shí)例添加通用的方法(如Person.prototype.sayHello
)可以減少內(nèi)存占用,因?yàn)榉椒ㄔ谠玩溕瞎蚕?#xff0c;而不是每個(gè)實(shí)例都有一份獨(dú)立的方法副本。示例 :
function Vehicle ( type ) { this . type = type;
}
Vehicle . prototype. start = function ( ) { console. log ( ` The ${ this . type} is starting. ` ) ;
} ;
const car = new Vehicle ( "car" ) ;
const truck = new Vehicle ( "truck" ) ;
car. start ( ) ;
truck. start ( ) ;
對(duì)象字面量擴(kuò)展 適用場(chǎng)景 :對(duì)于簡(jiǎn)單的、一次性的對(duì)象,對(duì)象字面量擴(kuò)展很方便。如果只是需要為一個(gè)特定的、獨(dú)立的對(duì)象添加一些方法,這種方式可以讓代碼在局部范圍內(nèi)清晰地定義對(duì)象及其行為。示例 :
const userSettings = { fontSize : 14 , color : "black" , updateFontSize : function ( newSize ) { this . fontSize = newSize; console. log ( ` Font size updated to ${ this . fontSize} ` ) ; }
} ;
userSettings. updateFontSize ( 16 ) ;
class
語法擴(kuò)展 適用場(chǎng)景 :在使用現(xiàn)代JavaScript開發(fā)大型應(yīng)用程序,遵循面向?qū)ο缶幊淘瓌t時(shí),class
語法提供了一種更結(jié)構(gòu)化、更易讀的方式來定義對(duì)象和擴(kuò)展方法。它使得代碼組織類似于傳統(tǒng)的面向?qū)ο笳Z言,便于團(tuán)隊(duì)協(xié)作和代碼維護(hù)。特別是在處理繼承關(guān)系(如extends
關(guān)鍵字)時(shí),class
語法更加清晰。示例 :
class Animal { constructor ( name ) { this . name = name; } makeSound ( ) { console. log ( "Generic animal sound" ) ; }
}
class Dog extends Animal { constructor ( name ) { super ( name) ; } makeSound ( ) { console. log ( "Woof!" ) ; }
}
const myDog = new Dog ( "Buddy" ) ;
myDog. makeSound ( ) ;
考慮功能需求和靈活性 Object.assign()
擴(kuò)展 適用場(chǎng)景 :當(dāng)需要合并多個(gè)對(duì)象的屬性和方法,或者從一個(gè)對(duì)象中復(fù)制屬性和方法到另一個(gè)對(duì)象時(shí),Object.assign()
很有用。這種方式在配置對(duì)象、創(chuàng)建具有默認(rèn)值和自定義值組合的對(duì)象等場(chǎng)景下表現(xiàn)出色。示例 :
const defaultSettings = { theme : "light" , fontSize : 16
} ;
const userPreferences = { fontSize : 18
} ;
const finalSettings = Object. assign ( { } , defaultSettings, userPreferences) ;
console. log ( finalSettings) ;
Function.prototype.bind()
間接擴(kuò)展 適用場(chǎng)景 :如果需要改變函數(shù)內(nèi)部this
的指向,將函數(shù)綁定到特定的對(duì)象上下文,bind()
方法是合適的選擇。在事件處理、回調(diào)函數(shù)等場(chǎng)景中,經(jīng)常需要確保函數(shù)在正確的this
上下文中執(zhí)行。示例 :
const button = document. createElement ( "button" ) ;
button. textContent = "Click me" ;
const obj = { message : "Button clicked"
} ;
button. addEventListener ( "click" , function ( ) { console. log ( this . message) ;
} . bind ( obj) ) ;
document. body. appendChild ( button) ;
裝飾器模式擴(kuò)展 適用場(chǎng)景 :當(dāng)你想要在不修改原有函數(shù)代碼的基礎(chǔ)上,為函數(shù)添加額外的功能,如日志記錄、性能監(jiān)控、權(quán)限驗(yàn)證等,裝飾器模式是很好的選擇。它提供了一種靈活的方式來動(dòng)態(tài)地增強(qiáng)函數(shù)的功能。示例 :
function logExecutionTime ( func ) { return function ( ) { const startTime = Date. now ( ) ; const result = func . apply ( this , arguments) ; const endTime = Date. now ( ) ; console. log ( ` Function ${ func. name} took ${ endTime - startTime} ms to execute ` ) ; return result; } ;
}
function add ( a, b ) { return a + b;
}
const loggedAdd = logExecutionTime ( add) ;
console. log ( loggedAdd ( 3 , 5 ) ) ;
Proxy
對(duì)象擴(kuò)展 適用場(chǎng)景 :如果需要對(duì)對(duì)象的操作(如方法調(diào)用、屬性訪問等)進(jìn)行攔截,并添加自定義的邏輯,如數(shù)據(jù)驗(yàn)證、訪問控制等,Proxy
對(duì)象是合適的選擇。它提供了一種強(qiáng)大的機(jī)制來擴(kuò)展對(duì)象的行為,并且可以在運(yùn)行時(shí)動(dòng)態(tài)地改變對(duì)象的行為。示例 :
const user = { name : "John" , age : 30
} ;
const userProxy = new Proxy ( user, { get ( target, property) { console. log ( ` Accessing property ${ property} ` ) ; return target[ property] ; } , set ( target, property, value) { console. log ( ` Setting property ${ property} to ${ value} ` ) ; target[ property] = value; return true ; }
} ) ;
console. log ( userProxy. name) ;
userProxy. age = 31 ;
大型項(xiàng)目 中擴(kuò)展方法應(yīng)用選擇
遵循面向?qū)ο笤O(shè)計(jì)原則(使用class
和prototype
) class
語法 適用場(chǎng)景 :在大型項(xiàng)目中,如果要構(gòu)建復(fù)雜的對(duì)象層次結(jié)構(gòu),class
語法是首選。例如,在一個(gè)大型的Web應(yīng)用程序的用戶界面組件庫中,每個(gè)組件可以定義為一個(gè)類。像React
組件(雖然它有自己的基于類的舊語法和函數(shù)式組件語法)或Vue
組件的類定義,通過class
可以清晰地定義組件的屬性、方法和生命周期鉤子等。示例 :假設(shè)我們?cè)跇?gòu)建一個(gè)簡(jiǎn)單的UI組件庫,有一個(gè)基礎(chǔ)的Button
類。
class Button { constructor ( text ) { this . text = text; this . enabled = true ; } click ( ) { if ( this . enabled) { console. log ( ` Button " ${ this . text} " clicked. ` ) ; } else { console. log ( ` Button " ${ this . text} " is disabled. ` ) ; } } disable ( ) { this . enabled = false ; }
}
const myButton = new Button ( "Submit" ) ;
myButton. click ( ) ;
myButton. disable ( ) ;
myButton. click ( ) ;
prototype
擴(kuò)展(與class
結(jié)合使用) : 適用場(chǎng)景 :對(duì)于一些通用的、不依賴于特定類實(shí)例狀態(tài)的方法,可以通過prototype
來擴(kuò)展。例如,在處理數(shù)據(jù)模型類時(shí),可能有一些工具方法用于數(shù)據(jù)驗(yàn)證或格式化,這些方法可以放在原型上。假設(shè)我們有一個(gè)User
數(shù)據(jù)模型類,通過prototype
為其添加一個(gè)驗(yàn)證電子郵件格式的方法。示例 :
function User ( name, email ) { this . name = name; this . email = email;
}
User . prototype. validateEmail = function ( ) { const emailRegex = / ^ [ a- zA - Z0 - 9_. + - ] + @[ a- zA - Z0 - 9 - ] + \. [ a- zA - Z0 - 9 - . ] + $/ ; return emailRegex. test ( this . email) ;
} ;
const user1 = new User ( "Alice" , "alice@example.com" ) ;
const user2 = new User ( "Bob" , "invalid_email" ) ;
console. log ( user1. validateEmail ( ) ) ;
console. log ( user2. validateEmail ( ) ) ;
配置和對(duì)象合并(使用Object.assign()
) 適用場(chǎng)景 :在大型項(xiàng)目中,配置管理是很重要的部分。Object.assign()
可用于合并默認(rèn)配置和用戶自定義配置。例如,在一個(gè)項(xiàng)目的主題系統(tǒng)中,有默認(rèn)的主題配置(顏色、字體等),可以使用Object.assign()
將用戶選擇的主題配置合并進(jìn)去。示例 :
const defaultTheme = { primaryColor : "blue" , secondaryColor : "gray" , fontSize : "16px"
} ;
const userTheme = { secondaryColor : "green" , fontWeight : "bold"
} ;
const finalTheme = Object. assign ( { } , defaultTheme, userTheme) ;
console. log ( finalTheme) ;
函數(shù)增強(qiáng)和中間件模式(裝飾器模式和Function.prototype.bind()
) 裝飾器模式 適用場(chǎng)景 :在大型項(xiàng)目的請(qǐng)求處理、日志記錄或權(quán)限控制等場(chǎng)景中,裝飾器模式可以有效地增強(qiáng)函數(shù)功能。例如,在一個(gè)后端API服務(wù)中,對(duì)于每個(gè)API端點(diǎn)的處理函數(shù),可以使用裝飾器來添加日志記錄和權(quán)限驗(yàn)證功能。示例 :假設(shè)我們有一個(gè)簡(jiǎn)單的函數(shù)用于獲取用戶數(shù)據(jù),使用裝飾器來添加日志記錄。
function logFunctionCall ( func ) { return function ( ) { console. log ( ` Calling function ${ func. name} ` ) ; return func . apply ( this , arguments) ; } ;
}
function getUserData ( userId ) { console. log ( ` Fetching data for user ${ userId} ` ) ; return { id : userId, name : "John Doe" } ;
}
const loggedGetUserData = logFunctionCall ( getUserData) ;
loggedGetUserData ( 123 ) ;
Function.prototype.bind()
適用場(chǎng)景 :在處理事件綁定或異步操作的回調(diào)函數(shù)時(shí),bind()
方法可以確保函數(shù)在正確的上下文中執(zhí)行。例如,在一個(gè)大型的JavaScript應(yīng)用程序中,當(dāng)處理用戶界面交互事件,如按鈕點(diǎn)擊事件,需要將事件處理函數(shù)綁定到正確的組件實(shí)例上。示例 :
class Counter { constructor ( ) { this . count = 0 ; this . incrementButton = document. createElement ( "button" ) ; this . incrementButton. textContent = "Increment" ; this . incrementButton. addEventListener ( "click" , this . increment . bind ( this ) ) ; document. body. appendChild ( this . incrementButton) ; } increment ( ) { this . count++ ; console. log ( ` Count: ${ this . count} ` ) ; }
}
new Counter ( ) ;
代理和攔截(使用Proxy
) 適用場(chǎng)景 :在大型項(xiàng)目的數(shù)據(jù)訪問層或?qū)ο蠼换?#xff0c;如果需要對(duì)對(duì)象的操作進(jìn)行細(xì)粒度的控制和攔截,Proxy
是很好的選擇。例如,在一個(gè)數(shù)據(jù)緩存系統(tǒng)中,可以使用Proxy
來攔截對(duì)數(shù)據(jù)對(duì)象的訪問,實(shí)現(xiàn)自動(dòng)緩存和讀取緩存的功能。示例 :
const cache = new Map ( ) ;
function createCachedObject ( target ) { return new Proxy ( target, { get ( target, property) { if ( ! cache. has ( property) ) { cache. set ( property, target[ property] ) ; } return cache. get ( property) ; } } ) ;
}
const dataObject = { value1 : 10 , value2 : 20
} ;
const cachedDataObject = createCachedObject ( dataObject) ;
console. log ( cachedDataObject. value1) ;
console. log ( cachedDataObject. value1) ;
小型項(xiàng)目中 擴(kuò)展應(yīng)用
對(duì)象字面量擴(kuò)展方法 適用場(chǎng)景 當(dāng)項(xiàng)目規(guī)模較小,邏輯相對(duì)簡(jiǎn)單,且主要是處理一些獨(dú)立的、一次性的對(duì)象時(shí),對(duì)象字面量擴(kuò)展方法是很方便的選擇。例如,在一個(gè)簡(jiǎn)單的網(wǎng)頁表單驗(yàn)證腳本中,你可能只需要為一個(gè)包含表單字段信息的對(duì)象添加驗(yàn)證方法。 示例
const formData = { username : "" , password : "" , validateUsername : function ( ) { return this . username. length > 0 ; } , validatePassword : function ( ) { return this . password. length >= 6 ; }
} ;
console. log ( formData. validateUsername ( ) ) ;
console. log ( formData. validatePassword ( ) ) ;
Function.prototype.bind()
方法 適用場(chǎng)景 在小型項(xiàng)目的事件處理場(chǎng)景中,尤其是當(dāng)你需要確保函數(shù)內(nèi)部的this
指向正確的對(duì)象時(shí),bind()
方法非常實(shí)用。例如,在一個(gè)小型的圖片輪播插件中,你可能有一個(gè)用于切換圖片的函數(shù),需要將其綁定到輪播組件對(duì)象上,以正確地訪問和更新組件的狀態(tài)。 示例
const carousel = { currentIndex : 0 , images : [ "image1.jpg" , "image2.jpg" , "image3.jpg" ] , nextImage : function ( ) { this . currentIndex++ ; if ( this . currentIndex >= this . images. length) { this . currentIndex = 0 ; } console. log ( ` Showing ${ this . images[ this . currentIndex] } ` ) ; }
} ;
const nextButton = document. createElement ( "button" ) ;
nextButton. textContent = "Next" ;
nextButton. addEventListener ( "click" , carousel. nextImage . bind ( carousel) ) ;
document. body. appendChild ( nextButton) ;
簡(jiǎn)單的原型(prototype
)擴(kuò)展(對(duì)于基于函數(shù)構(gòu)造器的情況) 適用場(chǎng)景 如果小型項(xiàng)目中使用了基于函數(shù)構(gòu)造器創(chuàng)建的對(duì)象,并且有一些通用的方法需要被這些對(duì)象共享,原型擴(kuò)展是一個(gè)不錯(cuò)的方式。比如,在一個(gè)簡(jiǎn)單的游戲項(xiàng)目中,有多種游戲角色都需要有一個(gè)移動(dòng)的方法,可以通過原型來添加這個(gè)共享的方法。 示例
function Character ( name, x, y ) { this . name = name; this . x = x; this . y = y;
}
Character . prototype. move = function ( dx, dy ) { this . x += dx; this . y += dy; console. log ( ` ${ this . name} moved to ( ${ this . x} , ${ this . y} ) ` ) ;
} ;
const player = new Character ( "Player" , 0 , 0 ) ;
const enemy = new Character ( "Enemy" , 5 , 5 ) ;
player. move ( 1 , 1 ) ;
enemy. move ( - 1 , - 1 ) ;