05_JS面向?qū)ο?/h1>

繼承的實(shí)現(xiàn)方式

在前面缰贝,我們的結(jié)論就是可以通過繼承來讓一個(gè)對象可以使用另一個(gè)對象的屬性和方法,那怎么實(shí)現(xiàn)繼承呢蠢古?

  • 最簡單的繼承實(shí)現(xiàn)
    混入式繼承
<script type="text/javascript">
    var obj = {
        name:"布萊德皮特",
        age:12,
        sayHello: function () {
            console.log("Hello World");

        }
    }
    var o = {};

    //混入式繼承
    for(var k in obj){
        o[k] = obj[k];
    }

    console.log(o);
</script>
  • 原型繼承
<script type="text/javascript">
    //原型繼承
    //利用原型中的成員可以被其他相關(guān)的對象共享這一特性玩焰,可以實(shí)現(xiàn)繼承
    //這種實(shí)現(xiàn)繼承的方式,就叫做原型繼承

    //  1募疮,給原型對象中添加成員(通過對象的動態(tài)特性) 不是嚴(yán)格意義上的繼承
    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.sayHello = function () {
        console.log("Hi,nihao");
    }
    var p = new Person("迪麗熱巴",24);
    p.sayHello();
    //此方式屬于對象繼承了原型對象
</script>
  • 直接替換原型對象的方式繼承
<script type="text/javascript">
    //  2炫惩,直接替換原型對象
    function Son(name, age){
        this.name = name;
        this.age = age;
    }
    var parent = {
        sayHello: function () {
            console.log("Hi,Wife");
        }
    }
    Son.prototype = parent;
    var s = new Son("蠟筆小新",12);//一定要在設(shè)置原型后面
    console.log(Son.prototype);
    s.sayHello();
    //s對象繼承了原型對象(parent對象)
</script>

注意:使用體會原型的方式實(shí)現(xiàn)繼承的時(shí)候,原有的原型中的成員會消失

  • 利用混入的方式給原型對象添加成員
<script type="text/javascript">
    //  3阿浓,利用混入的方式給原型對象添加成員
    function Son(name, age){
        this.name = name;
        this.age = age;
    }
    var s = new Son("蠟筆小新",12);//可以在設(shè)置原型之前
    var parent = {
        sayWife: function () {
            console.log("Hi,My Wife!");
        }
    }
    for(var k in parent){
        Son.prototype[k] = parent[k];
    }
    s.sayWife();
</script>
  • 經(jīng)典繼承方式的實(shí)現(xiàn)
<script type="text/javascript">
    //《JavaScript語言精粹》作者提出了一個(gè)方式來實(shí)現(xiàn)繼承
    function inherit(obj){
        var o = {};
        o.__proto__ = obj;
        return o;
    }
    var o = inherit({name:"張三"});
    console.log(o);

    //經(jīng)典繼承的語法
    //Object.create(obj)
    //返回值為一個(gè)對象他嚷,繼承自參數(shù)中的obj
    //這個(gè)方法是ES5中出來的,所以存在兼容性問題
//    var o = {
//        name:"李四"
//    }
//    var obj = Object.create(o);
//    console.log(obj);

    //如何處理Object.create的兼容性問題
    var o = {
        name:"李四"
    }
    //檢測瀏覽器的能力芭毙,如果沒有Object.create方法就給他添加一個(gè)(不推薦使用)
    if(Object.create){
        var obj= Object.create(o)
    }else{
        Object.create = function (o) {
            function F(){}
            F.prototype = o;
            var obj = new F;
            return obj;
        }
        var obj = Object.create()
    }

    var o1 = Object.create(o);
    console.log(o1);

    //自己定義個(gè)函數(shù)
    function create(obj){
        if(Object.create){
            return Object.create(obj)
        }else{
            Object.create = function (obj) {
                function F(){}
                F.prototype = obj;
                return new F;;
            }
        }
    }
    var o = {
        age:12,
    }
    var obj = create(o);
    console.log(obj);
</script>

原型繼承

每一個(gè)構(gòu)造函數(shù)都有prototype原型屬性筋蓖,通過構(gòu)造函數(shù)創(chuàng)建出來的對象都繼承自該原型屬性。所以可以通過更改構(gòu)造函數(shù)的原型屬性來實(shí)現(xiàn)繼承退敦。

function Dog(){
    this.type = "yellow Dog";
}

function extend(obj1, obj2){
    for (var k in obj2){
        obj1[k] = obj2[k];    
    }
};

//使用混入的方式粘咖,將屬性和方法添加到構(gòu)造函數(shù)的原型屬性上,構(gòu)造函數(shù)所創(chuàng)建出來的實(shí)例就都有了這些屬性和方法侈百。
extend(Dog.prototype, {
    name:"",
    age:"",
    sex:"",
    bark:function(){}

})

//使用面向?qū)ο蟮乃枷氚裡xtend方法重新封裝
//extend是擴(kuò)展的意思瓮下,誰要擴(kuò)展就主動調(diào)用extend這個(gè)方法
//所以extend應(yīng)該是對象的方法,那現(xiàn)在我們要擴(kuò)展的是構(gòu)造函數(shù)的原型對象
//所以給構(gòu)造函數(shù)的原型對象添加一個(gè)extend方法

//如下:

Dog.prototype.extend = function(obj){
    for (var k in obj){
        this[k]=obj[k];
    }
}

//調(diào)用方式就變成了下面這種形式

Dog.prototype.extend({
    name:"",
    age:"",
    sex:"",
    bark:function(){}
});

繼承的應(yīng)用


<script type="text/javascript">
    var arr = [1,2,5,3,8,1];
    //給數(shù)組添加一個(gè)sayHello方法
    Array.prototype.sayHello = function () {
        console.log("您好,我告訴你數(shù)組的長度是:"+this.length);
    }
    arr.sayHello();
    //但是這樣屬于擴(kuò)展內(nèi)置對象钝域,就是給內(nèi)置對象新增成員

    //在多人開發(fā)時(shí)讽坏,大家都擴(kuò)展內(nèi)置對象,如果名稱一樣會有問題
    //內(nèi)置對象中原來有的成員例证,可能會被替換路呜,那內(nèi)置對象的功能會喪失
    //在ECMScript升級時(shí),擴(kuò)展內(nèi)置對象的新增成員可能有被覆蓋的危險(xiǎn)
    //所以在項(xiàng)目中應(yīng)避免擴(kuò)展內(nèi)置對象

    //避免擴(kuò)展內(nèi)置對象战虏,使用繼承的方式
    function MArray(){

    }
    var arr = new Array();
    MArray.prototype = arr;
    //mArr這個(gè)對象就繼承自arr
    var mArr = new MArray();
    mArr.push(1);
    mArr.push(2,3,4,5);
    console.log(mArr);//打蛹鹪住:(5) [1, 2, 3, 4, 5]
</script>

屬性搜索原則

訪問一個(gè)對象的成員的時(shí)候,首先是在實(shí)例中找烦感,沒有找到, 就去原型中找, 但是原型中沒有怎么辦?

屬性搜索原則

所謂的屬性搜索原則巡社,也就是屬性的查找順序,在訪問對象的成員的時(shí)候手趣,會遵循如下的原則:

  • 首先在當(dāng)前對象中查找晌该,如果找到肥荔,停止查找,直接使用朝群,如果沒有找到燕耿,繼續(xù)下一步
  • 在該對象的原型中查找,如果找到姜胖,停止查找誉帅,直接使用,如果沒有找到右莱,繼續(xù)下一步
  • 在該對象的原型的原型中查找蚜锨,如果找到,停止查找慢蜓,直接使用亚再,如果沒有找到,繼續(xù)下一步晨抡。
  • 繼續(xù)往上查找氛悬,直到查找到Object.prototype還沒有, 那么是屬性就返回 undefied,是方法耘柱,就報(bào)錯(cuò)xxx is not a function如捅。

原型鏈

每一個(gè)對象都有原型屬性,那么對象的原型屬性也會有原型屬性调煎,所以這樣就形成了一個(gè)鏈?zhǔn)浇Y(jié)構(gòu)伪朽,我們稱之為原型鏈。

原型鏈結(jié)構(gòu)

凡是對象就有原型, 原型又是對象, 因此凡是給定義一個(gè)對象, 那么就可以找到他的原型, 原型還有原型. 那么如此下去, 就構(gòu)成一個(gè)對象的序列. 稱該結(jié)構(gòu)為原型鏈.
  使用構(gòu)造函數(shù)創(chuàng)建出對象, 并且沒有利用賦值的方式修改原型, 就說該對象保留默認(rèn)的原型鏈.
  默認(rèn)原型鏈結(jié)構(gòu)是什么樣子呢?

function Person() {
}

var p = new Person();
// p 具有默認(rèn)的原型鏈

默認(rèn)的原型鏈結(jié)構(gòu)就是:當(dāng)前對象 -> 構(gòu)造函數(shù).prototype -> Object.prototype -> null
在實(shí)現(xiàn)繼承的時(shí)候, 有時(shí)會利用替換原型鏈結(jié)構(gòu)的方式實(shí)現(xiàn)原型繼承, 那么原型鏈結(jié)構(gòu)就會發(fā)生改變

<script type="text/javascript">
    //1汛蝙,什么是原型鏈
    //  每個(gè)構(gòu)造函數(shù)都有原型對象
    //  每個(gè)對象都有構(gòu)造函數(shù)
    //  每個(gè)構(gòu)造函數(shù)的原型對象都是一個(gè)對象
    //  那么這個(gè)原型對象也會有構(gòu)造函數(shù)
    //  那么這個(gè)原型對象的構(gòu)造函數(shù)也會有原型對象
    //  這樣就會形成一個(gè)鏈?zhǔn)降慕Y(jié)構(gòu),稱為原型鏈
    function Person(){

    }
    var p = new Person();
    //p的原型是一個(gè)Object對象
    console.log(p.__proto__);
//    p---->Person.prototype ----> Object.prototype ----> null
    //屬性的搜索規(guī)則
    //  1.當(dāng)訪問一個(gè)對象的成員的時(shí)候朴肺,會現(xiàn)在自身找有沒有,如果找到直接使用窖剑,
    //  2.如果沒有找到,則去當(dāng)前對象的原型對象中去查找戈稿,如果找到了直接使用西土,
    //  3.如果沒有找到,繼續(xù)找原型對象的原型對象鞍盗,如果找到了需了,直接使用
    //  4.如果沒有找到,則繼續(xù)向上查找般甲,直到Object.prototype肋乍,如果還是沒有,就報(bào)錯(cuò)

    //原型繼承
    //通過修改原型鏈結(jié)構(gòu)實(shí)現(xiàn)的繼承敷存,就叫做原型繼承
</script>

復(fù)雜的原型鏈

<script type="text/javascript">
    function Animal(){
        this.age = 8;
    }
    Human.prototype = new Animal;
    Human.prototype.constructor = Human;
    function Human(){
        this.name = "楊迪";
    }
    Teacher.prototype = new Human;
    Teacher.prototype.constructor = Teacher;
    function Teacher(){
        this.work = "教書";
    }
    BadTeacher.prototype = new Teacher;
    BadTeacher.prototype.constructor = BadTeacher;
    function BadTeacher(){
        this.teaching = "打人";
    }

    var bt = new BadTeacher;
//    console.log(bt);
    //Teacher {work: "教書", constructor: function}
    console.log(bt.__proto__);
    //Human {name: "楊迪", constructor: function}
    console.log(bt.__proto__.__proto__);
    //Animal {age: 8, constructor: function}
    console.log(bt.__proto__.__proto__.__proto__);
    //Object {constructor: function}
    console.log(bt.__proto__.__proto__.__proto__.__proto__);
    //Object {__defineGetter__: function, __defineSetter__: function, hasOwnProperty: function, __lookupGetter__: function, __lookupSetter__: function…}
    console.log(bt.__proto__.__proto__.__proto__.__proto__.__proto__);
    //null
    console.log(bt.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);

    var arr = [];
    console.log(arr);
    //[constructor: function, toString: function, toLocaleString: function, join: function, pop: function…]
    console.log(arr.__proto__);
</script>

Object.prototype的成員

  • constructor
  • hasOwnProperty
  • propertyIsEnumerable
  • Object.defineProperty();
  • toString 和 toLocaleString
  • valueOf
  • __proto__
<script type="text/javascript">
    //1.constructor
    //原型對象內(nèi)的一個(gè)屬性墓造,指向該原型對象相關(guān)聯(lián)的構(gòu)造函數(shù)

    //2.hasOwnProperty
    //一個(gè)方法,用來判斷對象本身(不包含原型)是否擁有某個(gè)屬性
    function People(){
        this.name = "王久";
    }
    People.prototype.name = "張三";

    var pp = new People();
    console.log(pp.name);
    console.log(pp.hasOwnProperty("name"));//true
    console.log(pp.hasOwnProperty("__proto__"));//false

    //3.propertyIsEnumerable
    //    1. 判斷屬性是否屬于對象本身
    //    2. 判斷屬性是否可以被遍歷
    console.log(pp.propertyIsEnumerable("name"));//true

    //  Object.defineProperty();
    // 使用以上方法添加屬性的時(shí)候,可以附加一些信息觅闽,
    // 例如這個(gè)屬性是否可寫 可讀  可遍歷

    //4.toString 和  toLocaleString
    var o = {};
    console.log(o.toString());//[object Object]
    console.log(o.toLocaleString());//[object Object]

    var now = new Date();
    console.log(now.toString());//Wed Jul 19 2017 23:57:53 GMT+0800 (China Standard Time)
    console.log(now.toLocaleString());//2017/7/19 下午11:57:53


    function Person(){}
    var p = new Person();
    console.log(1+p);//1[object Object]
    //5.valueOf
    function Person1(){
        this.valueOf = function () {
            return 123;
        }
    }
    var p1 = new Person1();
    console.log(1 + p1);//124

    //在對象參與運(yùn)算的時(shí)候
    //  1.默認(rèn)的會先去調(diào)用對象的valueOf方法帝雇,
    //  2.如果valueOf獲取到的值,無法進(jìn)行運(yùn)算 蛉拙,就去去調(diào)用p的toString方法  最終做的就是字符串拼接的工作

    //6. __proto__
    //原型對象對象中的屬性
    //可以使用 對象.__proto__ 去訪問原型對象
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末尸闸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子孕锄,更是在濱河造成了極大的恐慌吮廉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硫惕,死亡現(xiàn)場離奇詭異茧痕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)恼除,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門踪旷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豁辉,你說我怎么就攤上這事令野。” “怎么了徽级?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵气破,是天一觀的道長。 經(jīng)常有香客問我餐抢,道長现使,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任旷痕,我火速辦了婚禮碳锈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘欺抗。我一直安慰自己售碳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布绞呈。 她就那樣靜靜地躺著贸人,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佃声。 梳的紋絲不亂的頭發(fā)上艺智,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音秉溉,去河邊找鬼力惯。 笑死碗誉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的父晶。 我是一名探鬼主播哮缺,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼甲喝!你這毒婦竟也來了尝苇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤埠胖,失蹤者是張志新(化名)和其女友劉穎糠溜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體直撤,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡非竿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谋竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片红柱。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蓖乘,靈堂內(nèi)的尸體忽然破棺而出锤悄,到底是詐尸還是另有隱情,我是刑警寧澤嘉抒,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布零聚,位于F島的核電站,受9級特大地震影響些侍,放射性物質(zhì)發(fā)生泄漏隶症。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一岗宣、第九天 我趴在偏房一處隱蔽的房頂上張望沿腰。 院中可真熱鬧,春花似錦狈定、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至躲叼,卻和暖如春芦缰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背枫慷。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工让蕾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浪规,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓探孝,卻偏偏與公主長得像笋婿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子顿颅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 博客內(nèi)容:什么是面向?qū)ο鬄槭裁匆嫦驅(qū)ο竺嫦驅(qū)ο缶幊痰奶匦院驮瓌t理解對象屬性創(chuàng)建對象繼承 什么是面向?qū)ο?面向?qū)ο?..
    _Dot912閱讀 1,424評論 3 12
  • 本章內(nèi)容 理解對象屬性 理解并創(chuàng)建對象 理解繼承 面向?qū)ο笳Z言有一個(gè)標(biāo)志缸濒,那就是它們都有類的概念,而通過類可以創(chuàng)建...
    悶油瓶小張閱讀 851評論 0 1
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持粱腻,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券庇配,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,998評論 4 14
  • 今天一早,斷舍離充斥在我的朋友圈柬批,就因?yàn)樽蛲砑尤肓艘粋€(gè)微信群啸澡,這個(gè)群是為了聽收納課而建立的,大家為了收納走在一起了...
    蘭花子閱讀 160評論 0 0
  • 野豬和馬一起吃草,野豬時(shí)常使壞揪漩,不是踐踏青草旋恼,就是把水?dāng)嚋啞qR十分惱怒奄容,一心想要報(bào)復(fù)冰更,便去請獵人幫忙。獵人說除非馬...
    中炯閱讀 1,222評論 0 1