摘要:在創建子類實例時,不能向超類型的構造函數中傳遞參數。構造函數繼承子類傳進的值是基本思想是在子類構造函數的內部調用超類或父類型構造函數。繼承保證構造函數指針指向如果想同時繼承多個,還可使用添加屬性的方式類繼承,
OOP:Object Oriented Programming 面向對象編程。
題外話:面向對象的范圍實在太大,先把這些大的東西理解理解。1.什么是對象?
根據高程和權威指南上的定義,對象是一組沒有特定順序的值,我們可以把對象看成是從字符串到值的映射。2.怎樣理解原型和原型鏈?
原型:
根據權威指南上的定義:每一個js對象(null除外)都和另一個對象相關聯, “另一個”對象就是我們熟知的原型,每一個對象都從原型上繼承屬性。原型也是對象。 通俗點講,就是一個擁有prototype屬性、且這個屬性指向函數的原型對象的對象。
原型的好處就是:原型上的方法和屬性會被所有實例所共享。
原型鏈:
當訪問某個實例屬性或方法時,會先自身對象中查找,查不到時再往當前對象原型上找; 若依然沒找到,則會繼續往原型對象的原型上找,一直到找到結果或者找到Object.prototype為止也沒找到, 然后這時就會返回undefined,這么一個鏈式查找過程形成的結構就叫原型鏈。
每個對象都有一個__proto__屬性,函數也是對象,所以函數也有;3.面向對象的三大特性是什么?
每個函數都有一個prototype屬性,而實例對象沒有。
封裝,繼承,多態(指一個方法可以有多種調用方式:例如有參或無參)4.創建對象有哪些方式? (1).對象字面量
let obj={};
(2).Object方式let obj=new Object();
(3).Object.createlet obj=Object.create({}/null);
注意!!前面這三種方式的的構造函數都是Object,而Object已經是原型鏈的最頂端了,所以Object.prototype都為undefined。(4).工廠模式可以用實例的__proto__.constructor查看構造函數是否指向Object構造函數。
function person(name,job){ let o={}; o.name=name; o.job=job; o.sayName=function(){ console.log(this.name); } return o; } let p1=person("nagi","sleep"); console.log(p1.constructor); // 指向Object p1 instanceof person; // false;
優缺點:
這種模式雖然解決了量產對象的問題,但卻無法獲知當前對象是何類型 (例如類型:Array,Math等內置對象,或者BOM(window)/DOM的宿主對象,又或者自定義對象等)
注意點:函數首字母不用大寫。
(5).構造函數模式function Person(name,job){ this.name=name; this.job=job; this.sayName=function(){ console.log(this.name); } } let p1=new Person("nagi","sleep"); console.log(p1.constructor); // 指向Person p1 instanceof Person; // true
與工廠模式區別:
a.沒有顯式創建對象; b.直接將屬性和方法賦給了this對象 c.不有return語句;
拓展:new操作符做了些什么?
a.創建一個新對象; b.將構造函數的作用域賦給新對象(因此this就指向一這個新對象); c.執行構造函數中的代碼(為這個新對象添加屬性); d.返回新對象(默認返回當前對象,除非有顯示返回某個對象)
優缺點:
首先是解決了工廠模式中不能判斷類型的問題; 但缺點是每實例一次的同時還會把方法重新創建一遍,造成內存資源浪費; 其次,因構造函數與其它函數的唯一區別就是調用方式不一樣,所以當被當作普通函數調用時,其內部的this會指向全局,引發作用域問題。(6).原型模式
function Person(){}; // 寫法一: Person.prototype.name="nagi"; Person.prototype.job="sleep"; Person.prototype.sayName=function(){ console.log(this.name); }; // 寫法二:注意,這種直接更改原型指向的寫法,會改變constructor指向,指向Object構造函數 /* Person.prototype={ // constructor:Person, name:"nagi", job:"sleep", sayName:function (){ console.log(this.name) } }*/ let p1=new Person();
優缺點:
優點:解決了上述構造函數的缺點,原型對象上的屬性和方法為所有實例所共享。 缺點: a.缺點也是所有實例共享方法和屬性,因此其中一個實例更改了引用類型的屬性值時,其他的實例也會被迫改變。(屬性) b.默認情況下所有實例都取得相同的屬性值。(7).組合模式(結合構造函數和原型模式)
function Person(name,job){ this.name=name; this.job=job; } Person.prototype.sayName=function(){ console.log(this.name); } let p1=new Person("nagi","sleep");4.對象繼承方式有哪些? (1).原型鏈繼承
function Parent(){ this.name="nagi"; this.colors=["red","blue","green"]; } Parent.prototype.sayName=function(){ console.log(this.name); } function Child(){ this.job="sleep"; }; Child.prototype=new Parent(); // 要注意:這種重寫原型鏈的寫法是會切斷構造函數與最初原型之間的聯系的, // 意味著此時Child.prototype.constructor指向Parent var child=new Child();
這種方式的基本思想就是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。
問題點:
a.上述例子中,通過原型繼承方式繼承相當于專門創建了一個Child.prototype.colors的屬性, 因為引用類型的原型屬性會被所有實例共享,也就意味著Child的所有實例都會共享colors這一屬性, 當其中一實例修改它的值時,那么其他的實例的值也會跟著被改變。 b.在創建子類實例時,不能向超類型的構造函數中傳遞參數。鑒于此,實際很少多帶帶用原型鏈繼承。
超類型:比如Child類繼承了Parent類的屬性,那么Parent就是Child的超類(也叫父類)。(2).構造函數繼承(call/apply)
function Parent(name){ console.log(`子類傳進的name值是:${name}`) this.name="nagi"; this.colors=["red","blue","green"]; } Parent.prototype.sayName=function(){ console.log(this.name); } function Child(){ Parent.call(this,"Bob") this.job="sleep"; }; var child1=new Child(); var child2=new Child();
基本思想是在子類構造函數的內部調用超類(或父類)型構造函數。
優缺點:
優勢:解決了原型鏈的兩個問題; 缺點: a. 方法都在構造函數定義的話,那函數復用就無從談起了。 b. 父類在原型中定義的方法,對于子類型來說是不可見的。鑒于此,構造函數也很少用。[捂臉](3).組合繼承(即原型鏈+構造函數)
function Parent(name){ this.name=name; this.job="sleep"; this.colors=["red","blue","green"]; } Parent.prototype.sayName=function(){ console.log(this.name); } function Child(name){ Parent.call(this,name); this.job="eat"; } Child.prototype=new Parent(); Child.prototype.constructor=Child; let child1=new Child("nagi"); let child2=new Child("Bob");
其實現思路是用原型鏈實現對原型屬性和方法的繼承,而借助構造函數實現對實例屬性的繼承。 優點:在前兩者基礎上,補足了構造函數和原型鏈的缺點,是比較常用的方式。(4). Object.create繼承
function Parent(name){ this.name=name; this.job="sleep"; this.colors=["red","blue","green"]; } Parent.prototype.sayName=function(){ console.log(this.name); } function Child(){ Parent.call(this); // 保證構造函數指針指向Child } Child.prototype=Object.create(Parent.prototype,{name:{value:"nagi"},job:{value:"eat"}}) // 如果想同時繼承多個,還可使用Object.assign()添加屬性 // Object.assign(A.prototype, B.prototype); let child=new Child();(5)ES6的extends方式
類繼承,class A extends B
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99321.html
摘要:構造函數通常首字母大寫,用于區分普通函數。這種關系常被稱為原型鏈,它解釋了為何一個對象會擁有定義在其他對象中的屬性和方法。中所有的對象,都有一個屬性,指向實例對象的構造函數原型由于是個非標準屬性,因此只有和兩個瀏覽器支持,標準方法是。 從這篇文章開始,復習 MDN 中級教程 的內容了,在初級教程中,我和大家分享了一些比較簡單基礎的知識點,并放在我的 【Cute-JavaScript】系...
摘要:組合構造原型模式將自身屬性于構造函數中定義,公用的方法綁定至原型對象上原型對象的解釋每一個函數創建時本身內部會有一個固有的原型對象,可以通過函數名去訪問,而其原型對象又有一個屬性指針指向該函數。 每次遇到JS面對對象這個概念,關于繼承及原型,腦海里大概有個知識框架,但是很不系統化,復習下,將其系統化,內容涉及到對象的創建,原型鏈,以及繼承。 創建對象 兩種常用方式,其余的比較少見工廠模...
摘要:所以繼承了對象的所有方法,當你用時,會先查一下它的構造函數的原型對象有沒有有方法,沒查到的話繼續查一下的原型對象有沒有這個方法。 普通函數與構造函數的區別 在命名規則上,構造函數一般是首字母大寫,普通函數遵照小駝峰式命名法。 在函數調用的時候: function fn() { } 構造函數:1. new fn( ) 2 .構造函數內部會...
閱讀 2285·2021-11-15 11:37
閱讀 2954·2021-09-01 10:41
閱讀 787·2019-12-27 11:58
閱讀 747·2019-08-30 15:54
閱讀 715·2019-08-30 13:52
閱讀 2930·2019-08-29 12:22
閱讀 1075·2019-08-28 18:27
閱讀 1452·2019-08-26 18:42