摘要:前言一篇徹底搞懂對象從此不用擔(dān)心沒對象啦本文從對象定義方法對象屬性數(shù)據(jù)類型遍歷幾種方法對象拷貝和攔截對象屬性方法及代碼實現(xiàn)幾個方面由淺入深介紹對象對象的聲明方法字面量構(gòu)造函數(shù)的作用創(chuàng)了一個新對象指向構(gòu)造函數(shù)構(gòu)造函數(shù)有返回會替換出來的對象如果
前言
一篇徹底搞懂對象,從此不用擔(dān)心沒對象啦;1.對象的聲明方法 1.1 字面量
本文從對象定義方法,對象屬性,Symbol數(shù)據(jù)類型,遍歷幾種方法,對象拷貝,vue2.x和vue3.x攔截對象屬性方法及代碼實現(xiàn)幾個方面由淺入深介紹對象
var test2 = {x:123,y:345}; console.log(test2);//{x:123,y:345}; console.log(test2.x);//123 console.log(test2.__proto__.x);//undefined console.log(test2.__proto__.x === test2.x);//false1.2 構(gòu)造函數(shù)
var test1 = new Object({x:123,y:345}); console.log(test1);//{x:123,y:345} console.log(test1.x);//123 console.log(test1.__proto__.x);//undefined console.log(test1.__proto__.x === test1.x);//false
new的作用:
1.創(chuàng)了一個新對象;
2.this指向構(gòu)造函數(shù);
3.構(gòu)造函數(shù)有返回,會替換new出來的對象,如果沒有就是new出來的對象
Obejct.create(obj,descriptor),obj是對象,describe描述符屬性(可選)
let test = Object.create({x:123,y:345}); console.log(test);//{} console.log(test.x);//123 console.log(test.__proto__.x);//3 console.log(test.__proto__.x === test.x);//true1.4 三種方法的優(yōu)缺點
1.功能:都能實現(xiàn)對象的聲明,并能夠賦值和取值
2.繼承性:內(nèi)置方法創(chuàng)建的對象繼承到__proto__屬性上
3.隱藏屬性:三種聲明方法會默認(rèn)為內(nèi)部的每個成員(屬性或方法)生成一些隱藏屬性,這些隱藏屬性是可以讀取和可配置的,屬性分類見下面
4.屬性讀取:Object.getOwnPropertyDescriptor()或getOwnPropertyDescriptor()
5.屬性設(shè)置:Object.definePropertype或Object.defineProperties
1.數(shù)據(jù)屬性4個特性:
configurable(可配置),enumerable(可枚舉),writable(可修改),value(屬性值)
2.訪問器屬性2個特性:
get(獲取),set(設(shè)置)
3.內(nèi)部屬性
由JavaScript引擎內(nèi)部使用的屬性;
不能直接訪問,但是可以通過對象內(nèi)置方法間接訪問,如:[[Prototype]]可以通過 Object.getPrototypeOf()訪問;
內(nèi)部屬性用[[]]包圍表示,是一個抽象操作,沒有對應(yīng)字符串類型的屬性名,如[[Prototype]].
1.定義:將一個屬性的所有特性編碼成一個對象返回
2.描述符的屬性有:數(shù)據(jù)屬性和訪問器屬性
3.使用范圍:
作為方法Object.defineProperty, Object.getOwnPropertyDescriptor, Object.create的第二個參數(shù),
1.訪問對象存在的屬性
特性名 | 默認(rèn)值 |
---|---|
value | 對應(yīng)屬性值 |
get | 對應(yīng)屬性值 |
set | undefined |
writable | true |
enumerable | true |
configurable | true |
所以通過上面三種聲明方法已存在的屬性都是有這些默認(rèn)描述符
2.訪問對象不存在的屬性
特性名 | 默認(rèn)值 |
---|---|
value | undefined |
get | undefined |
set | undefined |
writable | false |
enumerable | false |
configurable | false |
get,set與wriable,value是互斥的,如果有交集設(shè)置會報錯
2.4 屬性定義1.定義屬性的函數(shù)有兩個:Object.defineProperty和Object.defineProperties.例如:
Object.defineProperty(obj, propName, desc)
2.在引擎內(nèi)部,會轉(zhuǎn)換成這樣的方法調(diào)用:
obj.[[DefineOwnProperty]](propName, desc, true)
1.賦值運算符(=)就是在調(diào)用[[Put]].比如:
obj.prop = v;
2.在引擎內(nèi)部,會轉(zhuǎn)換成這樣的方法調(diào)用:
obj.[[Put]]("prop", v, isStrictModeOn)
名稱 | 含義 | 用法 |
---|---|---|
in | 如果指定的屬性在指定的對象或其原型鏈中,則in 運算符返回true | "name" in test //true |
hasOwnProperty() | 只判斷自身屬性 | test.hasOwnProperty("name") //true |
.或[] | 對象或原型鏈上不存在該屬性,則會返回undefined | test.name //"lei" test["name"] //"lei" |
是一種數(shù)據(jù)類型;
不能new,因為Symbol是一個原始類型的值,不是對象。
Symbol(),可以傳參
var s1 = Symbol(); var s2 = Symbol(); s1 === s2 // false // 有參數(shù)的情況 var s1 = Symbol("foo"); var s2 = Symbol("foo"); s1 === s2 // false3.3 用法
1.不能與其他類型的值進(jìn)行運算;
2.作為屬性名
let mySymbol = Symbol(); // 第一種寫法 var a = {}; a[mySymbol] = "Hello!"; // 第二種寫法 var a = { [mySymbol]: "Hello!" }; // 第三種寫法 var a = {}; Object.defineProperty(a, mySymbol, { value: "Hello!" }); // 以上寫法都得到同樣結(jié)果 a[mySymbol] // "Hello!"
3.作為對象屬性名時,不能用點運算符,可以用[]
let a = {}; let name = Symbol(); a.name = "lili"; a[name] = "lucy"; console.log(a.name,a[name]);
4.遍歷不會被for...in、for...of和Object.keys()、Object.getOwnPropertyNames()取到該屬性
3.4 Symbol.for1.定義:在全局中搜索有沒有以該參數(shù)作為名稱的Symbol值,如果有,就返回這個Symbol值,否則就新建并返回一個以該字符串為名稱的Symbol值
2.舉例:
var s1 = Symbol.for("foo"); var s2 = Symbol.for("foo"); s1 === s2 // true3.5 Symbol.keyFor
1.定義:返回一個已登記的Symbol類型值的key
2.舉例:
var s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" var s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined4.遍歷 4.1 一級對象遍歷方法
方法 | 特性 |
---|---|
for ... in | 遍歷對象自身的和繼承的可枚舉屬性(不含Symbol屬性) |
Object.keys(obj) | 返回一個數(shù)組,包括對象自身的(不含繼承的)所有可枚舉屬性(不含Symbol屬性) |
Object.getOwnPropertyNames(obj) | 返回一個數(shù)組,包括對象自身的所有可枚舉屬性(不含Symbol屬性) |
Object.getOwnPropertySymbols(obj) | 返回一個數(shù)組,包含對象自身的所有Symbol屬性 |
Reflect.ownKeys(obj) | 返回一個數(shù)組,包含對象自身的所有(不枚舉、可枚舉和Symbol)屬性 |
Reflect.enumerate(obj) | 返回一個Iterator對象,遍歷對象自身的和繼承的所有可枚舉屬性(不含Symbol屬性) |
總結(jié):1.只有Object.getOwnPropertySymbols(obj)和Reflect.ownKeys(obj)可以拿到Symbol屬性
2.只有Reflect.ownKeys(obj)可以拿到不可枚舉屬性
數(shù)據(jù)模型:
var treeNodes = [ { id: 1, name: "1", children: [ { id: 11, name: "11", children: [ { id: 111, name: "111", children:[] }, { id: 112, name: "112" } ] }, { id: 12, name: "12", children: [] } ], users: [] }, ];
遞歸:
var parseTreeJson = function(treeNodes){ if (!treeNodes || !treeNodes.length) return; for (var i = 0, len = treeNodes.length; i < len; i++) { var childs = treeNodes[i].children; console.log(treeNodes[i].id); if(childs && childs.length > 0){ parseTreeJson(childs); } } }; console.log("------------- 遞歸實現(xiàn) ------------------"); parseTreeJson(treeNodes);5.深度拷貝 5.1 Object.assign
1.定義:將源對象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對象(target)
2.用法:
合并多個對象 var target = { a: 1, b: 1 }; var source1 = { b: 2, c: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2);
3.注意:
這個是偽深度拷貝,只能拷貝第一層
1.原理:是將對象轉(zhuǎn)化為字符串,而字符串是簡單數(shù)據(jù)類型
5.3 遞歸拷貝function deepClone(source){ const targetObj = source.constructor === Array ? [] : {}; // 判斷復(fù)制的目標(biāo)是數(shù)組還是對象 for(let keys in source){ // 遍歷目標(biāo) if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === "object"){ // 如果值是對象,就遞歸一下 targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ // 如果不是,就直接賦值 targetObj[keys] = source[keys]; } } } return targetObj; }6.數(shù)據(jù)攔截
定義:利用對象內(nèi)置方法,設(shè)置屬性,進(jìn)而改變對象的屬性值
6.1 Object.defineProterty1.ES5出來的方法;
2.三個參數(shù):對象(必填),屬性值(必填),描述符(可選);
3.defineProterty的描述符屬性
數(shù)據(jù)屬性:value,writable,configurable,enumerable 訪問器屬性:get,set 注:不能同時設(shè)置value和writable,這兩對屬性是互斥的
4.攔截對象的兩種情況:
let obj = {name:"",age:"",sex:"" }, defaultName = ["這是姓名默認(rèn)值1","這是年齡默認(rèn)值1","這是性別默認(rèn)值1"]; Object.keys(obj).forEach(key => { Object.defineProperty(obj, key, { get() { return defaultName; }, set(value) { defaultName = value; } }); }); console.log(obj.name); console.log(obj.age); console.log(obj.sex); obj.name = "這是改變值1"; console.log(obj.name); console.log(obj.age); console.log(obj.sex); let objOne={},defaultNameOne="這是默認(rèn)值2"; Object.defineProperty(obj, "name", { get() { return defaultNameOne; }, set(value) { defaultNameOne = value; } }); console.log(objOne.name); objOne.name = "這是改變值2"; console.log(objOne.name);
5.攔截數(shù)組變化的情況
let a={}; bValue=1; Object.defineProperty(a,"b",{ set:function(value){ bValue=value; console.log("setted"); }, get:function(){ return bValue; } }); a.b;//1 a.b=[];//setted a.b=[1,2,3];//setted a.b[1]=10;//無輸出 a.b.push(4);//無輸出 a.b.length=5;//無輸出 a.b;//[1,10,3,4,undefined]; 結(jié)論:defineProperty無法檢測數(shù)組索引賦值,改變數(shù)組長度的變化; 但是通過數(shù)組方法來操作可以檢測到
6.存在的問題
不能監(jiān)聽數(shù)組索引賦值和改變長度的變化 必須深層遍歷嵌套的對象,因為defineProterty只能劫持對象的屬性,因此我們需要對每個對象的每個屬性進(jìn)行遍歷,如果屬性值也是對象那么需要深度遍歷,顯然能劫持一個完整的對象是更好的選擇6.2 proxy
1.ES6出來的方法,實質(zhì)是對對象做了一個攔截,并提供了13個處理方法
13個方法詳情請戳,阮一峰的proxy介紹
2.兩個參數(shù):對象和行為函數(shù)
let handler = { get(target, key, receiver) { console.log("get", key); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log("set", key, value); return Reflect.set(target, key, value, receiver); } }; let proxy = new Proxy(obj, handler); proxy.name = "李四"; proxy.age = 24;
3.問題和優(yōu)點
reflect對象沒有構(gòu)造函數(shù)
可以監(jiān)聽數(shù)組索引賦值,改變數(shù)組長度的變化,
是直接監(jiān)聽對象的變化,不用深層遍歷
1.defineProterty是es5的標(biāo)準(zhǔn),proxy是es6的標(biāo)準(zhǔn);
2.proxy可以監(jiān)聽到數(shù)組索引賦值,改變數(shù)組長度的變化;
3.proxy是監(jiān)聽對象,不用深層遍歷,defineProterty是監(jiān)聽屬性;
3.利用defineProterty實現(xiàn)雙向數(shù)據(jù)綁定(vue2.x采用的核心)
請戳,剖析Vue原理&實現(xiàn)雙向綁定MVVM
4.利用proxy實現(xiàn)雙向數(shù)據(jù)綁定(vue3.x會采用)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102133.html
摘要:面向?qū)ο笾玩湆ο蠛蛯ο笾g的關(guān)系注意這個系列文章要經(jīng)常站在之父的視角去思考。思考問題我們都知道都屬于那么既然他們都是對象一定有某些相同之處吧對象和對象之間有什么關(guān)聯(lián)呢如果說你沒有思考過這個問題那么可以換一個更具體的問題。 JS面向?qū)ο笾?【原型鏈】(對象和對象之間的關(guān)系) 注意這個系列文章,要經(jīng)常站在JS之父的視角去思考。 牢記我們的需求,我要在JS沒有class的情況下,那么...
摘要:實際上就是做了這樣一件事情顯式的指定是回顧一下隱式模式顯示模式觀點里所有函數(shù)都接受個參數(shù)第一個第二個是函數(shù)被調(diào)用時一定會有這個參數(shù)如果你用調(diào)用函數(shù)就是顯式的傳遞和如果你用語法直接調(diào)用函數(shù)那就去幫你偷偷的傳遞。 JS面向?qū)ο笾総his】 (對象和函數(shù)之間的關(guān)系) 上一篇,談了對象和對象的關(guān)系,現(xiàn)在我們談?wù)剬ο蠛秃瘮?shù)的關(guān)系 先說結(jié)論,也就是觀點1 觀點1: JS里函數(shù)和對象沒有關(guān)系,J...
摘要:序列文章面試之函數(shù)面試之對象面試之?dāng)?shù)組的幾個不操作面試之對比分析面試之?dāng)?shù)據(jù)結(jié)構(gòu)與算法前言設(shè)計模式如果應(yīng)用到項目中,可以實現(xiàn)代碼的復(fù)用和解耦,提高代碼質(zhì)量。 showImg(https://segmentfault.com/img/bVbq2VA?w=480&h=260); 序列文章 JS面試之函數(shù)(1)JS面試之對象(2)JS面試之?dāng)?shù)組的幾個不low操作(3)JS面試之http0.9~...
摘要:好程序員前端培訓(xùn)入門之基礎(chǔ)知識梳理匯總,前端工程師是當(dāng)前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。作用域鏈的前端,始終是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對象。 好程序員Web前端培訓(xùn)入門之JS基礎(chǔ)知識梳理匯總,Web前端工程師是當(dāng)前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。不論是專業(yè)還是非專業(yè),有基礎(chǔ)亦或是無基礎(chǔ),都想通過學(xué)習(xí)Web前端實現(xiàn)高薪就業(yè)。不過,學(xué)習(xí)要一...
摘要:好程序員前端培訓(xùn)入門之基礎(chǔ)知識梳理匯總,前端工程師是當(dāng)前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。作用域鏈的前端,始終是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對象。 好程序員Web前端培訓(xùn)入門之JS基礎(chǔ)知識梳理匯總,Web前端工程師是當(dāng)前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。不論是專業(yè)還是非專業(yè),有基礎(chǔ)亦或是無基礎(chǔ),都想通過學(xué)習(xí)Web前端實現(xiàn)高薪就業(yè)。不過,學(xué)習(xí)要一...
閱讀 638·2021-11-25 09:43
閱讀 1906·2021-11-17 09:33
閱讀 824·2021-09-07 09:58
閱讀 2062·2021-08-16 10:52
閱讀 482·2019-08-30 15:52
閱讀 1722·2019-08-30 15:43
閱讀 971·2019-08-30 15:43
閱讀 2922·2019-08-29 16:41