1. 程式人生 > >js的原型鏈以及繼承

js的原型鏈以及繼承

1. 先有建構函式,再有的例項物件
2. 建構函式裡面有一個原型物件
3. 原型物件裡面的構造器指向對應的建構函式
4. 例項物件裡面的原型指向建構函式裡面的原型物件

  原型鏈:是一種關係,例項物件和原型物件之間的關係,通過__proto __來聯絡的,建構函式本身與例項物件沒什麼聯絡
 
  建構函式裡面的原型物件裡面的原型__proto__指向的是objct,,objct的原型為null
 例如:
var divObj = document.getElementById("dv")
  console.dir(divObj);
var divObj = document.getElementById("dv")
    console.dir(divObj);
     
divObj.__proto__---->HTMLDivElement.prototype的__proto__----->
HTMLDivElement.prototype的__proto__----->Element.prototype的
__proto__----->Node.prototype的__proto__-------->
eventTarget.prototype的__proto__---->Object.prototype沒有__proto__,
所以Object.prototype中的__proto__為null
 

this物件 

建構函式中的this是例項物件
嚴格模式:
"use strict";
function f1 () {
console.log(this) ;window
}
f1();   //當加上嚴格模式後f1()呼叫結果為undefined,Window.f1()才對
不加上嚴格模式,不用加Window
原型物件方法中的this也是例項物件


 


 

原型的指向改變

當原型物件prototype裡面的指向改變了,那麼原型__proto__指向也改變了
 這裡的原型物件的指向相當於C語言中的指標

 先改變原型物件的指向,再新增方法,才能訪問當前的方法

這裡就相當於我告訴你錢在我這讓你來拿,但是你來的途中,我說錢不在我這,所以你在我這拿不到錢,而如果先把錢移動的位置告訴你,你就可以直接拿到錢,是一個道理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
     function Person (age) {
        this.age = age;
    }
     Person.prototype.study = function () {
        console.log("學習很重要");
    }
     function Zhu () {
    }
    Zhu.prototype = new Person(10);  
     Zhu.prototype.eat = function () {//指向改變後,再給一個新的原型
        console.log("豬隻知道吃");
    }
    var zhu = new Zhu();
//    var stu = new Person(10);
    zhu.study();
    zhu.eat();
</script>
</body>
</html>

繼承

真正的面嚮物件語言存在類(class)(特殊的資料型別),js沒有類的概念,不是面向物件的語言,所以js沒有類,但是js可以模擬面向物件的思想程式設計,js中會通過建構函式來模擬類的概念


 繼承:首先繼承是一種關係,類與類之間的關係,js中沒有類,但是通過建構函式模擬類,然後通過原型來實現繼承
 繼承也是為了資料共享,js中的繼承也是為了實現資料共享

 原型作用之一:實現資料共享,節省空間
 原型作用之二:為了實現繼承

1,通過建構函式原型物件來繼承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>

    //通過原型繼承 ,雖然能繼承,但是都是一樣的屬性與值
    function Person (name,age,sex) {
       this.name = name ;
       this.age = age ;
       this.sex = sex ;
    }
    Person.prototype.study = function () {
        console.log("學習");
    }
    function Stu (score) {
//        this.name = name ;
//        this.age = age ;
//        this.sex = sex ;
        this.score = score;
    }
    Stu.prototype = new Person("張",17,"男"); //使學生的指向改變成人,那麼人裡面的屬性和方法都能共享
    Stu.prototype.study1 = function () {
        console.log("學習");
    }
    var stu = new Stu(100);
    var stu1 = new Stu(100);
    var stu2 = new Stu(100);
    stu.study();
    stu1.study();
    stu2.study();
    console.log(stu.name,stu.sex,stu.age,stu.score);
    console.log(stu1.name,stu1.sex,stu1.age,stu1.score);
    console.log(stu1.name,stu1.sex,stu1.age,stu1.score);
</script>
</body>
</html>

這個繼承的缺點是所有繼承的屬性,方法都一樣 

那麼如何解決這種問題呢,來後接下來講一講下面這種繼承

2,通過建構函式的借用繼承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
    //借用建構函式繼承 :建構函式名字.call(當前物件,屬性),解決了屬性繼承,並且值不重複,但是方法不能繼承
    function Person (name,age,sex) {
        this.name = name ;
        this.age = age ;
        this.sex = sex ;
    }
    Person.prototype.study = function () {
        console.log("學習");
    }
    function Stu (name,age,sex,score) {
//        this.name = name ;
//        this.age = age ;
//        this.sex = sex ;
        Person.call(this,name,age,sex,score);//相當於呼叫Person物件
        this.score = score;
    }
//    Stu.prototype = new Person("張",17,"男");
    Stu.prototype.study1 = function () {
        console.log("學習");
    }
//    stu.name = "張";
//    stu.sex = "男";      在這裡重新賦值就可以了,但是太多,而且這樣就沒有傳值的必要性了
//    stu.age = "19";
//    var stu1 = new Stu(1);
    var stu1 = new Stu("張1","男1",119,1100);
//    stu1.name = "張1";
//    stu1.sex = "男1";
//    stu1.age = "20";
//    var stu2 = new Stu(1001);
    var stu2 = new Stu("張2","男2",129,1200);
//    stu2.name = "張2";
//    stu2.sex = "男2";
//    stu2.age = "21";
//    var stu3 = new Stu(1002);
    var stu3 = new Stu("張3","男3",139,1300);
//    stu3.name = "張3";
//    stu3.sex = "男3";
//    stu3.age = "22";
    console.log(stu1.name,stu1.sex,stu1.age,stu1.score);
    console.log(stu2.name,stu2.sex,stu2.age,stu2.score);
    console.log(stu3.name,stu3.sex,stu3.age,stu3.score);
    stu3.study();   //報錯,方法不能繼承

</script>
</body>
</html>

這種方法雖然解決了屬性值不用,但是缺陷在於其方法不能繼承,呼叫方法,會報錯 ,那麼為了解決不報錯問題,接下來引入

3.組合繼承(原型與借用一起使用)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
    function Person (name,age,sex) {
        this.name = name ;
        this.age = age ;
        this.sex = sex ;
    }
    Person.prototype.study = function () {
        console.log("學習");
    }
    function Stu (name,age,sex,score) {
        Person.call(this,name,age,sex,score);//相當於呼叫Person物件
        this.score = score;
    }
        Stu.prototype = new Person(); //不傳值
    Stu.prototype.study1 = function () {
        console.log("學習");
    }
    var stu1 = new Stu("張1","男1",119,1100);
    var stu2 = new Stu("張2","男2",129,1200);
    var stu3 = new Stu("張3","男3",139,1300);
    console.log(stu1.name,stu1.sex,stu1.age,stu1.score);
    stu1.study();
    console.log(stu2.name,stu2.sex,stu2.age,stu2.score);
    stu2.study();
    console.log(stu3.name,stu3.sex,stu3.age,stu3.score);
    stu3.study();   
</script>
</body>
</html>

後面還有繼承的方法,明日再來總結