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

繼承的實(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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

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