js中的對(duì)象,構(gòu)造函數(shù),原型,原型鏈,繼承

對(duì)象

創(chuàng)建對(duì)象

  • 方式1-字面量表示,推薦使用
var a = {};
  • 方式2-調(diào)用構(gòu)造函數(shù),不推薦使用
var obj = new Object();
//Object是所有對(duì)象的基礎(chǔ)
  • 方式3 ,自定義方法,形式和函數(shù)一樣,為了區(qū)分,構(gòu)造函數(shù)命名嚴(yán)格按照大駝峰形式(所有單詞首字母大寫)
function Person(){}
var person = new Person();

Object的所有實(shí)例都有下列屬性和方法,因此所有的對(duì)象都有這些屬性和方法

  • constructor
  • hasOwnProperty(propertyName)
    --->propertyName必須為字符串類型
  • propertyIsEnunerable(propertyName)
    --->propertyName必須為字符串類型
  • isPrototypeOf(object)
  • toString()
  • valueOf()
  • toLocaleString()

使用構(gòu)造函數(shù)創(chuàng)建對(duì)象模式

    function Person(name,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.sayName=function(){
            console.log(this.name);
        };
    }
    var person1 = new Person('xiaoli',29,'doctor');
    var person1 = new Person('xiaozhang',38,'teacher');
    console.log(person1.constructor ==Person);//true
    console.log(person2.constructor ==Person);//true

構(gòu)造函數(shù)原理

構(gòu)造函數(shù)和普通函數(shù)的唯一區(qū)別就是名字要首字母大寫和要用new實(shí)例化
要?jiǎng)?chuàng)建Person的實(shí)例,必須使用new,以這種方式調(diào)用構(gòu)造函數(shù)實(shí)際上會(huì)經(jīng)歷4個(gè)階段

  • 創(chuàng)建一個(gè)新對(duì)象
  • 新對(duì)象名字叫this(構(gòu)造函數(shù)的作用域賦予新對(duì)象)
  • 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)this.xxx=xxx;
  • 返回新對(duì)象 return this
構(gòu)造函數(shù)的注意點(diǎn)
  • 不同實(shí)例的同名函數(shù)是不相等的。
  • 所以創(chuàng)建兩個(gè)完成同樣任務(wù)的Function實(shí)例沒有必要,況且由this對(duì)象在,根本不用再執(zhí)行代碼前就把函數(shù)綁定在特定對(duì)象上
  • 把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部來解決這個(gè)問題
    function Person(name,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.sayName=sayName;
    }
    function sayName(){
            console.log(this.name);
        }
    var person1 = new Person('xiaoli',29,'doctor');
    var person1 = new Person('xiaozhang',38,'teacher');
但是這樣又有新的問題。
  • 在全局作用域中定義的sayName只能被某個(gè)函數(shù)調(diào)用,
  • 如果需要定義很多方法,那就要定義很多全局函數(shù),沒有封裝性
  • 通過原型模式來解決

原型模式

我們創(chuàng)建的每一個(gè)函數(shù)都有prototype屬性,prototype也是對(duì)象,是構(gòu)造函數(shù)制造出來的對(duì)象的公共祖先,創(chuàng)造出來的原型可以繼承原型里面的屬性和方法

  • JavaScript 的所有對(duì)象中都包含了一個(gè) __proto__ 內(nèi)部屬性,這個(gè)屬性所對(duì)應(yīng)的就是該對(duì)象的原型
  • JavaScript 的函數(shù)對(duì)象,除了原型 __proto__ 之外,還預(yù)置了 prototype 屬性
  • 當(dāng)函數(shù)對(duì)象作為構(gòu)造函數(shù)創(chuàng)建實(shí)例時(shí),該 prototype 屬性值將被作為實(shí)例對(duì)象的原型 __proto__

  • prototype是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例,的原型對(duì)象

不必再構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是將信息直接添加到原型對(duì)象中

function Person(){}
Person.prototype.name="lia";
Person.prototype.age=19;
Person.prototype.sayName=function(){
    console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.sayName();
person2.sayName();
理解原型對(duì)象
  • 無論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)為該函數(shù)創(chuàng)建一個(gè)prototype屬性。這個(gè)屬性指向函數(shù)的原型對(duì)象
  • 在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性是一個(gè)指向prototype屬性所在函數(shù)的指針,

Person.prototype.constructor指向Person

  • 創(chuàng)建一個(gè)自定義的構(gòu)造函數(shù)后,其原型對(duì)象只會(huì)默認(rèn)取得constructor屬性,至于其他方法,都是從Object繼承來的
  • 構(gòu)造函數(shù)初始化時(shí),新建的this空對(duì)象其實(shí)不是空的,里面自帶一條__proto__:Person.prototype,用來指引實(shí)例函數(shù)尋找他的原型
  • 在調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針,指向該構(gòu)造函數(shù)的原型對(duì)象。es5管這個(gè)指針叫[[prototype]]
  • 腳本中沒有標(biāo)準(zhǔn)的方法訪問[[prototype]],但Firefox,safari和chrome在每個(gè)對(duì)象上都支持一個(gè)屬性proto,而在其他實(shí)現(xiàn)中,這個(gè)屬性對(duì)腳本則是完全不可見的。
  • 這個(gè)鏈接存在于 實(shí)例函數(shù) 和 構(gòu)造函數(shù)的原型對(duì)象 之間,而不是存在于實(shí)例和構(gòu)造函數(shù)之間
  • 函數(shù)才有prototype,實(shí)例對(duì)象只有有proto, 而函數(shù)有的proto是因?yàn)楹瘮?shù)是Function的實(shí)例對(duì)象
以以上 Person構(gòu)造函數(shù)為例
  • Person.prototype指向了原型對(duì)象,而Person.prototype.cunstructor又指向了Person,

其他注意點(diǎn)

  • 當(dāng)為對(duì)象實(shí)例添加一個(gè)屬性是,這個(gè)屬性會(huì) <em>屏蔽</em> 原型對(duì)象中保存的同名屬性。(添加這個(gè)同名屬性只會(huì)阻止我們?cè)L問原型對(duì)象中的那個(gè)屬性,而不會(huì)修改那個(gè)屬性。)。即使這個(gè)屬性為null
  • 但是,使用delete操作符可以完全刪除實(shí)例屬性,從而可以可以重新訪問原型中的屬性

原型鏈-使用proto連接

任意一個(gè)函數(shù)(包括構(gòu)造函數(shù))都有一個(gè)prototype屬性,指向該函數(shù)的原型對(duì)象,同樣任意一個(gè)構(gòu)造函數(shù)實(shí)例化的對(duì)象,都有一個(gè)proto屬性

Grande.prototype.lastname="你爺爺";
function Grande(){}
var grande = new Grande();

Father.prototype=grande;
function Father (){}
var father = new Father();

Son.prototype=father;
function Son (){}
var son = new Son();
console.log(son.lastname);//你爺爺

Grande.prototype.proto--->Object.prototype

  • 絕大多數(shù)對(duì)象的最終,都會(huì)繼承自O(shè)bject.protype

var obj = Object.create(null)
這樣就沒有原型了,因?yàn)閚ull和undefined沒有toString方法

  • 重寫toString方法
            Number.prototype.toString=function(){
                return "你要返回的東西";
            }

方法

isPrototypeOf()

console.log(Person.prototype.isPrototypeOf(person1));//true
console.log(Person.prototype.isPrototypeOf(person2));//true
//因?yàn)镻erson1和Person2內(nèi)部都有一個(gè)指向Person的指針,所以返回true

Object.getPrototypeOf

返回這個(gè)對(duì)象的原型

hasOwnPrototype()

一個(gè)屬性是存在實(shí)例中,而不是存在于原型對(duì)象中,返回ture,繼承自O(shè)bject
使用for-in循環(huán)是,會(huì)循環(huán)實(shí)例和原型對(duì)象里面的屬性,

確認(rèn)屬性是原型中的屬性

function hasPrototypeProperty(object,name){
    return (name in object) && !object.hasOwnPrototype(name);
}
//左邊的卡確認(rèn)是實(shí)例或者原型的屬性,左邊返回ture后,右邊的如果是原型里面的屬性,則整體返回true

proto和prototype的聯(lián)系和區(qū)別

function a() {
    //console.log("I'am a function.");
}
//b是實(shí)例化對(duì)象,a是構(gòu)造函數(shù)
 var b = new a();
 console.log(b.__proto__ == a.prototype); //true
 //一個(gè)對(duì)象的隱式原型指向構(gòu)造該對(duì)象的構(gòu)造函數(shù)的原型,這也保證了實(shí)例能夠訪問在構(gòu)造函數(shù)原型中定義的屬性和方法。
console.log(Object.getPrototypeOf(b) == a.prototype); //true


區(qū)別:

  • 區(qū)別:prototype是構(gòu)造函數(shù)訪問原型對(duì)象,proto是對(duì)象實(shí)例訪問原型對(duì)象。
  • proto是每個(gè)對(duì)象都有的一個(gè)屬性,而prototype是函數(shù)才會(huì)有的屬性!!!
  • 使用Object.getPrototypeOf()代替proto

注意: 函數(shù)才有prototype,實(shí)例對(duì)象只有有proto, 而函數(shù)有的proto是因?yàn)楹瘮?shù)是Function的實(shí)例對(duì)象

繼承

借用構(gòu)造函數(shù)法

在構(gòu)造函數(shù)中 使用Parent.call(this)的方法繼承父類屬性。

原理: 將子類的this使用父類的構(gòu)造函數(shù)跑一遍

缺點(diǎn): Parent原型鏈上的屬性和方法并不會(huì)被子類繼承

function Parent() {
  this.name = 'parent'
}

function Child() {
  Parent.call(this);
  this.type = 'child'
}

原型鏈實(shí)現(xiàn)繼承

原理:把子類的prototype(原型對(duì)象)直接設(shè)置為父類的實(shí)例

Son.prototype=new Father();

缺點(diǎn):當(dāng)子類對(duì)象上進(jìn)行值修改時(shí),如果是修改的原始類型的值,那么會(huì)在實(shí)例上新建這樣一個(gè)值;
但如果是引用類型的話,他就會(huì)去修改子類上唯一一個(gè)父類實(shí)例里面的這個(gè)引用類型,這會(huì)影響所有子類實(shí)例

繼承圣杯模式

* 繼承圣杯模式

var inherit =(function(){
    var F = function(){};//利用閉包,實(shí)現(xiàn)變量私有化
    return function(Target,Origin){
        F.prototype = Origin.prototype;
        Target.prototype= new F();
        //通過原型鏈連接
        Targer.prototype.constructor = Target;
        Target.prototype.uber = Origin.prototype;
    }
}());

對(duì)象的遍歷

for in

var obj= {
    name:123,
    age:33,
    __proto__:{
        lastName:deng;
    }
}
for(bar i in obj){
    //為了不訪問到原型里面的方法
    if(obj.hasOwnProperty(i)){
        console,log(i+":"+obj[i]);
    }
}
//i是一個(gè)字符串,如果寫成obj.i,系統(tǒng)會(huì)轉(zhuǎn)換成obj['i'],就成屬性讀取,,所以必須要寫方括號(hào),
//如果是系統(tǒng)自帶的原型,沒程序員設(shè)置,他就不會(huì)打印出來,。要程序員自己設(shè)置的原型,才會(huì)被打印出來

object.name與object["name"]

  • 使用方括號(hào)讀取對(duì)象屬性(替代點(diǎn)方式)-比較靈活
var obj = {
    name:"xiaoli"
}
obj.name;//用這種方式訪問,會(huì)在后臺(tái)轉(zhuǎn)換成方括號(hào)模式
obj['name'];
//這兩種方式,本質(zhì)來說是一樣的,方括號(hào)比較靈活
  • 應(yīng)用
 var deng = {
     wife1:{name:"1111"},
     wife2:{name:"22222"},
     wife3:{name:"3333"},
     wife4:{name:"4444"},
     sayWife:function(num){
         console.log(deng['wife'+num]);
     }  
 }

模擬Jquery實(shí)現(xiàn)鏈?zhǔn)骄幊?/h4>
var deng = {
    smoke : function(){
       console.log("smoking...");
       return this
    },
    sayHi:function(){
        console.log("hello");
        return this;
    }
}
deng.smoke().sayHi();

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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