4、JavaScript的Object類型

Object對象

對象的創(chuàng)建

對象字面量
var obj = {}
構(gòu)造函數(shù)
//通過Object()是系統(tǒng)提供的構(gòu)造函數(shù)
var obj = new Object();
//系統(tǒng)提供的構(gòu)造函數(shù)還有Array(),Number()...

//自定義構(gòu)造函數(shù)
function Car(color){
    this.color = color;
    this.name = "BMW";
    this.gas = "300"
    this.run = function(){
        this.gas--;
    }
}
var car = new Car("red");//創(chuàng)建對象,相當(dāng)于工廠造對象,有基本的屬性,創(chuàng)建的對象都是獨(dú)立的。

構(gòu)造函數(shù)內(nèi)部原理:

在函數(shù)體最前面隱式加上 this = { }

執(zhí)行this.xxx = xxx;

隱式返回this(如果有自定義的不是引用類型,字符串等會被this代替,真正返回的是this)

function Person(name,height){
    //var this = {};隱式添加
    this.name = name;
    this.height = height;
    this.say = function(){
        console.log("my name is"+this.name);
    }
    return 100;
    //return this;隱式添加
}
var person = new Person("小明","179");//當(dāng)new了以后會進(jìn)行隱式添加兩行代碼
console.log(person);//依然輸出整個(gè)對象,而不是100
ES6中的class

上面的代碼等價(jià)于

class Person{
  constructor(name,height){
    //new時(shí)會執(zhí)行constructor的代碼
    this.name = name;
    this.height = height;
    this.say = function(){
        console.log("my name is"+this.name);
    }
    console.log(123);//當(dāng)new的時(shí)候會打印
  }
}
var person = new Person("小明","179");
console.log(person);

包裝類

原始值(六個(gè)原始值)不能擁有屬性和方法,當(dāng)硬要給原始值添加屬性得時(shí)候會隱式執(zhí)行new Number(4).len=3;

然后新建的Number對象就會被刪除。

六個(gè)原始值:number,boolean,string,null,undefined,symbol
引用類型:Object,Array,F(xiàn)unction,Date...

var num = 4;
num.len = 3;
//隱式執(zhí)行new Number(4).len = 3;然后刪除
console.log(num.len);//對象已經(jīng)刪除,但訪問時(shí)會再一次隱式執(zhí)行new Number(4).len,這是一個(gè)新的Number對象,里面并沒有l(wèi)en屬性,所以會打印undefine

能進(jìn)行這樣子操作的有Number,Boolean,String。

String、Boolean、Number類型的數(shù)據(jù)之所有會有可調(diào)用的方法,是因?yàn)樵谒脑玩溕隙x了那些可用的方法

原型

原型是函數(shù)上的一個(gè)屬性,他定義了構(gòu)造函數(shù)制造出來的對象的公有祖先。通過該構(gòu)造函數(shù)產(chǎn)生的對象,可以繼承該原型的屬性和方法,原型也是對象。
__proto__是對象訪問原型的屬性,在實(shí)例中存在。

Person.prototype.FirstName  = "鄒";//prototype是function對象的屬性,他的對象引用不可以訪問
Person.prototype.say = function(){
    console.log("I am father!");
}
function Person(){
    this.say = function(){
        console.log("I am son!");
    }
}
var p1 = new Person();
console.log(p1);
console.log(p1.__proto__);//__proto__是隱式屬性,對象的引用訪問原型。
/*
直接打印p1的時(shí)候顯示為空對象,因?yàn)镻erson對象沒有FirstName屬性。但是訪問p1.FirstName可以打印出“鄒”。原因是Person.prototype作為Person的父類,Person對象繼承了父類的屬性和方法。Person對象的所有對象都可以繼承父類的屬性和方法。這一點(diǎn)跟java的繼承思想基本一樣。
*/
console.log(p1      .say());
/*
this.say = function(){...}相當(dāng)于java繼承中的重寫。
*/

圖解:

對象的原型

原型的應(yīng)用

把對象共性的東西提取到原型里面,減少代碼的冗余。

Person.prototype.Name  = "寶馬";
Person.prototype.run = function(){
    console.log("run run run!!!");
}
function Car(color){
    this.color = color;
}
var car = new Car("red");
//此時(shí)car擁有Name屬性和run方法。

name屬性和run方法是共有的,可以提取共有屬性到原型。

原型對象的另一種寫法:

Person.prototype={
    constructor:Person,
    Name:"寶馬",
    run : function(){
        console.log("run run run!!!");
    }
    /* 這種寫法是把整個(gè)prototype對象的引用更換了,使用點(diǎn)賦值只是把prototype對象屬性賦新值。*/
}
function Car(color){
    this.color = color;
}
var car = new Car("red");
/*__proto__是javascript內(nèi)部隱式定義的屬性,當(dāng)使用構(gòu)造函數(shù)生成對象的時(shí)候,隱式執(zhí)行的var this = {}其實(shí)里面有東西:*/
var this = {
    __proto__:obj.prototype
} 
/*對象查找屬性的時(shí)候如果自身沒有,就會根據(jù)__proto__指向的obj.prototype去找*/

原型鏈

原型鏈結(jié)構(gòu)圖.png

原型鏈上的屬性增刪改查:增刪改都需要是本身屬性的增刪改,兒子不能增刪改父親的,父親可以增刪改自己的。

對象都有原型,絕大多數(shù)(使用Object.create(null)沒有原型)對象最終都會繼承Object.prototype。

缺點(diǎn):過多的繼承了父類沒用的屬性。

關(guān)于 prototype 和 _proto_

Javascript中所有的對象都是Object的實(shí)例,并繼承Object.prototype的屬性和方法,也就是說Object.prototype是所有對象的爸爸。(個(gè)人感覺搞清楚這一點(diǎn)很重要)。

1、當(dāng)定義一個(gè)函數(shù)的時(shí)候,這個(gè)函數(shù)會經(jīng)過瀏覽器處理,會得到一個(gè)prototype屬性。prototype里面有兩個(gè)屬性:constructor和_proto_。

--constructor這個(gè)屬性就指向了函數(shù)本身。

--這個(gè)_proto指向的就是構(gòu)造函數(shù)的prototype

--Object.prototype是所有函數(shù)的爹,當(dāng)你聲明一個(gè)函數(shù)的時(shí)候也就是相當(dāng)于對Object的實(shí)例化。

prototype

2、當(dāng)構(gòu)造函數(shù)被實(shí)例化,他的實(shí)例b的_proto_就指向了這個(gè)構(gòu)造函數(shù)B的prototype。

所以b._proto_==B.prototype

當(dāng)b需要訪問name時(shí),先從自身的屬性開始找,找不到就去_proto找,_proto指向了B的prototype中有name,所以訪問成功,實(shí)現(xiàn)了繼承。

__proto__和prototype

Object上的方法

方法名 用處
Object.create(prototype,[propertiesObject]) 用指定的原型對象及其屬性去創(chuàng)建一個(gè)新的對象
Object.assign(target,source1,source2...) 用于對象的合并,把source的可枚舉屬性合并到target上。
Object.defineProperties(obj,props) 在一個(gè)對象上定義或修改屬性,并返回該對象。
Object.defineProperty(obj,prop,descriptor) 在一個(gè)對象上定義或修改一個(gè)對象的屬性并返回這個(gè)對象。
Object.keys(obj) 返回一個(gè)由一個(gè)給定對象的自身可枚舉屬性組成的數(shù)組。
var obj ={ a:1, b:2};Object.keys(obj)
打印[a,b]
Object.values(obj) 方法返回一個(gè)給定對象自己的所有可枚舉屬性值的數(shù)組
Object.entries(obj) 返回一個(gè)給定對象自身可枚舉屬性的鍵值對數(shù)組??
obj.hasOwnProperty(“prop”) 判斷對象自身屬性中是否具有指定的屬性。
(不包括原型鏈)
Object.getOwnPropertyNames(obj) 返回一個(gè)由指定對象的所有自身屬性的屬性名組成的數(shù)組。
Obj.isPrototypeOf(obj) 判斷一個(gè)對象是否存在于另一個(gè)對象的原型鏈上。
Object.setPrototypeOf(obj,prototype) 設(shè)置對象的原型對象 (性能消耗很大。)
Object.is(value1,value2) 判斷兩個(gè)值是否相同。相當(dāng)于value1===value2
Object.freeze(obj) 凍結(jié)一個(gè)對象,凍結(jié)指的是不能向這個(gè)對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。
Object.isFrozen(obj) 判斷一個(gè)對象是否被凍結(jié)
Object.preventExtensions() 對象不能再添加新的屬性??尚薷模瑒h除現(xiàn)有屬性,不能添加新屬性。

Object.assign

把源對象(source)的可枚舉屬性拷貝到目標(biāo)對象,原來的相同屬性會被覆蓋掉。

const target = { a: 1, b: 2 };
const source1 = { b: 4, c: 5 };
const source2 = { c: 9, d: 8 };

const returnedTarget = Object.assign(target, source1, source2);

console.log(target);//Object { a: 1, b: 4, c: 9,  d: 8 }

console.log(returnedTarget);//Object { a: 1, b: 4, c: 9, d: 8 }

1、他的所有參數(shù)都是對象,如果不是對象會轉(zhuǎn)換為對象,如果首參數(shù)是null和undefind不能轉(zhuǎn)換成對象,所以會報(bào)錯(cuò)。
2、source除了是對象、字符串、數(shù)組以外的其他類型,不會產(chǎn)生影響。字符串會以數(shù)組形式進(jìn)行操作。
3、assign是淺拷貝,如果source屬性值是引用值,那么拷貝的是這個(gè)對象的引用
4、assign常用于:克隆對象、合并多個(gè)對象、為屬性指定默認(rèn)值。

Object.create

根據(jù)第一個(gè)參數(shù)(必須)為原型創(chuàng)建一個(gè)對象,并且這個(gè)對象擁有第二個(gè)參數(shù)(可選)的可枚舉屬性。

//var o = Object.create(null); 創(chuàng)建一個(gè)沒有prototype的對象
var obj = {name:"APPLE"}
var a = Object.create(obj,{
    "a":{value :1,congigurable :false,enumerable :true,writable:true},
    "b":{value :2,congigurable :false,enumerable :true,writable:true},
    "c":{value :3,congigurable :false,enumerable :true,writable:true}
})//創(chuàng)建一個(gè)a對象,他的原型是obj,它有a,b,c三個(gè)自身屬性。
console.log(a);//a.__proto__.name="APPLE"

1、undefined ,null沒有原型。
2、創(chuàng)建的對象以第一個(gè)對象為原型,創(chuàng)造出來的對象 通過_proto_訪問obj。
3、第二個(gè)參數(shù)是可選參數(shù),表示創(chuàng)建的對象擁有的自身屬性。
value:對象的屬性值。
congigurable:能否修改或刪除這個(gè)屬性名,默認(rèn)true
enumerable:此屬性是否為可枚舉(即能否被for-in遍歷),默認(rèn)true
writable:此屬性值是否可以被修改,默認(rèn)true

Object.definePropertyObject.defineProperties

通過定義屬性描述對象,來定義或修改一個(gè)屬性,然后返回修改后的對象.

{
  value: 123,//屬性的值,數(shù)據(jù)描述符
  writable: false,//可寫,數(shù)據(jù)描述符
  enumerable: true,//可枚舉
  configurable: false,//可配置性
  get: undefined,//獲取值,數(shù)據(jù)存取符
  set: undefined//設(shè)置值,數(shù)據(jù)存取符
}//屬性描述對象的一個(gè)實(shí)例,數(shù)據(jù)描述符和數(shù)據(jù)存取符不可一起使用。

  var obj = {
    a:10
  }
Object.defineProperty(obj, "attri", {
    value: 123,
    writable: false,
    enumerable: true,
    configurable: false
})//為obj對象設(shè)置attri屬性的描述對象。
//如果要設(shè)置多個(gè)屬性,使用Object.defineProperties

let value = 123;
Object.defineProperty(obj, "prop", {
    get() { 
      console.log('get');  
      return value; 
    },
  set(newValue) {
      console.log('set');
      value= newValue; 
    },
    enumerable: true,
    configurable: false
});
obj.prop;// 打印 get
obj.prop = 234; // 打印 set

第一個(gè)參數(shù)是要添加屬性的對象。
第二個(gè)是字符串形式的屬性名,如果屬性已存在則更新此屬性。
第三個(gè)是屬性的描述對象。
數(shù)據(jù)描述符和數(shù)據(jù)存取符不可一起使用。
defineProperty和defineProperties都有性能損耗不建議大量使用

Object.keys、Object.values、Object.entries

返回一個(gè)由一個(gè)給定對象的自身可枚舉屬性組成的數(shù)組。

  var obj = {
    a:10,
    b:20
  }
Object.defineProperty(obj, "attri", {
    value: 123,
    enumerable: false  //不可枚舉
})
console.log(Object.keys(obj));//["a","b"]

和Object.values(obj)相對應(yīng),keys返回的是屬性名數(shù)組,values返回屬性值數(shù)組。
Object.entries(obj),返回的是二維數(shù)組,數(shù)組里面是["屬性名",屬性值]

Object.getOwnPropertyNames(obj)則可以獲取到所有屬性(包括不可枚舉類型)

obj.hasOwnProperty(“prop”)

判斷對象自身屬性中是否具有指定的屬性。(不包括原型鏈上的屬性)

function F(name,age){
  this.name=name;
  this.age=age;
}
F.prototype.color = "red"
let f = new F("zou",18)
console.log(f.color);//red
console.log(f.hasOwnProperty("color"));//false

對象枚舉

for-in循環(huán) 和 hasOwnProperty

for-in用于遍歷對象的屬性

hasOwnProperty用于判斷時(shí)候?yàn)樽约旱膶傩?/p>

var obj = {
    name:"eee",
    age:100,
    height:176,
    __proto__:{
        firstName:"zpi";
    }
}
for (var i in obj){
    if(obj.hasOwnProperty(i)){
        /* obj.hasOwnProperty(i)用于判斷i這個(gè)屬性是否屬于obj,返回布爾值。如果沒有這個(gè)判斷,原型繼承的屬性也會被打印出來 */
        console.log(obj[i]);
        /*每循環(huán)一圈都會把屬性名的字符串形式賦值給i,所以不能用.來訪問對象屬性*/
    }
}

關(guān)于obj[i]訪問屬性:訪問對象的方法有兩種。一是obj.name,二是obj['name'],第一種最終還是會變成第二種的方式去執(zhí)行。

obj['name'] 中括號里面必須是字符串形式。這樣子的話我們有時(shí)候可以利用字符串拼接的方式去訪問對象。

for-of循環(huán)

循環(huán)可迭代(普通對象不可迭代)的數(shù)據(jù)。

var arr = {
    a:1,
    b:2,
    c:3
}
for(var i of arr){
    console.log(i);
}
//Uncaught TypeError: arr is not iterable

可迭代的數(shù)據(jù):數(shù)組,字符串,Map,Set,arguments(類數(shù)組),Typed Arrays,Generators。

  var arr = [
    { name:'nick', age:18 },
    { name:'freddy', age:24 },
    { name:'mike', age:26 },
    { name:'james', age:34 }
  ];

  for(var i of arr){
    console.log(i);//打印的是數(shù)組元素
  }
  for(var i in arr){
    console.log(i);//打印的是索引
  }

for-in遍歷的是索引,for-of遍歷的是值。

in操作符

用于判斷屬性時(shí)候存在于這個(gè)對象。(與hasOwnProperty不同)

var obj = {
    name:"eee",
    age:100,
    height:176,
    __proto__:{
        firstName:"zou"
    }
}
console.log('firstName' in obj);//true
console.log('lastName' in obj);//false

必須是字符串形式,如果該屬性能被obj訪問則返回true。

也就是說,再obj和obj的原型鏈上的屬性用in都返回true。

(使用的概率極低)

instanceof 操作符

文檔說:a instanceof A 用于判斷a是否為A的實(shí)例。

更準(zhǔn)確的說: a instanceof A 用于判斷a的原型鏈上是否有A。

function A(){}
function B(){}
var a = new A();
var b = new B();
console.log(a instanceof A);//a是A的實(shí)例,返回true
console.log(a instanceof B);//a不是B的實(shí)例,返回false
console.log(a instanceof Object);//a的原型鏈上有Object,返回true
console.log([] instanceof Array);//[]的原型鏈上有Array,返回true

json對象

JSON是一種傳輸數(shù)據(jù)的格式。本質(zhì)上是對象,但是用途有所區(qū)別。對象供本地使用,json用于傳輸數(shù)據(jù)。

var obj={
    age:10,
    name:"mary"
}
var a = JSON.stringify(obj);    //字符串化,對象-->字符串
var b = JSON.parse(a);          //解析,字符串-->對象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容