1. 創(chuàng)建對象的方式
- 對象字面量
var obj = {
name: 'qiqi',
age: 25
}
- 通過Object構造器創(chuàng)建對象
var obj = new Object();
obj.name = 'qi';
以上兩種方法缺點: 每創(chuàng)建一個對象蝎毡,都要重新聲明一次袜刷。產(chǎn)生大量重復代碼颁股。
- 通過工廠模式創(chuàng)建對象
function Person(name){
var o = new Object();
o.name = name;
return o;
}
var person1 = Person('aaa');
缺點:當創(chuàng)建多個相似對象時星著,無法識別是由那個對象創(chuàng)建的特笋。
- 通過構造函數(shù)創(chuàng)建對象
function Person(name, age) {
this.name = name;
this.age = age;
this.read = function(){
console.log('read');
}
}
var person1 = new Person('qiqi', 25)
-
new
操作符執(zhí)行的事情- 創(chuàng)建一個新對象
- 構造函數(shù)作用域指向新對象(this指向新對象,該新對象的原型指向構造函數(shù)的prototype屬性)
- 執(zhí)行構造函數(shù)代碼(為新對象設置屬性)
- 返回新對象(若構造函數(shù)返回新對象則為該對象,若返回為空拢切。返回this對象)
缺點: 當創(chuàng)建多個實例是蒂萎,每個實例都會創(chuàng)建一個read函數(shù)
- 通過原型創(chuàng)建對象
function Person() {}
Person.prototype.z = 3;
var person1 = new Person();
person1.x = 10;
原型鏈.png
- 理解原型與原型鏈
- 創(chuàng)建一個Person函數(shù)對象
- Person函數(shù)對象默認帶一個
prototype
屬性,指向一個對象淮椰,該對象是Person的原型對象 (箭頭3) - 每個原型對象都有一個
constructor
屬性五慈,指向prototype
屬性所在函數(shù)(如:Person
) (箭頭4) - 通過
new
關鍵字構造一個person1
實例 (箭頭1) - 每個實例
person1
都有一個constructor
屬性,指向構造這個實例的構造器Person
(箭頭2) - 每個實例(如:
person1
)內部有一個指針__proto__
指向構造函數(shù)的原型對象 (箭頭5) - 訪問一個實例的屬性和方法主穗,現(xiàn)在實例本身中找泻拦,沒有找到就在
__proto__
指針指向的原型對象上找。這就是原型鏈(紅色箭頭) - 每個對象都是
Object()
實例忽媒,都繼承了Object.prototype
上的屬性和方法(例如:tostring
) -
Object.prototype
指向null
,訪問對象屬性時争拐,沿著原型鏈一直向上查找,直到null
-
in
判斷屬性是否在對象的原型鏈上晦雨,hasOwnProperty
判斷該對象本身是否有該屬性架曹。 -
propertyIsEnumerable
屬性能否被枚舉 -
delete
操作隘冲,只能刪除對象本身的屬性,不能刪除原型鏈上的屬性
- 總結:通過
new
關鍵字創(chuàng)建的對象绑雄,可以繼承原型鏈上的屬性展辞,又不會修改原型鏈上的屬性
function Person() {} //創(chuàng)建一個Person函數(shù)對象
Person.prototype.z = 3;
Person.prototype.list = ['a', 'b']; //一個實例對list操作后,另一個實例也跟著改變
var person1 = new Person();
person1.x = 1;
'z' in person1 //true
person1.hasOwnProperty('z') //false
person1.hasOwnProperty('x') //true
person1.propertyIsEnumerable('x') //true
person1.propertyIsEnumerable('toString') //false
person1.z = 5
person1.hasOwnProperty('x') //true
delete person1.z
person1.hasOwnProperty('z') //false
Person.prototype.z //3
console.log(person1.z) //3 原型對象屬性
console.log(typeof person1.toString) // function
person1.constructor //Person
Person.prototype.constructor //Person
Person.prototype === person1.__proto__ //true
var a = {}
a.__proto__ === Object.prototype //true
//Person.prototype = {name: 'a'} 與 Person.prototype.name = 'a' 的區(qū)別
//Person.prototype = {name: 'a'}
Person.prototype.constructor === Person //true
//Person.prototype = {name: 'a'}, {}是Object的實例绳慎,{}.constructor指向Object
Person.prototype.constructor === Object //true
Person.prototype = {
constructor: 'Person'
name: 'a'
}
缺點: 當一個實例對原型對象上的屬性操作后(比如: list),另一個實例也跟著改變漠烧。
- 構造函數(shù)定義屬性與原型對象定義方法相結合(應用廣泛)
function Person(name) {
this.name = name;
}
Person.prototype = {
constructor: Person,
aFun: function() {
console.log('ddd')
}
}
var person1 = new Person('q');
- 通過
Object.create
創(chuàng)建對象
var obj = Object.create({x: 1})
obj.x //1
obj.hasOwnProperty('x') //false
Object.create
是Object
內置的方法杏愤,接受一個對象參數(shù)。生成一個新對象已脓,并且新對象的原型指向參數(shù)對象珊楼。
2.
-
Object.keys(對象)
獲取對象上的屬性, 不返回屬性特性enumerable: false
的
var o = {a: 1, b:2}
Object.keys(o) //["a", "b"]