class(類)和構造函數(原型對象)


構造函數和class的關系,還有面向對象和原型對象,其實很多人都會很困惑這些概念,這是第二次總結這些概念了,之前一次,沒有class類,其實了解了構造函數,class也就很容易理解了

 

一. 構造函數和原型 

  1.function 聲明(創造)了一個函數 Person,叫構造函數

  2.原型對象:在聲明了一個函數之后,瀏覽器會自動按照一定的規則創建一個對象,這個對象就叫做原型對象。這個原型對象其實是儲存在了內存當中。

  3.在聲明了一個函數后,這個構造函數(聲明了的函數)中會有一個屬性prototype,這個屬性指向的就是這個構造函數(聲明了的函數)對應的原型對象;原型對象中有一個屬性constructor,這個屬性指向的是這個構造函數(聲明了的函數)。

  所以說:Person(構造函數)的 prototype 指向原型對象,原型對象的 constructor 屬性,又指向該構造函數本身

1 function Person(name, age) {
2       this.name = name;
3       this.age = age;
4     }
5     console.log(Person);                               // 構造函數本身
6     console.log(Person.prototype.constructor);         // 指向 構造函數本身
7     Person("范順", 18);

 二. 構造函數使用new來創建對象 

1 function students() {
2   
3     }
4   
5 var stu = new students();

  1.  stu 是 new students()(構造函數) 創建出來的對象,這個stu對象中是沒有prototype屬性的,prototype屬性只有在構造函數students中有

  2. 但stu(創建出來的對象)有一個__proto__屬性,stu調用這個屬性可以直接訪問到構造函數students的原型對象(也就是說,stu的__proto__屬性指向的是構造函數的原型對象)

  所以:stu.__proto__ = students.prototype 都指向原型對象

 

 

 

   3. 我們給原型對象添加屬性和方法,那么 new 出來的這個對象就可以訪問到該原型對象的屬性和方法

 1 function students() {
 2       /* 我就是構造函數 */
 3     }
 4     students.prototype.name="shun"
 5     var stu = new students();
 6     console.log(stu.__proto__.name);  // 訪問到原型對象添加的屬性
 7     console.log(stu.name);  // 這樣也是能訪問到原型對象添加的屬性,因為stu本身沒有這個name屬性,所以說會向stu對象的__proto__ 屬性指向的原型對象中找,找到就返回,找不到就往上找,就是原型鏈
 8     
 9     stu.name = "fan"      // 給stu對象添加屬性
10     console.log(stu.name);  // 訪問stu對象的屬性

  4. 因為 new 出來的 stu 是一個對象,我們也可以給它直接設置屬性,如果找到直接返回值,如果stu對象本身沒有這個屬性,那么就會向上找stu對象的__proto__屬性指向的原型對象中查找,如果查找到則返回。(如果原型中也沒有找到,則繼續向上找原型的原型 這就是所說的原型鏈

  5. 如果通過stu對象添加了一個屬性name,則stu對象來說就屏蔽了原型中的屬性name。 換句話說:在stu中就沒有辦法訪問到原型的屬性name了。
通過stu對象只能讀取原型中的屬性name的值,而不能修改原型中的屬性name的值。 stu.name = “李四”; 並不是修改了原型中的值,而是在stu對象中給添加了一個屬性name

<script type="text/javascript">
        function students () {       
        }
        // 可以使用students.prototype 直接訪問到原型對象
        //給students函數的原型對象中添加一個屬性 name並且值是 "張三"
        students.prototype.name = "張三";
        students.prototype.age = 20;
  
        var stu = new students();
        /*
            訪問stu對象的屬性name,雖然在stu對象中我們並沒有明確的添加屬性name,但是
            stu的__proto__屬性指向的原型中有name屬性,所以這個地方可以訪問到屬性name
            就值。
            注意:這個時候不能通過stu對象刪除name屬性,因為只能刪除在stu中刪除的對象。
        */
        alert(stu.name);  // 張三
  
        var stu1 = new students();
        alert(stu1.name);  // 張三  都是從原型中找到的,所以一樣。
  
        alert(stu.name === stu1.name);  // true
  
        // 由於不能修改原型中的值,則這種方法就直接在stu中添加了一個新的屬性name,然后在stu中無法再訪問到
        //原型中的屬性。
        stu.name = "李四";
        alert(stu.name); //李四
        // 由於stu1中沒有name屬性,則對stu1來說仍然是訪問的原型中的屬性。   
        alert(stu1.name);  // 張三 
    </script>

三. 與原型有關的幾個方法
**1. prototype屬性**

prototype 存在於構造函數中 (其實任意函數中都有,只是不是構造函數的時候prototype我們不關注而已) ,他指向了這個構造函數的原型對象。

**2.constructor屬性**

constructor屬性存在於原型對象中,他指向了構造函數

如下面代碼:

<script type="text/javascript">
function students () {
}
alert(students.prototype.constructor === students); // true
</script> 

我們根據需要,可以students.prototype 屬性指定新的對象,來作為students的原型對象。但是這個時候有個問題,新的對象的constructor屬性則不再指向students構造函數了。

**3.__proto__ 屬性(注意:左右各是2個下划線)**

用構造方法創建一個新的對象之后,這個對象中默認會有一個屬性__proto__, 這個屬性就指向了構造方法的原型對象。

四. class(類)

 1 class Point {
 2   constructor() {
 3     // ...
 4   }
 5   toString() {
 6     return '類似於夠贊函數中的原型鏈,訪問到這個原型身上的方法'
 7   }
 8   toValue() {
 9     // ...
10   }
11 }
12 
13 
14 // 等同於
15 // Point.prototype = {
16   //toString(){},
17   //toValue(){}
18 //};
19 
20 // 所以說
21 const p1 = new Point()
22 console.log(p1.toString())  //類似於夠贊函數中的原型鏈,訪問到這個原型身上的方法

 實例屬性和靜態屬性(實例方法和靜態方法)      

  這里我是進入了一個誤區,但是通過打印發現

  拿下面的例子舉例:我錯誤的認為 P1.info 是有值的,雖然構造函數身上追加了一個屬性 info,顯而易見,這是原型對象的 constructor 身上的屬性,並不是原型對象身上的屬性

,因為 原型對象的 constructor指向構造函數本身,這個info是構造函數身上的方法,而通過new出來的實例對象 P1.info 其實是通過原型鏈的形式訪問原型對象身上的info屬性,所以說訪問的是 undefined,這里的 constructor屬性和 P1 的 info屬性都屬於原型對象身上的屬性,他倆是平級關系

  只要是通過new出來的實例能訪問到的方法(屬性),叫做實例方法,靜態方法只存在構造函數本身

  實例屬性:通過new出來的實例訪問到的屬性叫做實例屬性 

  靜態屬性:在構造函數中構造函數添加的屬性 或者說 在class內部通過static 修飾的屬性叫做靜態屬性

 1 function Person(name, age) {
 2   this.name = name;
 3   this.age = age;
 4 }
 5 
  Person.show = function() { //靜態方法
    console.log('這是靜態方法')
  } 6 Person.info = '哈哈' //靜態屬性
  Person.prototype.say = function() { //
這是實例方法,掛載到的是構造函數的原型對象身上,P1可以訪問到
    console.log("這是實例方法,掛載到的是構造函數的原型對象身上,P1可以訪問到")
  }
7 const P1 = new Person("范順", 18); 8 console.log(P1.name) //通過new出來的實例訪問到的屬性叫做實例屬性 9 console.log(P1.age) 10 11 console.log(P1.info) // undefined 12 console.log(Person.info) //靜態屬性
  P1.say() //
這是實例方法,掛載到的是構造函數的原型對象身上,P1可以訪問到

13 14 15 class Anmin { 16 constructor(name, age) { 17 this.name = name; 18 this.age = age; 19 } 20 21 // 在class內部通過static 修飾的屬性叫做靜態屬性,只能被構造函數名或者類名讀取,new出來的對象讀不到 22 static info = '哈哈'
   say() {
    console.log('實例方法')
  }
  static show() {
    console.log('靜態方法')
  }
23 } 24 25 const A1 = new Anmin('大黃', 9) 26 27 console.log(A1.name) //實例屬性 28 console.log(A1.age) 29 30 console.log(A1.info) // undefined 31 console.log(Anmin.info) //靜態屬性
  console.log(A1.say()) //實例方法 say

class類的extends繼承 

  繼承父類的屬性和方法

 

 

 1 class Father {
 2   constructor(name, age) {
 3     this.name = name
 4     this.age = age
 5   }
 6 }
 7 // 子類
 8 class Person extends Father {
 9   constructor(name, age, yellow) {    //yellow 是子類定義的屬性
10     super(name, age, yellow)
11     this.yellow = yellow
12   }
13 }
14 
15 const P1 = new Person("范順", 18, "紅")
16 console.log(P1)
17 
18 // 子類
19 // class Anmainl {
20 // }
21 
22 // const A1 = new Anmainl('二哈', 9)
23 // console.log(A1)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM