OOP

一、對象

1.三類JavaScript對象和兩類屬性的區(qū)分

  • 內(nèi)置對象:如數(shù)組、函數(shù)、日期和正則表達(dá)式。
  • 宿主對象:由JavaScript解釋器所嵌入的宿主環(huán)境(如web瀏覽器)
    定義??梢援?dāng)成內(nèi)置對象。
  • 自定義對象:由運(yùn)行中的代碼創(chuàng)建的對象。
  • 自有屬性:直接在對象中定義的屬性。
  • 繼承屬性:在對象的原型對象中定義的屬性。

2.創(chuàng)建對象

//對象直接量
var book={
  "title": "js";
  "author": "viaphlyn";
}
//new 
//內(nèi)置構(gòu)造函數(shù)
var o=new Object();//創(chuàng)建一個空對象,和{ }一樣
var a=new Array();//創(chuàng)建一個空數(shù)組,[ ]
//自定義構(gòu)造函數(shù)
var Vehicle = function () {
  this.price = 1000;
};

var v = new Vehicle();
v.price // 1000

二、new

執(zhí)行構(gòu)造函數(shù)(后面的括號可有可無。可接受參數(shù)),返回一個實(shí)例對象

1.原理

  • 創(chuàng)建一個空對象,作為將要返回的對象實(shí)例
  • 將這個空對象的原型,指向構(gòu)造函數(shù)的prototype屬性
  • 將這個空對象賦值給函數(shù)內(nèi)部的this關(guān)鍵字
  • 開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼

2.

  • 不使用new命令,直接調(diào)用構(gòu)造函數(shù)會使構(gòu)造函數(shù)就變成了普通函數(shù),并不會生成實(shí)例對象。this這時代表全局對象。
    (可使用嚴(yán)格模式,即第一行加上use strict避免)
  • 函數(shù)內(nèi)部可以使用new.target屬性。如果當(dāng)前函數(shù)是new命令調(diào)用,new.target指向當(dāng)前函數(shù),否則為undefined

三、object對象和繼承

  • Object.getOwnPropertyNames
    返回一個數(shù)組,成員是對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。
Object.getOwnPropertyNames(Date)
//Array [ "UTC", "parse", "now", "prototype", "length", "name" ]
  • Object.keys
    只獲取那些可以枚舉的屬性
  • Object.prototype.hasOwnProperty()
    返回一個布爾值,判斷某個屬性定義在對象自身,還是定義在原型鏈上。
    唯一一個處理對象屬性時,不會遍歷原型鏈的方法。
  • in運(yùn)算符
    返回一個布爾值,表示一個對象是否具有某個屬性。不區(qū)分該屬性是對象自身的屬性,還是繼承的屬性。
  • for...in循環(huán)
    獲得對象的所有可枚舉屬性(不管是自身的還是繼承的)

四、Javascript面向?qū)ο箢惡皖惖睦^承怎么實(shí)現(xiàn)

每個函數(shù)(function)本身就是一個構(gòu)造函數(shù)(constructor),就是一個類。
同一個構(gòu)造函數(shù)的多個實(shí)例之間,無法共享屬性,從而造成對系統(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.最簡單直接的方式: 屬性拷貝;雖然實(shí)現(xiàn)了原型屬性的繼承,但有一個非常明顯的缺陷:子類實(shí)例無法通過父類的 instanceof 驗證,即子類的實(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對象

  • 所有對象=>......=>Object.prototype=>null
  • 讀取對象的某個屬性時。沿著“原型鏈”去找,如果直到最頂層的Object.prototype還是找不到,則返回undefined。
  • prototype對象有一個constructor屬性,默認(rèn)指向prototype對象所在的構(gòu)造函數(shù)??梢员凰袑?shí)例對象繼承。
    可用來分辨原型對象到底屬于哪個構(gòu)造函數(shù)
function F() {};
var f = new F();

f.constructor === F // true
f.constructor === RegExp // false

可以從實(shí)例新建另一個實(shí)例。

function Constr() {}
var x = new Constr();

var y = new x.constructor();
y instanceof Constr // true

constructor屬性表示原型對象與構(gòu)造函數(shù)之間的關(guān)聯(lián)關(guān)系,如果修改了原型對象,一般會同時修改constructor屬性,防止引用的時候出錯。

  • instanceof運(yùn)算符
    返回一個布爾值,表示某個對象是否為指定的構(gòu)造函數(shù)的實(shí)例。
v instanceof Vehicle
// 等同于
Vehicle.prototype.isPrototypeOf(v)

可以巧妙地解決,調(diào)用構(gòu)造函數(shù)時,忘了加new命令的問題。

function Fubar (foo, bar) {
  if (this instanceof Fubar) {
    this._foo = foo;
    this._bar = bar;
  }
  else {
    return new Fubar(foo, bar);
  }
}
  • Object.getPrototypeOf
    返回一個對象的原型。這是獲取原型對象的標(biāo)準(zhǔn)方法。

  • Object.setPrototypeOf
    為現(xiàn)有對象設(shè)置原型,返回一個新對象。
    接受兩個參數(shù),第一個是現(xiàn)有對象,第二個是原型對象。

  • Object.prototype.isPrototypeOf()
    判斷一個對象是否是另一個對象的原型

  • Object.prototype.__ proto__
    指向當(dāng)前對象的原型對象,即構(gòu)造函數(shù)的prototype屬性??梢愿膶懩硞€對象的原型對象
    __ proto__屬性只有瀏覽器才需要部署,其他環(huán)境可以沒有這個屬性,而且前后的兩根下劃線,表示它本質(zhì)是一個內(nèi)部屬性,不應(yīng)該對使用者暴露。因此,應(yīng)該盡量少用這個屬性,而是用Object.getPrototypeof()(讀取)和Object.setPrototypeOf()(設(shè)置),進(jìn)行原型對象的讀寫操作。
    原型鏈可以用__ proto__很直觀地表示。

  • 獲取實(shí)例對象obj的原型對象,有三種方法。

    • obj.__ proto__
    • obj.constructor.prototype//在手動改變原型對象時,可能會失效。
    • Object.getPrototypeOf(obj)//推薦
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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