超詳細(xì)JavaScript深淺拷貝的實(shí)現(xiàn)教程
一、淺拷貝
淺拷貝是指,一個(gè)新的對(duì)象對(duì)原始對(duì)象的屬性值進(jìn)行精確地拷貝,如果拷貝的是基本數(shù)據(jù)類型,拷貝的就是基本數(shù)據(jù)類型的值;如果拷貝的是引用數(shù)據(jù)類型,拷貝的就是內(nèi)存地址。如果其中一個(gè)對(duì)象的引用內(nèi)存地址發(fā)生改變,另一個(gè)對(duì)象也會(huì)發(fā)生變化。
1. Object.assign()
object.assign
是 ES6 中 object 的一個(gè)方法,該方法可以用于 JS 對(duì)象的合并。我們可以使用它來(lái)實(shí)現(xiàn)淺拷貝。
該方法的參數(shù) target 指的是目標(biāo)對(duì)象,sources指的是源對(duì)象。使用形式如下:
Object.assign(target,?...sources)
使用示例:
let?target?=?{a:?1}; let?object2?=?{b:?{d?:?2}}; let?object3?=?{c:?3}; Object.assign(target,?object2,?object3);?? console.log(target);??//?{a:?1,?b:?{d?:?2},?c:?3}
這里通過(guò) Object.assign 將 object2 和 object3 拷貝到了 target 對(duì)象中,下面來(lái)嘗試將 object2 對(duì)象中的 b 屬性中的d屬性由 2 修改為 666:
object2.b.d?=?666; console.log(target);?//?{a:?1,?b:?{d:?666},?c:?3}
可以看到,target的b屬性值的d屬性值變成了666,因?yàn)檫@個(gè)b的屬性值是一個(gè)對(duì)象,它保存了該對(duì)象的內(nèi)存地址,當(dāng)原對(duì)象發(fā)生變化時(shí),引用他的值也會(huì)發(fā)生變化。
注意:
- 如果目標(biāo)對(duì)象和源對(duì)象有同名屬性,或者多個(gè)源對(duì)象有同名屬性,則后面的屬性會(huì)覆蓋前面的屬性;
- 如果該函數(shù)只有一個(gè)參數(shù),當(dāng)參數(shù)為對(duì)象時(shí),直接返回該對(duì)象;當(dāng)參數(shù)不是對(duì)象時(shí),會(huì)先將參數(shù)轉(zhuǎn)為對(duì)象然后返回;
- 因?yàn)?code>null 和
undefined
不能轉(zhuǎn)化為對(duì)象,所以第一個(gè)參數(shù)不能為null
或undefined
,否則會(huì)報(bào)錯(cuò); - 它不會(huì)拷貝對(duì)象的繼承屬性,不會(huì)拷貝對(duì)象的不可枚舉的屬性,可以拷貝 Symbol 類型的屬性。
實(shí)際上,Object.assign 會(huì)循環(huán)遍歷原對(duì)象的可枚舉屬性,通過(guò)復(fù)制的方式將其賦值給目標(biāo)對(duì)象的相應(yīng)屬性。
2. 擴(kuò)展運(yùn)算符
使用擴(kuò)展運(yùn)算符可以在構(gòu)造字面量對(duì)象的時(shí)候,進(jìn)行屬性的拷貝。使用形式如下:
let?cloneObj?=?{?...obj?};
使用示例:
let?obj1?=?{a:1,b:{c:1}} let?obj2?=?{...obj1}; obj1.a?=?2; console.log(obj1);?//{a:2,b:{c:1}} console.log(obj2);?//{a:1,b:{c:1}} obj1.b.c?=?2; console.log(obj1);?//{a:2,b:{c:2}} console.log(obj2);?//{a:1,b:{c:2}}
擴(kuò)展運(yùn)算符 和 object.assign 實(shí)現(xiàn)的淺拷貝的功能差不多,如果屬性都是基本類型的值,使用擴(kuò)展運(yùn)算符進(jìn)行淺拷貝會(huì)更加方便。
3. 數(shù)組淺拷貝
(1)Array.prototype.slice()
slice()
方法是JavaScript數(shù)組方法,該方法可以從已有數(shù)組中返回選定的元素,不會(huì)改變?cè)紨?shù)組。使用方式如下:
array.slice(start,?end)
該方法有兩個(gè)參數(shù),兩個(gè)參數(shù)都可選:
- start: 規(guī)定從何處開(kāi)始選取。如果是負(fù)數(shù),那么它規(guī)定從數(shù)組尾部開(kāi)始算起的位置。也就是說(shuō),-1 指最后一個(gè)元素,-2 指倒數(shù)第二個(gè)元素,以此類推。
- end:規(guī)定從何處結(jié)束選取。該參數(shù)是數(shù)組片斷結(jié)束處的數(shù)組下標(biāo)。如果沒(méi)有指定該參數(shù),那么切分的數(shù)組包含從 start 到數(shù)組結(jié)束的所有元素。如果這個(gè)參數(shù)是負(fù)數(shù),那么它規(guī)定的是從數(shù)組尾部開(kāi)始算起的元素。
如果兩個(gè)參數(shù)都不寫,就可以實(shí)現(xiàn)一個(gè)數(shù)組的淺拷貝:
let?arr?=?[1,2,3,4]; console.log(arr.slice());?//?[1,2,3,4] console.log(arr.slice()?===?arr);?//false
slice 方法不會(huì)修改原數(shù)組,只會(huì)返回一個(gè)淺拷貝了原數(shù)組中的元素的一個(gè)新數(shù)組。原數(shù)組的元素會(huì)按照下述規(guī)則拷貝:
- 如果該元素是個(gè)對(duì)象引用 (不是實(shí)際的對(duì)象),slice 會(huì)拷貝這個(gè)對(duì)象引用到新的數(shù)組里。兩個(gè)對(duì)象引用都引用了同一個(gè)對(duì)象。如果被引用的對(duì)象發(fā)生改變,則新的和原來(lái)的數(shù)組中的這個(gè)元素也會(huì)發(fā)生改變。
- 對(duì)于字符串、數(shù)字及布爾值來(lái)說(shuō),slice 會(huì)拷貝這些值到新的數(shù)組里。在別的數(shù)組里修改這些字符串或數(shù)字或是布爾值,將不會(huì)影響另一個(gè)數(shù)組。
如果向兩個(gè)數(shù)組任一中添加了新元素,則另一個(gè)不會(huì)受到影響。
(2)Array.prototype.concat()
concat()
方法用于合并兩個(gè)或多個(gè)數(shù)組,此方法不會(huì)更改原始數(shù)組,而是返回一個(gè)新數(shù)組。使用方式如下:
arrayObject.concat(arrayX,arrayX,......,arrayX)
該方法的參數(shù)arrayX是一個(gè)數(shù)組或值,將被合并到arrayObject數(shù)組中。如果省略了所有 arrayX 參數(shù),則 concat 會(huì)返回調(diào)用此方法的現(xiàn)存數(shù)組的一個(gè)淺拷貝:
let?arr?=?[1,2,3,4]; console.log(arr.concat());?//?[1,2,3,4] console.log(arr.concat()?===?arr);?//false
concat方法創(chuàng)建一個(gè)新的數(shù)組,它由被調(diào)用的對(duì)象中的元素組成,每個(gè)參數(shù)的順序依次是該參數(shù)的元素(參數(shù)是數(shù)組)或參數(shù)本身(參數(shù)不是數(shù)組)。它不會(huì)遞歸到嵌套數(shù)組參數(shù)中。
concat方法不會(huì)改變this或任何作為參數(shù)提供的數(shù)組,而是返回一個(gè)淺拷貝,它包含與原始數(shù)組相結(jié)合的相同元素的副本。原始數(shù)組的元素將復(fù)制到新數(shù)組中,如下所示:
- 對(duì)象引用(而不是實(shí)際對(duì)象):concat將對(duì)象引用復(fù)制到新數(shù)組中。原始數(shù)組和新數(shù)組都引用相同的對(duì)象。也就是說(shuō),如果引用的對(duì)象被修改,則更改對(duì)于新數(shù)組和原始數(shù)組都是可見(jiàn)的。這包括也是數(shù)組的數(shù)組參數(shù)的元素。
- 數(shù)據(jù)類型如字符串,數(shù)字和布爾值:concat將字符串和數(shù)字的值復(fù)制到新數(shù)組中。
4. 手寫實(shí)現(xiàn)淺拷貝
根據(jù)以上對(duì)淺拷貝的理解,實(shí)現(xiàn)淺拷貝的思路:
- 對(duì)基礎(chǔ)類型做最基本的拷貝;
- 對(duì)引用類型開(kāi)辟新的存儲(chǔ),并且拷貝一層對(duì)象屬性。
代碼實(shí)現(xiàn):
//?淺拷貝的實(shí)現(xiàn); function?shallowCopy(object)?{ ??//?只拷貝對(duì)象 ??if?(!object?||?typeof?object?!==?"object")?return; ??//?根據(jù)?object?的類型判斷是新建一個(gè)數(shù)組還是對(duì)象 ??let?newObject?=?Array.isArray(object)???[]?:?{}; ??//?遍歷?object,并且判斷是?object?的屬性才拷貝 ??for?(let?key?in?object)?{ ????if?(object.hasOwnProperty(key))?{ ??????newObject[key]?=?object[key]; ????} ??} ??return?newObject; }
這里用到了 hasOwnProperty()
方法,該方法會(huì)返回一個(gè)布爾值,指示對(duì)象自身屬性中是否具有指定的屬性。所有繼承了 Object 的對(duì)象都會(huì)繼承到 hasOwnProperty()
方法。這個(gè)方法可以用來(lái)檢測(cè)一個(gè)對(duì)象是否是自身屬性。
可以看到,所有的淺拷貝都只能拷貝一層對(duì)象。如果存在對(duì)象的嵌套,那么淺拷貝就無(wú)能為力了。深拷貝就是為了解決這個(gè)問(wèn)題而生的,它能解決多層對(duì)象嵌套問(wèn)題,徹底實(shí)現(xiàn)拷貝。
二、深拷貝
深拷貝是指,對(duì)于簡(jiǎn)單數(shù)據(jù)類型直接拷貝他的值,對(duì)于引用數(shù)據(jù)類型,在堆內(nèi)存中開(kāi)辟一塊內(nèi)存用于存放復(fù)制的對(duì)象,并把原有的對(duì)象類型數(shù)據(jù)拷貝過(guò)來(lái),這兩個(gè)對(duì)象相互獨(dú)立,屬于兩個(gè)不同的內(nèi)存地址,修改其中一個(gè),另一個(gè)不會(huì)發(fā)生改變。
1. JSON.stringify()
JSON.parse(JSON.stringify(obj))
是比較常用的深拷貝方法之一,它的原理就是利用JSON.stringify
將JavaScript
對(duì)象序列化成為JSON字符串),并將對(duì)象里面的內(nèi)容轉(zhuǎn)換成字符串,再使用JSON.parse
來(lái)反序列化,將字符串生成一個(gè)新的JavaScript對(duì)象。
這個(gè)方法是目前我在公司項(xiàng)目開(kāi)發(fā)中使用最多的深拷貝的方法,也是最簡(jiǎn)單的方法。
使用示例:
let?obj1?=?{?? ??a:?0, ??b:?{ ????c:?0 ??} }; let?obj2?=?JSON.parse(JSON.stringify(obj1)); obj1.a?=?1; obj1.b.c?=?1; console.log(obj1);?//?{a:?1,?b:?{c:?1}} console.log(obj2);?//?{a:?0,?b:?{c:?0}}
這個(gè)方法雖然簡(jiǎn)單粗暴,但也存在一些問(wèn)題,在使用該方法時(shí)需要注意:
- 拷貝的對(duì)象中如果有函數(shù),undefined,symbol,當(dāng)使用過(guò)
JSON.stringify()
進(jìn)行處理之后,都會(huì)消失。 - 無(wú)法拷貝不可枚舉的屬性;
- 無(wú)法拷貝對(duì)象的原型鏈;
- 拷貝 Date 引用類型會(huì)變成字符串;
- 拷貝 RegExp 引用類型會(huì)變成空對(duì)象;
- 對(duì)象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的結(jié)果會(huì)變成 null;
- 無(wú)法拷貝對(duì)象的循環(huán)應(yīng)用,即對(duì)象成環(huán) (
obj[key] = obj
)。
在日常開(kāi)發(fā)中,上述幾種情況一般很少出現(xiàn),所以這種方法基本可以滿足日常的開(kāi)發(fā)需求。如果需要拷貝的對(duì)象中存在上述情況,還是要考慮使用下面的幾種方法。
2. 函數(shù)庫(kù)lodash
該函數(shù)庫(kù)也有提供_.cloneDeep
用來(lái)做深拷貝,可以直接引入并使用:
var?_?=?require('lodash'); var?obj1?=?{ ????a:?1, ????b:?{?f:?{?g:?1?}?}, ????c:?[1,?2,?3] }; var?obj2?=?_.cloneDeep(obj1); console.log(obj1.b.f?===?obj2.b.f);//?false
這里附上lodash中深拷貝的源代碼供大家學(xué)習(xí):
/** * value:需要拷貝的對(duì)象 * bitmask:位掩碼,其中 1 是深拷貝,2 拷貝原型鏈上的屬性,4 是拷貝 Symbols 屬性 * customizer:定制的 clone 函數(shù) * key:傳入 value 值的 key * object:傳入 value 值的父對(duì)象 * stack:Stack 棧,用來(lái)處理循環(huán)引用 */ function?baseClone(value,?bitmask,?customizer,?key,?object,?stack)?{ ????let?result ? ????//?標(biāo)志位 ????const?isDeep?=?bitmask?&?CLONE_DEEP_FLAG??//?深拷貝,true ????const?isFlat?=?bitmask?&?CLONE_FLAT_FLAG??//?拷貝原型鏈,false ????const?isFull?=?bitmask?&?CLONE_SYMBOLS_FLAG?//?拷貝?Symbol,true ? ????//?自定義?clone?函數(shù) ????if?(customizer)?{ ????????result?=?object???customizer(value,?key,?object,?stack)?:?customizer(value) ????} ????if?(result?!==?undefined)?{ ????????return?result ????} ? ????//?非對(duì)象?? ????if?(!isObject(value))?{ ????????return?value ????} ???? ????const?isArr?=?Array.isArray(value) ????const?tag?=?getTag(value) ????if?(isArr)?{ ????????//?數(shù)組 ????????result?=?initCloneArray(value) ????????if?(!isDeep)?{ ????????????return?copyArray(value,?result) ????????} ????}?else?{ ????????//?對(duì)象 ????????const?isFunc?=?typeof?value?==?'function' ? ????????if?(isBuffer(value))?{ ????????????return?cloneBuffer(value,?isDeep) ????????} ????????if?(tag?==?objectTag?||?tag?==?argsTag?||?(isFunc?&&?!object))?{ ????????????result?=?(isFlat?||?isFunc)???{}?:?initCloneObject(value) ????????????if?(!isDeep)?{ ????????????????return?isFlat ??????????????????????copySymbolsIn(value,?copyObject(value,?keysIn(value),?result)) ?????????????????:?copySymbols(value,?Object.assign(result,?value)) ????????????} ????????}?else?{ ????????????if?(isFunc?||?!cloneableTags[tag])?{ ????????????????return?object???value?:?{} ????????????} ????????????result?=?initCloneByTag(value,?tag,?isDeep) ????????} ????} ????//?循環(huán)引用 ????stack?||?(stack?=?new?Stack) ????const?stacked?=?stack.get(value) ????if?(stacked)?{ ????????return?stacked ????} ????stack.set(value,?result) ? ????//?Map ????if?(tag?==?mapTag)?{ ????????value.forEach((subValue,?key)?=>?{ ????????????result.set(key,?baseClone(subValue,?bitmask,?customizer,?key,?value,?stack)) ????????}) ????????return?result ????} ? ????//?Set ????if?(tag?==?setTag)?{ ????????value.forEach((subValue)?=>?{ ????????????result.add(baseClone(subValue,?bitmask,?customizer,?subValue,?value,?stack)) ????????}) ????????return?result ????} ? ????//?TypedArray ????if?(isTypedArray(value))?{ ????????return?result ????} ? ????//?Symbol?&?原型鏈 ????const?keysFunc?=?isFull ???????(isFlat???getAllKeysIn?:?getAllKeys) ?????:?(isFlat???keysIn?:?keys) ? ????const?props?=?isArr???undefined?:?keysFunc(value) ???? ????//?遍歷賦值 ????arrayEach(props?||?value,?(subValue,?key)?=>?{ ????????if?(props)?{ ????????????key?=?subValue ????????????subValue?=?value[key] ????????} ????????assignValue(result,?key,?baseClone(subValue,?bitmask,?customizer,?key,?value,?stack)) ????}) ???? ????//?返回結(jié)果 ????return?result }
3. 手寫實(shí)現(xiàn)深拷貝
(1)基礎(chǔ)遞歸實(shí)現(xiàn)
實(shí)現(xiàn)深拷貝的思路就是,使用for in來(lái)遍歷傳入?yún)?shù)的屬性值,如果值是基本類型就直接復(fù)制,如果是引用類型就進(jìn)行遞歸調(diào)用該函數(shù),實(shí)現(xiàn)代碼如下:
function?deepClone(source)?{ ??????//判斷source是不是對(duì)象 ??????if?(source?instanceof?Object?==?false)?return?source; ?????? ????//根據(jù)source類型初始化結(jié)果變量 ??????let?target?=?Array.isArray(source)???[]?:?{};? ??????for?(let?i?in?source)?{ ????????//?判斷是否是自身屬性 ????????if?(source.hasOwnProperty(i))?{ ??????????//判斷數(shù)據(jù)i的類型 ??????????if?(typeof?source[i]?===?'object')?{ ????????????target[i]?=?deepClone(source[i]); ??????????}?else?{ ????????????target[i]?=?source[i]; ??????????} ????????} ??????} ??????return?target; ????} ??? console.log(clone({b:?{c:?{d:?1}}}));??//?{b:?{c:?{d:?1}}})
這樣雖然實(shí)現(xiàn)了深拷貝,但也存在一些問(wèn)題:
- 不能復(fù)制不可枚舉屬性以及 Symbol 類型;
- 只能對(duì)普通引用類型的值做遞歸復(fù)制,對(duì)于 Date、RegExp、Function 等引用類型不能正確拷貝;
- 可能存在循環(huán)引用問(wèn)題。
(2)優(yōu)化遞歸實(shí)現(xiàn)
上面只是實(shí)現(xiàn)了一個(gè)基礎(chǔ)版的深拷貝,對(duì)于上面存在的幾個(gè)問(wèn)題,可以嘗試去解決一下:
- 使用
Reflect.ownKeys()
方法來(lái)解決不能復(fù)制不可枚舉屬性以及 Symbol 類型的問(wèn)題。Reflect.ownKeys()
方法會(huì)返回一個(gè)由目標(biāo)對(duì)象自身的屬性鍵組成的數(shù)組。它的返回值等同于:Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
; - 當(dāng)參數(shù)值為 Date、RegExp 類型時(shí),直接生成一個(gè)新的實(shí)例并返回;
- 利用
Object.getOwnPropertyDescriptors()
方以獲得對(duì)象的所有屬性以及對(duì)應(yīng)的特性。簡(jiǎn)單來(lái)說(shuō),這個(gè)方法返回給定對(duì)象的所有屬性的信息,包括有關(guān)getter和setter的信息。它允許創(chuàng)建對(duì)象的副本并在復(fù)制所有屬性(包括getter和setter)時(shí)克隆它。 - 使用
Object.create()
方法創(chuàng)建一個(gè)新對(duì)象,并繼承傳入原對(duì)象的原型鏈。Object.create()
方法會(huì)創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的__proto__
。 - 使用 WeakMap 類型作為 Hash 表,WeakMap 是弱引用類型,可以防止內(nèi)存泄漏,所以可以用來(lái)檢測(cè)循環(huán)引用,如果存在循環(huán),則引用直接返回 WeakMap 存儲(chǔ)的值。WeakMap的特性就是,保存在其中的對(duì)象不會(huì)影響垃圾回收,如果WeakMap保存的節(jié)點(diǎn),在其他地方都沒(méi)有被引用了,那么即使它還在WeakMap中也會(huì)被垃圾回收回收掉了。在深拷貝的過(guò)程當(dāng)中,里面所有的引用對(duì)象都是被引用的,為了解決循環(huán)引用的問(wèn)題,在深拷貝的過(guò)程中,希望有個(gè)數(shù)據(jù)結(jié)構(gòu)能夠記錄每個(gè)引用對(duì)象有沒(méi)有被使用過(guò),但是深拷貝結(jié)束之后這個(gè)數(shù)據(jù)能自動(dòng)被垃圾回收,避免內(nèi)存泄漏。
代碼實(shí)現(xiàn):
function?deepClone?(obj,?hash?=?new?WeakMap())?{ ??//?日期對(duì)象直接返回一個(gè)新的日期對(duì)象 ??if?(obj?instanceof?Date){ ???return?new?Date(obj); ??}? ??//正則對(duì)象直接返回一個(gè)新的正則對(duì)象????? ??if?(obj?instanceof?RegExp){ ???return?new?RegExp(obj);????? ??} ??//如果循環(huán)引用,就用?weakMap?來(lái)解決 ??if?(hash.has(obj)){ ???return?hash.get(obj); ??} ??//?獲取對(duì)象所有自身屬性的描述 ??let?allDesc?=?Object.getOwnPropertyDescriptors(obj); ??//?遍歷傳入?yún)?shù)所有鍵的特性 ??let?cloneObj?=?Object.create(Object.getPrototypeOf(obj),?allDesc) ?? ??hash.set(obj,?cloneObj) ??for?(let?key?of?Reflect.ownKeys(obj))?{? ????if(typeof?obj[key]?===?'object'?&&?obj[key]?!==?null){ ?????cloneObj[key]?=?deepClone(obj[key],?hash); ????}?else?{ ?????cloneObj[key]?=?obj[key]; ????} ??} ??return?cloneObj }
可以使用以下數(shù)據(jù)進(jìn)行測(cè)試:
let?obj?=?{ ??num:?1, ??str:?'str', ??boolean:?true, ??und:?undefined, ??nul:?null, ??obj:?{?name:?'對(duì)象',?id:?1?}, ??arr:?[0,?1,?2], ??func:?function?()?{?console.log('函數(shù)')?}, ??date:?new?Date(1), ??reg:?new?RegExp('/正則/ig'), ??[Symbol('1')]:?1, }; Object.defineProperty(obj,?'innumerable',?{ ??enumerable:?false,?value:?'不可枚舉屬性'? }); obj?=?Object.create(obj,?Object.getOwnPropertyDescriptors(obj)) obj.loop?=?obj????//?將loop設(shè)置成循環(huán)引用的屬性 let?cloneObj?=?deepClone(obj) console.log('obj',?obj) console.log('cloneObj',?cloneObj)
運(yùn)行結(jié)果如下:
可以看到,這樣基本就實(shí)現(xiàn)了多數(shù)數(shù)據(jù)類型的深拷貝,不過(guò)也還存在一些缺陷,比如Map和Set結(jié)構(gòu)在這個(gè)方法中無(wú)法進(jìn)行拷貝,可以自己實(shí)現(xiàn)一下。
以上就是超詳細(xì)JavaScript深淺拷貝的實(shí)現(xiàn)教程的詳細(xì)內(nèi)容,更多關(guān)于JavaScript深淺拷貝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Javascript實(shí)現(xiàn)商品秒殺倒計(jì)時(shí)(時(shí)間與服務(wù)器時(shí)間同步)
在一些購(gòu)物商城經(jīng)常看到有很多商品做秒殺活動(dòng),也就是倒計(jì)時(shí),本篇文章給大家介紹Javascript實(shí)現(xiàn)商品秒殺倒計(jì)時(shí)(時(shí)間與服務(wù)器時(shí)間同步),需要的朋友可以了解下2015-09-09javascript分頁(yè)代碼(當(dāng)前頁(yè)碼居中)
昨天看了妙味課堂的 分頁(yè)視頻教程,今天自己參照其思路,自己寫了下,并且自己新增了一個(gè)顯示頁(yè)碼個(gè)數(shù)的屬性 showPageNum2012-09-09js+css實(shí)現(xiàn)三級(jí)導(dǎo)航菜單
這篇文章主要為大家詳細(xì)介紹了js+css實(shí)現(xiàn)三級(jí)導(dǎo)航菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Javascript 使用function定義構(gòu)造函數(shù)
Javascript并不像Java、C#等語(yǔ)言那樣支持真正的類。但是在js中可以定義偽類。做到這一點(diǎn)的工具就是構(gòu)造函數(shù)和原型對(duì)象。首先介紹js中的構(gòu)造函數(shù)。2010-02-02一文詳解JavaScript?如何將?HTML?轉(zhuǎn)成?Markdown
這篇文章主要介紹了一文詳解JavaScript如何將HTML轉(zhuǎn)成Markdown,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08ES6基礎(chǔ)之 Promise 對(duì)象用法實(shí)例詳解
這篇文章主要介紹了ES6基礎(chǔ)之 Promise 對(duì)象用法,結(jié)合實(shí)例形式詳細(xì)分析了ES6中 Promise 對(duì)象功能、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-08-08JS仿京東移動(dòng)端手指撥動(dòng)切換輪播圖效果
這篇文章主要為大家詳細(xì)介紹了JS仿京東移動(dòng)端手指撥動(dòng)切換輪播圖效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12通過(guò)AJAX的JS、JQuery兩種方式解析XML示例介紹
解析XML的方法有很多,在本文要為大家介紹下是使用AJAX的JS、JQuery兩種方式來(lái)進(jìn)行解析,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下2013-09-09深入理解JavaScript單體內(nèi)置對(duì)象
下面小編就為大家?guī)?lái)一篇JavaScript單體內(nèi)置對(duì)象。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06