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去找*/
原型鏈

原型鏈上的屬性增刪改查:增刪改都需要是本身屬性的增刪改,兒子不能增刪改父親的,父親可以增刪改自己的。
對象都有原型,絕大多數(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í)例化。

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)了繼承。

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.defineProperty和Object.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); //解析,字符串-->對象