一涂圆、對(duì)象
1.三類JavaScript對(duì)象和兩類屬性的區(qū)分
- 內(nèi)置對(duì)象:如數(shù)組劫狠、函數(shù)廊驼、日期和正則表達(dá)式。
- 宿主對(duì)象:由JavaScript解釋器所嵌入的宿主環(huán)境(如web瀏覽器)
定義钳垮。可以當(dāng)成內(nèi)置對(duì)象把曼。 - 自定義對(duì)象:由運(yùn)行中的代碼創(chuàng)建的對(duì)象胡岔。
- 自有屬性:直接在對(duì)象中定義的屬性。
- 繼承屬性:在對(duì)象的原型對(duì)象中定義的屬性歹袁。
2.創(chuàng)建對(duì)象
//對(duì)象直接量
var book={
"title": "js";
"author": "viaphlyn";
}
//new
//內(nèi)置構(gòu)造函數(shù)
var o=new Object();//創(chuàng)建一個(gè)空對(duì)象坷衍,和{ }一樣
var a=new Array();//創(chuàng)建一個(gè)空數(shù)組,[ ]
//自定義構(gòu)造函數(shù)
var Vehicle = function () {
this.price = 1000;
};
var v = new Vehicle();
v.price // 1000
二条舔、new
執(zhí)行構(gòu)造函數(shù)(后面的括號(hào)可有可無枫耳。可接受參數(shù))孟抗,返回一個(gè)實(shí)例對(duì)象
1.原理
- 創(chuàng)建一個(gè)空對(duì)象迁杨,作為將要返回的對(duì)象實(shí)例
- 將這個(gè)空對(duì)象的原型钻心,指向構(gòu)造函數(shù)的prototype屬性
- 將這個(gè)空對(duì)象賦值給函數(shù)內(nèi)部的this關(guān)鍵字
- 開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼
2.
- 不使用new命令,直接調(diào)用構(gòu)造函數(shù)會(huì)使構(gòu)造函數(shù)就變成了普通函數(shù)铅协,并不會(huì)生成實(shí)例對(duì)象捷沸。this這時(shí)代表全局對(duì)象。
(可使用嚴(yán)格模式狐史,即第一行加上use strict避免) - 函數(shù)內(nèi)部可以使用new.target屬性痒给。如果當(dāng)前函數(shù)是new命令調(diào)用,new.target指向當(dāng)前函數(shù)骏全,否則為undefined
三苍柏、object對(duì)象和繼承
- Object.getOwnPropertyNames
返回一個(gè)數(shù)組,成員是對(duì)象本身的所有屬性的鍵名姜贡,不包含繼承的屬性鍵名序仙。
Object.getOwnPropertyNames(Date)
//Array [ "UTC", "parse", "now", "prototype", "length", "name" ]
- Object.keys
只獲取那些可以枚舉的屬性 - Object.prototype.hasOwnProperty()
返回一個(gè)布爾值,判斷某個(gè)屬性定義在對(duì)象自身鲁豪,還是定義在原型鏈上潘悼。
唯一一個(gè)處理對(duì)象屬性時(shí),不會(huì)遍歷原型鏈的方法爬橡。 - in運(yùn)算符
返回一個(gè)布爾值治唤,表示一個(gè)對(duì)象是否具有某個(gè)屬性。不區(qū)分該屬性是對(duì)象自身的屬性糙申,還是繼承的屬性宾添。 - for...in循環(huán)
獲得對(duì)象的所有可枚舉屬性(不管是自身的還是繼承的)
四、Javascript面向?qū)ο箢惡皖惖睦^承怎么實(shí)現(xiàn)
每個(gè)函數(shù)(function)本身就是一個(gè)構(gòu)造函數(shù)(constructor)柜裸,就是一個(gè)類缕陕。
同一個(gè)構(gòu)造函數(shù)的多個(gè)實(shí)例之間,無法共享屬性疙挺,從而造成對(duì)系統(tǒng)資源的浪費(fèi)扛邑。
// 構(gòu)造函數(shù)模式
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
alert("Hi, I'm " + this.name);
};
}
var zhangsan = new Person("張三", 20);
var lisi = new Person("李四", 21);
//alert(zhangsan.sayHi === lisi.sayHi); // false,問題所在
// 構(gòu)造函數(shù)+原型組合模式
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function() {
alert("Hi, I'm " + this.name);
};
var zhangsan = new Person("張三", 20);
var lisi = new Person("李四", 21);
alert(zhangsan.sayHi === lisi.sayHi); // true
2.最簡(jiǎn)單直接的方式: 屬性拷貝;雖然實(shí)現(xiàn)了原型屬性的繼承铐然,但有一個(gè)非常明顯的缺陷:子類實(shí)例無法通過父類的 instanceof 驗(yàn)證蔬崩,即子類的實(shí)例不是父類的實(shí)例。
// 拷貝繼承
function extend(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
}
extend(SubClass.prototype, SuperClass.prototype);
3.通過原型鏈來實(shí)現(xiàn)繼承:
// 原型鏈繼承
function User(name, age, password) {
// 繼承特權(quán)成員
Person.call(this, name, age);
this.password = password;
}
// 繼承原型
User.prototype = new Person();
// 修改了原型指針搀暑,需重新設(shè)置 constructor 屬性
User.prototype.constructor = User;
var zhangsan = new User("張三", 20, "123456");
zhangsan.sayHi(); // Hi, I'm 張三
五沥阳、 prototype對(duì)象
- 所有對(duì)象=>......=>Object.prototype=>null
- 讀取對(duì)象的某個(gè)屬性時(shí)。沿著“原型鏈”去找自点,如果直到最頂層的Object.prototype還是找不到桐罕,則返回undefined。
- prototype對(duì)象有一個(gè)constructor屬性,默認(rèn)指向prototype對(duì)象所在的構(gòu)造函數(shù)功炮〗η保可以被所有實(shí)例對(duì)象繼承。
可用來分辨原型對(duì)象到底屬于哪個(gè)構(gòu)造函數(shù)
function F() {};
var f = new F();
f.constructor === F // true
f.constructor === RegExp // false
可以從實(shí)例新建另一個(gè)實(shí)例死宣。
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true
constructor屬性表示原型對(duì)象與構(gòu)造函數(shù)之間的關(guān)聯(lián)關(guān)系,如果修改了原型對(duì)象碴开,一般會(huì)同時(shí)修改constructor屬性毅该,防止引用的時(shí)候出錯(cuò)。
- instanceof運(yùn)算符
返回一個(gè)布爾值潦牛,表示某個(gè)對(duì)象是否為指定的構(gòu)造函數(shù)的實(shí)例眶掌。
v instanceof Vehicle
// 等同于
Vehicle.prototype.isPrototypeOf(v)
可以巧妙地解決,調(diào)用構(gòu)造函數(shù)時(shí)巴碗,忘了加new命令的問題朴爬。
function Fubar (foo, bar) {
if (this instanceof Fubar) {
this._foo = foo;
this._bar = bar;
}
else {
return new Fubar(foo, bar);
}
}
Object.getPrototypeOf
返回一個(gè)對(duì)象的原型。這是獲取原型對(duì)象的標(biāo)準(zhǔn)方法橡淆。Object.setPrototypeOf
為現(xiàn)有對(duì)象設(shè)置原型召噩,返回一個(gè)新對(duì)象。
接受兩個(gè)參數(shù)逸爵,第一個(gè)是現(xiàn)有對(duì)象具滴,第二個(gè)是原型對(duì)象。Object.prototype.isPrototypeOf()
判斷一個(gè)對(duì)象是否是另一個(gè)對(duì)象的原型Object.prototype.__ proto__
指向當(dāng)前對(duì)象的原型對(duì)象师倔,即構(gòu)造函數(shù)的prototype屬性构韵。可以改寫某個(gè)對(duì)象的原型對(duì)象
__ proto__屬性只有瀏覽器才需要部署趋艘,其他環(huán)境可以沒有這個(gè)屬性疲恢,而且前后的兩根下劃線,表示它本質(zhì)是一個(gè)內(nèi)部屬性瓷胧,不應(yīng)該對(duì)使用者暴露显拳。因此,應(yīng)該盡量少用這個(gè)屬性搓萧,而是用Object.getPrototypeof()(讀任堋)和Object.setPrototypeOf()(設(shè)置),進(jìn)行原型對(duì)象的讀寫操作矛绘。
原型鏈可以用__ proto__很直觀地表示耍休。-
獲取實(shí)例對(duì)象obj的原型對(duì)象,有三種方法货矮。
- obj.__ proto__
- obj.constructor.prototype//在手動(dòng)改變?cè)蛯?duì)象時(shí)羊精,可能會(huì)失效。
- Object.getPrototypeOf(obj)//推薦