這篇文章為大家帶來了關於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学习教程】
以上是JavaScript學習總結之原型物件(整理分享)的詳細內容。更多資訊請關注PHP中文網其他相關文章!