JavaScript學習總結之原型物件(整理分享)

2022-01-17 19:01:16
本篇文章給大家帶來了關於JavaScript中原型物件的相關知識,希望對大家有幫助。

你理解的類?類的特性有哪些?(封裝,繼承,多型)

類實際是一個「特殊的函數」,就像你能夠定義的函數表示式和函數宣告一樣,類語法也由兩個組成部分:類宣告和類表示式。類的主體都是在嚴格模式下執行的。

類的類體是由一對花括號{}中的部分,這是定義類成員的位置。【成員主要是方法或者建構函式】

類的所有方法都等價於是定義在類的prototype屬性上。在類的實列上呼叫方法,等同於在呼叫原型上的方法。

class A(){
    constructor(){}
    a(){}
    b(){}
}
//等價於
A.prototype={constructor(){},a(){},b(){}}

組成:

  • 建構函式:

constructor方法是一個特殊的方法,這種方法用於建立和初始化一個由class建立的物件。一個類只能有一個建構函式,如果多個會報錯,如果沒有會預設新增一個空的constructor。其中constructor預設返回實列物件【即this】。一個建構函式可以使用super關鍵字來呼叫一個父類別的建構函式。

  • 屬性

  • 原型方法:該方法不需要加上function關鍵字,直接把函數的定義放進去就可以了。方法和方法之間不能用逗號分隔,會報錯。

  • 靜態方法:使用static定義靜態方法,呼叫靜態方法,不能類的實列去呼叫,只能使用類去呼叫。

  • 取值函數getter和存值函數setter:在類中使用get和set關鍵字,對某個屬性設定存值和取值函數,攔截該屬性的存取行為。

類語法:

  • 類宣告:使用class關鍵字

class Rectangle{
    constructor(height,width){
        this.height=height;
        this.width=width;
    }
}

注意:函數宣告和類宣告的區別:類宣告不會提升,函數宣告會提升。

類表示式:類表示式可以是被命名的或匿名的。賦予一個命名類表示式的名稱是類的主體的本地名稱。

 let Rectangle=class{//匿名類
      constructor(height,width){
            this.height=height;
            this.width=width;
        }
 }
 let Rectangle= class Rectangle{//命名類
      constructor(height,width){
            this.height=height;
            this.width=width;
        }
 }

使用extends建立子類:

extends關鍵字在類宣告或類表示式中用於建立一個類作為另一個類的子類。

使用super呼叫超類:

super關鍵字用於呼叫物件的父物件上的函數

類的特性:

- 封裝:主要是通過函數,私有屬性和方法的設定主要是通過塊級作用域實現

- 多型:可以通過函數呼叫,因為引數是可以多變的

- 繼承:主要通過原型鏈

當我們在new一個普通函數時候,發生了什麼?

  • 以構造器的 prototype 屬性(注意與私有欄位 [[prototype]] 的區分)為原型,建立新物件;

  • 將this 和呼叫引數傳給構造器,執行;

  • 如果構造器返回的是物件,則返回,否則返回第一步建立的物件。

new 這樣的行為,試圖讓函數物件的語法跟類變得相似,但是,它客觀上提供了兩種方式,一是在構造器中新增屬性,二是在構造器的 prototype 屬性上新增屬性。

new後面的函數名一定要大寫嗎?

不是,主要是為了便於區分類。一般約束為大寫

如何理解ProtoType?查詢一個物件的某個屬性的過程?

prototype:

每個函數都有一個特殊的屬性叫做原型物件【prototype】

js是基於原型的語言,每個物件都擁有一個原型物件,物件以其原型為模板、從原型繼承方法和屬性。這些屬性和方法時定義在物件的建構函式之上的prototype屬性上,而非物件的範例本身。

原型物件可以再擁有原型物件,並從中繼承方法和屬性,一層一層,層層向上直到一個物件的原型物件為 null,這種就是原型鏈。

建立物件範例時,物件的範例和它的構造器之間建立一個連結【__proto__屬性,是從建構函式的prototype屬性派生的。也就是__proto__與建構函式的prototype是指向同個物件】Object.getPrototypeof(new Foobar())和Foobar.prototype是相等的。

Object.create()。是從指定的原型物件,建立一個新物件。var newObj=Object.create(obj)。則newObj的__proto__=obj

每個實列物件都從原型中繼承了一個constructor屬性。該屬性指向了構造此範例的建構函式。

一般都是構造器中定義屬性,在prototype定義方法。

一般由建構函式實列化出一個新物件,新物件的原型物件是一個constructor和一個Object的原型物件組成。而函數建構函式的原型物件是也是由另外一個constructor和一個Function的原型物件組成。

    var F=function(){};
    Object.prototype.a=function(){};
    Function.prototype.b=function(){};
    var f=new F();
    //上面的結果是,f能取到a,不能取到b.
    詳解:
        1.f.__proto__===F.prototype
        2.F.prototype.__proto__===Object.prototype(所以f可以存取a)
        3.f.constructor===F
        4.F.__proto__===Function.prototype(所以f.constructor.b可以存取)

查詢屬性的過程:

1.先查詢自己身屬性是否由包含該屬性。

2.如果沒有,才會沿著原型鏈,層層向上搜尋,直到找到名字的屬性

3.如果找到最後原型鏈的末尾,即最後的原型為null,那就是沒有找到該屬性。就會返回undefined

不同方法建立物件和原型鏈

1.使用語法結構建立物件

var o = {a: 1};
// o 這個物件繼承了 Object.prototype 上面的所有屬性
// o 自身沒有名為 hasOwnProperty 的屬性
// hasOwnProperty 是 Object.prototype 的屬性
// 因此 o 繼承了 Object.prototype 的 hasOwnProperty
// Object.prototype 的原型為 null
// 原型鏈如下:
// o ---> Object.prototype ---> null
var a = ["yo", "whadup", "?"];
// 陣列都繼承於 Array.prototype 
// (Array.prototype 中包含 indexOf, forEach 等方法)
// 原型鏈如下:
// a ---> Array.prototype ---> Object.prototype ---> null
function f(){
return 2;
}
// 函數都繼承於 Function.prototype
// (Function.prototype 中包含 call, bind等方法)
// 原型鏈如下:
// f ---> Function.prototype ---> Object.prototype ---> null

2.使用建構函式建立物件

function A() {
this.a = 1;
this.b = 2;
}
A.prototype = {
write: function(){
    console.log(this.a);
}
};
var a = new A();
// a 是生成的物件,他的自身屬性有 'a' 和 'b'。

3.使用Object.create()建立物件(ES5)

var a = {a: 1}; 
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (繼承而來)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因為d沒有繼承Object.prototype
使用

4.使用class建立物件(ES6)

class A {
constructor(a, b) {
    this.a = a;
    this.b = b;
}
}
class B extends A {
constructor(a,b,c) {
    super(a, b);
    this.c=c;
}
get ab() {
    return this.a + this.b;
}
set d(d) {
    this.a = d;
    this.b = d;
    this.c = d;
}
}
var a= new A('a','b');//a的原型物件是 A.prototype
var b = new B('a','b','c');//    //b的原型物件是 B.prototype

當一個物件設定屬性時都發生了什麼?

如果物件包含普通資料存取屬性,直接賦值只會修改屬性值

var a={b=1}//因為b是a的普通屬性,資料型別為Number

a.b="a"; //直接更改b的型別為String,且賦值為'a'.

如果物件找不到該屬性,且原型鏈也找不到,就直接預設新增一個屬性到該物件上。

var a={}//b不是a的普通屬性,且原型鏈上也沒有

a.b="a"; //直接在a上新增b的型別,為String,且賦值為'a'.

如果屬性b,存在於原型鏈上

//在原型鏈上層存在名為b的普通資料存取屬性並且沒有標記為唯讀(writable:false),那就會直接在a中新增一個名為b的新屬性,且值為'a'。而原型鏈上的b就會被遮蔽掉:

    function A(){};
    A.prototype.b=1;
    var a=new A();
    a.b='a';

//在原型鏈上層存在b,但是他被標記為唯讀,那麼無法修改已有屬性,或者在a中建立遮蔽屬性。如果執行在嚴格模式下,程式碼會丟擲一個錯誤,否則,這條賦值語句會被忽略,總之,不會發生遮蔽。

    function A(){
    };
A.prototype.b=1
    Object.defineProperty(A.prototype,'b',{
        configurable:true,
        writable:false
    })
    var a=new A();
    a.b='a';//結果a.b還是1

【相關推薦:

以上就是JavaScript學習總結之原型物件(整理分享)的詳細內容,更多請關注TW511.COM其它相關文章!