面向?qū)ο笾蛯ο蟮睦^承day03

JavaScript面相對象的繼承

一.in操作符與hasOwnProperty的用法和區(qū)別

in操作符:

①遍歷對象

②判斷(檢查)對象中是否存在指定的屬性(實例成員 + 原型成員)
語法:'屬性' in 對象

hasOwnProperty:

檢查對象是否擁有這個屬性(只檢查自己的成員,實例成員)

語法:對象.hasOwnProperty(屬性|方法);

    <script>
//1.創(chuàng)建一個空對象
var o = {};

//2.提供一個已經(jīng)有的對象obj
var obj = {
    name:'對象的屬性',
    age:20,
    demo:{nme:"lalala"},
    sayHello:function (){
        console.log('hello');
    }

};

//3.混入式繼承(把原有對象的所有屬性和方法都拷貝給新的對象)
for (var k in obj){
    if(obj.hasOwnProperty(k)) {
        o[k] = obj[k];
    }
}

//注意:利用for...in賦值和直接賦值不一樣,for...in賦值只有引用類型的屬共享,其他的值類型不共享,

//直接賦值的話,直接賦值:完全共享.賦值的是地址指針,所得屬性都是共享的.

//4,打印查看o對象

console.log(o.des);
console.log(o);//object
console.log(obj.des);//undefined



obj.sayHello = function (){
    console.log('改變了');
};


//5.問題:新對象的引用類型屬性和舊對象中的對應(yīng)屬性是否相等
console.log(o.sayHello == obj.sayHello,"___");//true
console.log(o.sayHello == obj.sayHello);//false
//注意:在修改方法的時候,這里的方法是使用函數(shù)聲明了.重新設(shè)置了一個聲明的函數(shù),重新定義了一個函數(shù)的地址空間,所以這里的函數(shù)方法不是共存的所以方法不相等.

console.log(o.sayHello);
console.log(obj.sayHello);
//問題:那么兩個對象中的其中某個修改了該屬性,則另一個對象會受到影響

console.log(o.demo == obj.demo);
o.demo.nme = "nnnn";
console.log(o.demo == obj.demo);

</script>

補充說明:

eg:<script>
function Person(){
    this.name = "默認(rèn)"
}

Person.prototype.hi = "hi";
var p1 = new Person();
var o = {};

/*for (var k in p1)
{
    if(p1.hasOwnProperty(k))
    {
        o[k] = p1[k];
    }

}

console.log(o.hi);*/

</script>

<script>
var obj = {
    name:"123",
    showName:function(){
        console.log("12345");
    }
}

   /* var obj2 = obj;*/
    var obj2 = {};

//直接賦值:完全共享
 /*   obj.name = "sss";
    console.log(obj2.name);*/
    for(var k in obj){
        if(obj.hasOwnProperty(k)){
            obj2[k] = obj[k];
        }
    }
    console.log(obj.showName == obj2.showName);//true
    obj.showName = function (){
        console.log('改變了');
    }
    console.log(obj.showName == obj2.showName);

</script>

圖形解析:
(1)



(2)



(3)

二.原型對象的補充說明

1.構(gòu)造函數(shù)有一個相關(guān)聯(lián)的原型對象,這個原型對象默認(rèn)是一個空對象{}(實際上這個原型對象擁有一個屬性為constructor屬性的對象).

2.構(gòu)造函數(shù)的原型對象本身是一個Object類型的,Person.prototype (原型對象)是Object,他的構(gòu)造函數(shù)是Object

3.使用構(gòu)造函數(shù)創(chuàng)建出來的對象會擁有一個構(gòu)造器屬性(constructor),該屬性指向創(chuàng)建當(dāng)前對象的構(gòu)造函數(shù).

4.對象本身沒有構(gòu)造器屬性,這個屬性是從原型對象上繼承來的.

eg:

<script>
    function Person(){

    }
    var p1 = Person();

   // console.log(p1.constructor == Person);//報錯
    console.log(Person.prototype.constructor == Person);//true
    
</script>
console.log(Person.prototype);//Object
var o = {};
console.log(o);

console.log(Person.prototype.constructor);//Person這個對象的(訪問的是自己的實例屬性)
delete Person.prototype.constructor;
console.log(Person.prototype.constructor);//Object這個對象的(訪問的是原型對象上面的屬性)

問題???

構(gòu)造函數(shù)的原型對象(空對象|Object類型),他的構(gòu)造函數(shù)是Object,那么他的構(gòu)造器屬性難道不應(yīng)該是Object嗎?

解答:

構(gòu)造器的原型對象身上其實有兩個(constructor)屬性(實例屬性 + 構(gòu)造函數(shù)的原型對象的原型對象上面的屬性)

圖形解析:

image

三.繼承的幾種實現(xiàn)方案

  1. 屬性拷貝(淺拷貝)
  2. 原型式繼承(A.B.C)
  3. 原型鏈繼承
  4. 借用構(gòu)造函數(shù)
  5. 組合繼承
  6. (深拷貝 + 原型式)組合繼承

知識點1:屬性拷貝和直接賦值的區(qū)別:

01 屬性拷貝:

引用類型: (數(shù)組):引用會共享,如果重新設(shè)置,那么會切斷聯(lián)系
引用類型:(函數(shù)):函數(shù)會共享,如果重新設(shè)置,那么會切斷聯(lián)系.

==注意==
屬性拷貝的包括成員和原型對象

02 直接賦值:

直接賦值:完全共享!

數(shù)組: 數(shù)組會共享,如果重新設(shè)置,那么另一個對象會受影響.
函數(shù): 函數(shù)會共享,如果重新設(shè)置,那么另一個對象會受影響.

==1.屬性拷貝繼承:==


eg1:
<script>
var obj1 = {
    arr :[1,2,3],
    show:function (){
        console.log('show');
    }
}

var o = {};
//屬性拷貝
for(var i in obj1){
    o[i] = obj1[i];
}
console.log(o);
console.log(o.arr);
console.log(obj1.arr);

//重新設(shè)置值
obj1.arr = ['demo1','demo2'];
console.log(o.arr);
console.log(obj1.arr);//受影響
</script>

eg2:
<script>
function Person(){
    this.name = '默認(rèn)的名稱';
    this.friends = ['123','456','789'];
}
Person.prototype.hi = 'hi';
var p1 = new Person();
var o = {};
//屬性拷貝
for(var k in p1){
    if(p1.hasOwnProperty(k)){//排除了拷貝原型對象
        o[k] = p1[k];
    }
}
console.log(o);
console.log(p1);
o.name = '我是一個數(shù)字';
console.log(p1.name);//默認(rèn)名稱
p1.friends.push('我給改變了');
console.log(o.friends);
console.log(p1.hi);
console.log(o.hi);//undefined
</script>

圖像解析1:

image

圖形解析2:
image

==直接賦值拷貝==

eg1:
<script>
var demo1 = {
    arr:[1,2,3],
    show:function (){
        console.log('show');
    }
};
//直接賦值
var demo2 = demo1;
console.log(demo1.arr);
console.log(demo2.arr);

demo1.arr = ['test1','test2'];
console.log(demo1.arr);
console.log(demo2.arr);

demo1.show();
demo2.show();
demo1.show = function (){
    console.log('hahaha');
}
demo1.show();
demo2.show();
</script>

圖形解析:

image

==2.原型式繼承==

A 利用對象的動態(tài)特性 (對象-原型)

B 字面量直接替換 (對象-原型)

C 設(shè)置子構(gòu)造函數(shù)的原型對象 = 父構(gòu)造函數(shù)的原型對象 (子構(gòu)造函數(shù)-父構(gòu)造函數(shù))

問題:可以獲得父構(gòu)造函數(shù)原型對象上面的屬性和方法,但是無法獲得父構(gòu)造函數(shù)的實例對象上的屬性和方法.

eg:
A 利用對象的動態(tài)特性 對象-原型
<script>
function Person (name){
    this.name = name;
}
Person.prototype.des = '描述信息';
var p1 = new Person('張三');
</script>

B 字面量直接替換     對象-原型
<script>
function Person(name){
    this.name = name;
}
Person.prototype = {
    constructor:Person,
    des:'默認(rèn)的描述信息'
}
var p1 = new Person('張三');
</script>


C 設(shè)置子構(gòu)造函數(shù)的原型對象=父構(gòu)造函數(shù)的原型對象  子構(gòu)造函數(shù)-父構(gòu)造函數(shù)
<script>
function Person(){
    this.name = '張三';
}
Person.prototype = {
    constructor:Person,
    des:'默認(rèn)的描述信息',
    showDes:function (){
        console.log(this.des);
    }
}

function Boy() {
    this.lol = function (){
        console.log('lol');
    }
}


//設(shè)置子構(gòu)造函數(shù)的原型對象為父構(gòu)造函數(shù)的原型對象,便可以繼承父構(gòu)造函數(shù)的原型對象的屬性和方法
Boy.prototype = Person.prototype;

var boy1 = new Boy();
console.log(boy1.des);//默認(rèn)描述信息
boy1.showDes();
boy1.lol();
</script>

圖形解析:

image

==3.擴展內(nèi)置對象==

定義:
把需要共享的屬性和方法寫在內(nèi)置構(gòu)造函數(shù)的原型對象上.

問題:

01 原型對象上面所有的屬性和方法都會被該構(gòu)造函數(shù)創(chuàng)建出來的對象共享,共享可能會導(dǎo)致一些問題.

02 如果所有的開發(fā)人員都往內(nèi)置構(gòu)造函數(shù)的原型對象上面添加屬性和方法,那么原型上面的屬性和方法會越來越多,難以管理,難以維護,還可能會出現(xiàn)覆蓋問題.

eg:
<script>
//需求:要求給arr1添加屬性name|desLog
var arr1 = [1,2,3];
console.log(arr1);//arr1的構(gòu)造函數(shù)為Array
console.log(arr1.constructor);

arr1.name = 'arr1的名稱';
arr1.desLog = function (){
    console.log('arr1的des');
};

console.log(arr1);

//需求:要求給arr2添加屬性name|desLog
var arr2 = ['demo1','demo2'];
arr2.name = 'arr2的名稱';
arr2.desLog = function (){
    console.log('arr2的des');
}
console.log(arr2);

//需求:要求所有的數(shù)組都擁有name和desLog方法养筒?
</script>
<script>
Array.prototype.name = '默認(rèn)的名稱';
Array.prototype.desLog = function (){
    console.log('默認(rèn)的描述信息');
}

var arr1 = [1];
var arr2 = ['demo1'];
console.log(arr1.name);
console.log(arr2.name);
arr1.desLog();
arr2.desLog();
</script>
注意:共享可能會導(dǎo)致一些問題如下
<script>
Array.prototype.name = 'name';
var arr1 = [1,2,3,4];
for (var i = 0;i<arr1.length;i++){
    console.log(i,arr1[i]);
}
console.log('---------------');
for(var i in arr1){
    console.log(i,arr1[i]);//會打印出name name
}
//兩次遍歷打印的結(jié)果不一樣
</script>

安全的擴展內(nèi)置對象:

01 提供一個自定義的構(gòu)造函數(shù)(空函數(shù))(MyArray)

02 設(shè)置該構(gòu)造函數(shù)的原型對象為內(nèi)置構(gòu)造函數(shù)的實例

03 在構(gòu)造函數(shù)的原型對象上面添加屬性和方法

04 使用自定義的構(gòu)造函數(shù)來創(chuàng)建對象并且使用

 eg:
 <script>
//1.提供一個自定義的構(gòu)造函數(shù)
function MyArray(){}
    //2.設(shè)置該構(gòu)造函數(shù)的原型對象為內(nèi)置構(gòu)造函數(shù)的一個實例
    MyArray.prototype = new Array();//獲得Array的所有的屬性和方法
    //MyArray.prototype = Array.prototype;

    //3.設(shè)置原型對象
    MyArray.prototype.name = '默認(rèn)名稱';
    MyArray.prototype.desLog = function (){
        console.log('哈哈');
    }

    //4.使用自定義的構(gòu)造函數(shù)來創(chuàng)建對象并且使用
    var myArr01 = new MyArray();
    myArr01.push('123','345');
    console.log(myArr01);
    console.log(myArr01.name);//默認(rèn)名稱
    myArr01.desLog();//哈哈

    var myArr02 = new MyArray();
    console.log(myArr02);

//其他的開發(fā)人員
function OtherArray (){};
OtherArray.prototype = new Array();
OtherArray.prototype.name = '默認(rèn)名稱++++++++++++';
OtherArray.prototype.desLog = function (){
    console.log('嘿嘿');
}

var other1 = new OtherArray();
other1.push('demo1','demo2');
console.log(other1);
console.log(other1.name);

var arr = new MyArray();
console.log(arr.name);//默認(rèn)名稱
</script>

圖形解析:

image

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

  1. 其實在js中所有的對象都是由構(gòu)造函數(shù)創(chuàng)建出來的
  2. 所有的構(gòu)造函數(shù)的原型對象所有一個相關(guān)聯(lián)的原型對象
  3. 所有構(gòu)造函數(shù)的原型對象本身也是一個對象,所以構(gòu)造函數(shù)的原型對象也是由構(gòu)造函數(shù)創(chuàng)建出來的
  4. 構(gòu)造函數(shù)的原型對象的構(gòu)造函數(shù)也有一個與之相關(guān)聯(lián)的原型對象,這個原型對象本身也是一個對象
  5. 構(gòu)造函數(shù)的原型對象的原型對象也有自己的構(gòu)造函數(shù)
  6. 構(gòu)造函數(shù)的原型對象的原型對象也有自己的原型對象.以上會形成一種鏈?zhǔn)浇Y(jié)構(gòu),這個結(jié)構(gòu)就是原型鏈.
  7. 在原型鏈的頂端(終點)Object.prototype
  8. Object.prototype本身也是一個對象,所以也有自己的構(gòu)造函數(shù)===>Object
  9. Object.prototype的原型對象應(yīng)該是它的構(gòu)造函數(shù)的原型對象 Object.prototype (推理 不成立)

Object.prototype.__proto__=Object .prototype.constructor.prototype[Object.prototype]

  1. js處理:Object.prototype.__proto__ = null;
    圖形解析:
    image

原型鏈中屬性的搜索規(guī)則:

  1. 對象在訪問屬性的屬性的時候,首先先查找實例對象的成員(屬性|方法)

  2. 如果找到了,那么就直接使用,如果沒有找到,那么就去它的原型對象上面查找,如果找到了就直接使用.

  3. 如果原型上面也沒有找到,那么就繼續(xù)搜索原型對象的原型對象,如果找到了就繼續(xù)使用,如果沒有找到,那么就繼續(xù)上面的過程.

  4. ...重復(fù)上面的搜索過程

  5. 如果查找到Object.prototype也沒有找到,那么句undefined或者是報錯.

     eg:
     <script>
     function Person(){
         this.name = '默認(rèn)'
     }
     Person.prototype.name = '原型上面的名稱';
     Person.prototype.age = '原型上面的年齡';
    
     function Boy(){
         this.lol = 'lol';
         this.name = '男孩';
     }
    
     Boy.prototype = new Person();
     var boy = new Boy();
    
     console.log(boy.name);//男孩
     console.log(boy.age);//原型上面的年齡
     console.log(boy.des);//undefined
     </script>
    

==4.原型鏈繼承==
形式: 子構(gòu)造函數(shù).prototype = new 父構(gòu)造函數(shù)();

步驟:

  1. 提供構(gòu)造函數(shù)

  2. 設(shè)置屬性和方法

  3. 設(shè)置繼承(原型鏈繼承)

  4. 修正構(gòu)造器屬性

     eg:
     <script>
     function A(){
         this.a = 'a';
     }
     A.prototype.desA = 'desA';
    
     function B(){
         this.b = 'b';
     }
    
     //設(shè)置原型鏈繼承
     B.prototype = new A();
     var b = new B();
     console.log(b.a);
     console.log(b.desA);
     </script>
    

使用注意點:

  1. 在設(shè)置完原型鏈接繼承之后,要修正構(gòu)造函數(shù)的原型對象的構(gòu)造器屬性
  2. 設(shè)置原型對象的屬性和方法這個操作需要注意位置,建議在完成原型鏈繼承之后再添加成員(屬性和方法)
  3. 在設(shè)置完原型鏈繼承之后,不能使用字面量的方式來替換當(dāng)前構(gòu)造函數(shù)的原型對象(如果替換,繼承結(jié)構(gòu)會丟失)

不足:

01 無法向父構(gòu)造函數(shù)傳遞參數(shù)

02 父構(gòu)造函數(shù)的實例屬性變成了子構(gòu)造函數(shù)創(chuàng)建出來的對象的原型屬性

    eg:
<script>
function Person(name){
    this.name = name;
    this.friends = ['小花','嘩啦','巴拉']
}

Person.prototype.hi = 'hi';
function Boy(){}
//設(shè)置原型鏈繼承
Boy.prototype = new Person('張三');
Boy.prototype.constructor = Boy;

var boy = new Boy();
console.log(boy);

var boy2 = new Boy();
console.log(boy2);

console.log(boy.friends);//?
console.log(boy2.friends);//?

boy.friends.push('taotao');
console.log(boy.friends);
console.log(boy2.friends);

</script>

==5.Object.create的方法說明:==

  • Object是內(nèi)置構(gòu)造函數(shù)

  • Object.Create()靜態(tài)方法(直接添加在構(gòu)造函數(shù)上面的方法)

  • 作用:創(chuàng)建對象,并且指向原型對象

  • 注意點:該方法是ES5推出,所以有兼容性問題

      eg:
      <script>
      var obj = {
          name:'張三'
      }
    
     /* var o = {};
      o.__proto__ = obj;
      console.log(o.name);*/
    
      var o = Object.create(obj);//創(chuàng)建一個對象,并且指定這個對象的原型對象為obj
      console.log(o);
      </script>
    

兼容性處理:

1.先判斷是否支持create方法,如果不支持,那么我們就是要臨時的構(gòu)造函數(shù)來設(shè)置原型對象并創(chuàng)建對象的實例

2.先判斷是否支持,如果不支持,那么我們就為Object主動地提供create方法

3.抽取一個函數(shù),把設(shè)置原型的過程封裝起來

eg:
<script>
var demo = {
    name:'demo'
}
if(typeof Object.create == 'function'){
    var o = Object.create(demo);
}else{
    //var o = {};
    //o.__proto__ = demo;   //不推薦這樣寫  換一種寫法
    //設(shè)置原型對象
    //訪問原型對象的幾種方法
    //01 構(gòu)造函數(shù).prototype
    //02 對象.__proto__
    //03 Object.getPrototypeOf
    function F(){}
    F.prototype = demo;
    var o = new F();
}
</script>

<script>
    var demo = {
        name:'demo'
    }
    if(typeof Object.create == 'function'){
        var o = Object.create(demo);
    }else{
        Object.create = function (){
            function F(){}
            F.prototype = demo;
            var o = new F();
        }
    }
</script>
<script>
    function Create(obj){
        if(typeof Object.create == 'function'){
            var o = Object.create(obj);
        }else{
            function F(){}
            F.prototype = obj;
            return new F();
        }
    }

    var obj = {age:23};
    var o = Create(obj);
</script>

==6.Object.assign()方法==

作用: 拷貝多個對象的屬性(不會拷貝對象的原型成員)而利用for...in...拷貝會拷貝原型成員

語法:Object.assign(目標(biāo)對象,要拷貝的對象...);

eg:
<script>
var obj1 = {
    name:'默認(rèn)的名稱'
}

var obj2 = {
    age:23
}

var obj3 = {
    book:'小說'
}

var obj = {};
Object.assign(obj,obj1,obj2,obj3);
console.log(obj);
</script>
<script>
function Person (){
    this.name = '張三'
}
Person.prototype.hi = 'hi';

var p1 = new Person();
var o = {};
Object.assign(o,p1);
console.log(o);
console.log(o.hi);//undefined
</script>

==7.call和apply的用法說明==

call和apply是js中所有對象都擁有的兩種方法

作用:借用對象的方法
call和apply的作用一模一樣

區(qū)別:傳遞參數(shù)不一樣

call:
第一個參數(shù):誰調(diào)用(借用)就傳遞誰,傳遞的是誰,那么函數(shù)內(nèi)部的this就指向誰

其他參數(shù):參數(shù)列表的方式傳遞
對象.方法.call(this綁定的對象,參數(shù)1葱轩,參數(shù)2闸盔,參數(shù)3,...)

apply:
第一個參數(shù):誰調(diào)用(借用)就傳遞誰预麸,傳遞的是誰盖溺,那么函數(shù)內(nèi)部的this就指向誰

其他參數(shù):數(shù)組元素
對象.方法.apply(this綁定的對象,[參數(shù)1砰苍,參數(shù)2莫鸭,參數(shù)3,...])

eg:
<script>
var obj1 = {
    name:'張三',
    showName:function (param1,param2){
        console.log(this.name + param1 + param2);
    }
}

var obj2 = {
    name:'李四'
}

/*obj1.showName();
obj2.showName();*///obj2要使用obj1的showName方法

obj1.showName.call(obj2,'demo1','demo2');
//obj1.showName.apply(obj2);
obj1.showName.apply(obj2,['demo1','demo2']);
</script>

==8.this.的指向說明詳解:==

this 指向的永遠(yuǎn)都是一個對象(在非嚴(yán)格模式下)
函數(shù)的調(diào)用

  • 01 以普通函數(shù)方式調(diào)用 this -->window

  • 02 以對象的方法來調(diào)用 this --->對象

  • 03 new 構(gòu)造函數(shù)的方式來調(diào)用 this--->指向內(nèi)部新創(chuàng)建的對象

  • 04 函數(shù)上下文的方式來調(diào)用(call|apply) this--->綁定的第一個參數(shù) 如果不傳遞參數(shù)那么默認(rèn)指向window

      eg:
      <script>
      function func(){
          console.log(this);
      }
    
      //1.以普通函數(shù)調(diào)用
      func();//window
    
      var obj = {name:'test'};
      obj.funcTest = func;
      //2.以對象的方法來調(diào)用
      obj.funcTest();//obj
    
      var o = {
          test:function (){
              console.log(this);
          }
      }
      o.test.call();//window
      </script>
    

==9.借用構(gòu)造函數(shù)繼承的基本寫法.==

借用構(gòu)造函數(shù)繼承的基本寫法:

通過借用父構(gòu)造函數(shù)獲得父構(gòu)造函數(shù)的實例屬性
思考:無法獲得父構(gòu)造函數(shù)的原型成員

eg:
<script>
function Person(name){
    this.name = name;
}
Person.prototype.hi = 'hi';

function Boy(name,lol){
    //在構(gòu)造函數(shù)內(nèi)部默認(rèn)會創(chuàng)建空對象并且賦值給this
    this.lol = lol;
    //獲取Person構(gòu)造函數(shù)的實例屬性
    Person.call(this,name);
}

var boy = new Boy('張三','英雄聯(lián)盟');
console.log(boy.name);

var boy2 = new Boy('李四','CF');
console.log(boy2.name);
console.log(boy.lol);
console.log(boy2.lol);

console.log(boy.hi);//undefined
console.log(boy2.hi);//undefined

</script>

組合構(gòu)造函數(shù)繼承的基本寫法:

eg:
<script>
function Person(name){
    this.name = name;
}
Person.prototype.hi = 'hi';

function Boy(name,lol){
    //在構(gòu)造函數(shù)內(nèi)部默認(rèn)會創(chuàng)建空對象并且賦值給this
    this.lol = lol;
    //獲取Person構(gòu)造函數(shù)的實例屬性
    Person.call(this,name);
}

//設(shè)置原型鏈繼承
Boy.prototype = Person.prototype;//原型式繼承C(繼承原型對象)

var boy = new Boy('張三','英雄聯(lián)盟');
console.log(boy.name);

var boy2 = new Boy('李四','CF');
console.log(boy2.name);
console.log(boy.lol);
console.log(boy2.lol);

console.log(boy.hi);//hi
console.log(boy2.hi);//hi

console.log(boy);
</script>

==10.深拷貝和淺拷貝:==

淺拷貝:for...in obj[k] = obj1[k] 引用類型會分享

深拷貝:對淺拷貝的方式進行改進

eg:
<script>
var o = {
    name:'張三',
    friends:['demo1','demo2'],
    car:{
        type:'奔馳'
    }
}

function deepCopy(obj1,obj2){
    obj1 = obj1 || {};
    for(var k in obj2){
        if(obj2.hasOwnProperty(k)){
            //判斷是值類型還是引用類型
            if(typeof obj2[k] == 'object'){
                //如果是引用類型闹丐,那么就再次循環(huán)
                //注意:obj1[k]要做初始化處理 ES5
                obj1[k] = Array.isArray(obj2[k]?[]:{}); //檢查是什么類型的?如果是數(shù)組[],如果是對象{}
                deepCopy(obj1[k],obj2[k]);
            }else{
                obj1[k] = obj2[k];//值類型
            }
        }
    }
}

var demo  = {};
deepCopy(demo,o);
console.log(demo);
demo.car.type = '奧迪';
console.log(o.car.type);
console.log(o);
console.log(demo);
</script>

==11.深拷貝與借用構(gòu)造函數(shù)實現(xiàn)繼承==

01 通過借用父構(gòu)造函數(shù)獲得父構(gòu)造函數(shù)的 實例屬性

02 思考:無法獲得父構(gòu)造函數(shù)的原型成員

eg:
<script>
function deepCopy(obj1,obj2) {
    obj1 = obj1 || {};
    for(var k in obj2)
    {
        if (obj2.hasOwnProperty(k)){
            //判斷是值類型還是引用類型
            if (typeof obj2[k] == "object")
            {
                //如果是引用類型被因,那么就再次循環(huán)
                //注意:obj1[k]要做初始化處理 ES5
                obj1[k] = Array.isArray(obj2[k])?[]:{};   //檢查是什么類型的卿拴?如果是數(shù)組[],如果是對象{}
                deepCopy(obj1[k],obj2[k]);
            }else
            {
                obj1[k] = obj2[k];  //值類型
            }
        }
    }
}
function Person(name){
    this.name = name;
}
Person.prototype.hi = 'hi';
Person.prototype.car = {
    type:'飛船'
}

function Boy(name,lol){
    //在構(gòu)造函數(shù)內(nèi)部默認(rèn)會創(chuàng)建空對象并且賦值給this
    this.lol  = lol;
    //獲取Person構(gòu)造函數(shù)中的實例屬性
    Person.call(this,name);
}

//設(shè)置原型鏈繼承
//Boy.prototype = new Person();
//Boy.prototype = Person.prototype;     //原型式繼承C
deepCopy(Boy.prototype,Person.prototype);

var p1 = new Person();
var boy = new Boy('李四','CF');
console.log(p1.car);//飛船
console.log(boy.car);//飛船

p1.car.type = '傻逼了';
console.log(p1.car);//傻逼了
console.log(boy.car);//傻逼了
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衫仑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子堕花,更是在濱河造成了極大的恐慌文狱,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缘挽,死亡現(xiàn)場離奇詭異瞄崇,居然都是意外死亡,警方通過查閱死者的電腦和手機壕曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門苏研,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窝稿,你說我怎么就攤上這事楣富。” “怎么了伴榔?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵纹蝴,是天一觀的道長。 經(jīng)常有香客問我踪少,道長塘安,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任援奢,我火速辦了婚禮兼犯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘集漾。我一直安慰自己切黔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布具篇。 她就那樣靜靜地躺著纬霞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驱显。 梳的紋絲不亂的頭發(fā)上诗芜,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音埃疫,去河邊找鬼伏恐。 笑死,一個胖子當(dāng)著我的面吹牛栓霜,可吹牛的內(nèi)容都是我干的翠桦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胳蛮,長吁一口氣:“原來是場噩夢啊……” “哼秤掌!你這毒婦竟也來了愁铺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闻鉴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茂洒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孟岛,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年督勺,在試婚紗的時候發(fā)現(xiàn)自己被綠了渠羞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡智哀,死狀恐怖次询,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓷叫,我是刑警寧澤屯吊,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站摹菠,受9級特大地震影響盒卸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜次氨,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一蔽介、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧煮寡,春花似錦虹蓄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杈帐,卻和暖如春体箕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挑童。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工累铅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人站叼。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓娃兽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尽楔。 傳聞我的和親對象是個殘疾皇子投储,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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