摘要:就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。構(gòu)造函數(shù)模式可以創(chuàng)建自定義引用類型,可以像創(chuàng)建內(nèi)置對(duì)象實(shí)例一樣使用操作符。
數(shù)據(jù)類型:
簡(jiǎn)單數(shù)據(jù)類型:Undefined、Null、String、Number、Boolean、Symbol 復(fù)雜數(shù)據(jù)類型:Object // Undefined:聲明,但未初始化 // Null:空對(duì)象指針
typeof操作符(檢測(cè)基本數(shù)據(jù)類型):
typeof的返回值有哪些: 1. undefined // 聲明和未初始化的變量,使用typeof都會(huì)返回Undefined 2. boolean 3. string 4. number 5. object // 當(dāng)是object、null、array時(shí) 6. function // 函數(shù)是對(duì)象,不是一種數(shù)據(jù)類型,因?yàn)樘厥猓瑃ypeof把它從對(duì)象中區(qū)分出來。typeof 正則也返回function)
typeof 的用途是檢測(cè)基本數(shù)據(jù)類型,檢測(cè)引用類型數(shù)的值時(shí),用instanceof
instanceof操作符(確定實(shí)例和原型之間關(guān)系):
如果變量是給定引用類型的實(shí)例,instanceof操作符就會(huì)返回true
例如:
person instanceof Object arr instanceof Array pattern instanceof RegExp
(經(jīng)典問題)判斷一個(gè)對(duì)象是不是數(shù)組:
value instanceof Array
Array.isArray(value)
Object.prototype.toString.call(value) // [object Array]
創(chuàng)建對(duì)象: 1. 工廠模式function createPerson(name, age) { var o = new Object() // 顯示地創(chuàng)建對(duì)象 o.name = name o.age = age o.getName = function () { console.log(this.name) } return o // 最后需要return }
其實(shí)就是寫了一個(gè)函數(shù),每次創(chuàng)建對(duì)象就是調(diào)用這個(gè)函數(shù)。
優(yōu)點(diǎn):工廠函數(shù)解決了創(chuàng)建多個(gè)類似對(duì)象的問題2. 構(gòu)造函數(shù)模式
缺點(diǎn):沒有解決對(duì)象識(shí)別問題(即怎樣知道一個(gè)對(duì)象的類型 constructor)
構(gòu)造函數(shù)可以創(chuàng)建特定類型的函數(shù),像Object、Array這樣的原生構(gòu)造函數(shù)。我們可以創(chuàng)建自定義的構(gòu)造函數(shù)
function Person(name, age) { this.name = name this.age = age this.getName = function() { console.log(this.name) } } var person1 = new Person("zhangsan", 18) var person2 = new Person("lisi", 20)
new 操作符做了什么: 1.創(chuàng)建一個(gè)新對(duì)象 2.將構(gòu)造函數(shù)的作用于賦給新對(duì)象(因此this就只想新對(duì)象) 3.執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性) 4.返回新對(duì)象
person1和person2分別保存著Person的一個(gè)不同實(shí)例,這兩個(gè)對(duì)象都有一個(gè)constructor(構(gòu)造函數(shù))屬性,該屬性指向Person
person1.constructor == Person // true person2.constructor == Person // true
對(duì)象的constructor屬性最初是用來標(biāo)識(shí)對(duì)象類別的。檢測(cè)對(duì)象類型還是用instanceof更靠譜(++確定實(shí)例和原型之間關(guān)系++)
person1 instance Person //true person1 instance Object //true
構(gòu)造函數(shù)還可以在另一個(gè)對(duì)象的作用域中調(diào)用
var o = new Object() Person.call(o, "xiaoming", 12) // 在o的作用于調(diào)用Person構(gòu)造函數(shù),o就擁有了Person所有的屬性和方法。 o.getName() // "xiaoming"
call()和apply()的第一個(gè)參數(shù)是誰,就是在誰的作用于中調(diào)用構(gòu)造函數(shù)。
優(yōu)點(diǎn):(解決了對(duì)象識(shí)別問題)創(chuàng)建自定義的構(gòu)造函數(shù)意味著將來可以將它的實(shí)例標(biāo)識(shí)為一種特定的類型(Person類),這也是構(gòu)造函數(shù)模式勝過工廠模式的地方
缺點(diǎn):構(gòu)造函數(shù)的每個(gè)方法,都要在每個(gè)實(shí)例上重新創(chuàng)建一遍。因此不同實(shí)例上的同名函數(shù)不相等。
person1.getName == person2.getName // false3. 原型模式
先理解一些概念:
我們創(chuàng)建的每個(gè)函數(shù)(例如構(gòu)造函數(shù))都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象(函數(shù)的原型對(duì)象),這個(gè)對(duì)象包含所有實(shí)例共享的屬性和方法。prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。使用原型對(duì)象的好處是可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。
例如:給構(gòu)造函數(shù)Person的原型添加屬性和方法,那實(shí)例也會(huì)共享這些屬性和方法。
function Person() {} Person.prototype.name = "zhangsan" Person.prototype.getName = function() {console.log(this.name)} var person1 = new Person() person1.getName() // "zhangsan"
每個(gè)函數(shù)都有一個(gè)prototype屬性,指向該函數(shù)的原型對(duì)象。而原型對(duì)象又有一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性是一個(gè)指向prototype屬性所在函數(shù)的指針。
例如:Person.prototype.constructor 指向 Person
當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)實(shí)例,該實(shí)例的內(nèi)部將包含一個(gè)指針_proto_,指向構(gòu)造函數(shù)的原型對(duì)象。這個(gè)連接存在于實(shí)例與構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在于實(shí)例和構(gòu)造函數(shù)之間。
Person.prototype.constructor-->Person 實(shí)例person1._proto_-->Person.prototype
Person.prototype.isPrototypeOf(person1) //true Object.getPrototypeOf(person1) == Person.prototype //true
hasOwnProperty和in:
hasOwnProperty檢測(cè)屬性存在于實(shí)例,還是原型上。只有屬性值存在于實(shí)例時(shí),才返回true
in操作符無法檢測(cè)屬性存在于實(shí)例還是原型上。只要通過對(duì)象能訪問到屬性值,就返回true
function Person() {} Person.prototype.name = "zhangsan" var person1 = new Person() person1.sex = "男" person1.hasOwnProperty("name") //false person1.hanOwnProperty("sex") //true name in person1 //true sex in person1 // true
判斷屬性僅存在于原型:
function(obj, name) { return !obj.hasOwnProperty(name) && (name in obj) }
for in和Object.keys
for in // 實(shí)例和原型上所有可枚舉的屬性(返回的是所有能夠通過對(duì)象訪問的,可枚舉的屬性) Object.keys // 僅實(shí)例上可枚舉的屬性
重寫原型(重新設(shè)定constructor):
Person.prototype = { constructor: Person, name: "zhangsan", getName: function() { console.log(this.name) } }
優(yōu)點(diǎn):共享函數(shù),不需要每次創(chuàng)建實(shí)例都重新創(chuàng)建同名函數(shù)。4. 組合使用構(gòu)造函數(shù)模式和原型模式(認(rèn)可度最高的模式)
缺點(diǎn):屬性的共享
創(chuàng)建自定義類型最常用的方式,使用最廣范、認(rèn)可度最高
集兩種模式之長:構(gòu)造函數(shù)模式用于定義實(shí)例屬性,原型模式用于定義方法和共享的屬性。這樣每個(gè)實(shí)例都有自己的一份實(shí)例屬性副本,但同時(shí)又共享著對(duì)方法的引用,最大限度地節(jié)省了內(nèi)存。
在沒有類的情況下,可以采用以下方式創(chuàng)建對(duì)象。
工廠模式:使用簡(jiǎn)單的函數(shù)創(chuàng)建對(duì)象,為對(duì)象添加屬性和方法,然后返回對(duì)象。這個(gè)模式后來被構(gòu)造函數(shù)模式所取代。
構(gòu)造函數(shù)模式:可以創(chuàng)建自定義引用類型,可以像創(chuàng)建內(nèi)置對(duì)象實(shí)例一樣使用new操作符。不過構(gòu)造函數(shù)模式也有缺點(diǎn),即他的每個(gè)成員都無法得到復(fù)用,包括函數(shù)。由于函數(shù)可以不局限于任何對(duì)象,因此沒有理由不在多個(gè)對(duì)象間共享。
原型模式:使用構(gòu)造函數(shù)的prototype屬性來指定那些應(yīng)該共享的屬性和方法。組合使用構(gòu)造函數(shù)模式和原型模式時(shí),使用構(gòu)造函數(shù)定義實(shí)例屬性,使用原型定義共享的屬性和方法。
繼承:主要依靠原型鏈來實(shí)現(xiàn)繼承
1. 原型鏈原型鏈的主要思想:利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法
先回顧下構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:
每一個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象(prototype),原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針(constructor),而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。
那么,假如我們讓原型對(duì)象等于另一個(gè)類型的實(shí)例:
function SuperType() { this.type = true } SuperType.prototype.getSuperValue = function() { return this.type } function SubType() { this.subtype = false } // 繼承了SuperType SubType.prototype = new SuperType() //實(shí)例賦值給原型的方式 SubType.prototype.getSubValue() { return this.subtype } var instance = new SubType() console.log(instance.getSuperValue()) // true
以上定義了兩個(gè)類型:SuperType和SubType。每個(gè)類型分別有一個(gè)屬性和方法。
SubType繼承了SuperType,而繼承是通過創(chuàng)建SuperType實(shí)例,并將該實(shí)例賦給SubType.prototype來實(shí)現(xiàn)的(以一個(gè)新類型的實(shí)例重寫原型對(duì)象)。因此,原來存在于SuperType的實(shí)例中的所有屬性和方法,現(xiàn)在也存在于SubType.prototype中了。
最終:instance指向SubType的原型,SubType的原型又指向SuperType的原型
當(dāng)訪問實(shí)例屬性時(shí),首先在示例中搜索該屬性,如果沒找到該屬性,則會(huì)繼續(xù)搜索實(shí)力的原型,如果還沒找到,就沿著原型鏈繼續(xù)往上找。
原型鏈的問題:
原型屬性會(huì)被所有實(shí)例所共享。此方法實(shí)現(xiàn)繼承,原型實(shí)際上變成了另一個(gè)類型的實(shí)例。SuperType的屬性就變成了SubType原型上的屬性了,就會(huì)被SubType的實(shí)例instance1、instance2等所繼承。
在創(chuàng)建子類型實(shí)例時(shí),不能向超類型實(shí)例傳遞參數(shù)。
因此實(shí)際中很少多帶帶使用原型鏈。
function SuperType() { this.colors = ["red", "blue"] } function SubType() {} SubType.prototype = new SuperType() // 繼承了SuperType var instance1 = new SubType() instance1.colors.push("black") console.log(instance.coloes) // "red", "blue", "black" var instance2 = new SubType() console.log(instance2.colors) // "red", "blue", "black"2. 借用構(gòu)造函數(shù)(經(jīng)典繼承)
基本思想: 在子類型構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)
function SuperType() { this.colors = ["red", "blue"] } function SubType() { // 繼承了SuperType SuperType.call(this) } var instance1 = new SubType() instance1.push("black") console.log(instance1.colors) //"red", "blue", "black" var instance2 = new SubType() console.log(instance2.colors) //"red", "blue"
通過使用call()方法或者apply()方法,我們實(shí)際上是在(將來)新創(chuàng)建的SubType實(shí)例的環(huán)境下調(diào)用SuperType構(gòu)造函數(shù)。
傳遞參數(shù):
function SuperType(name) { this.name = name } function SubType() { // 繼承了SuperType,同時(shí)還傳遞了參數(shù) SuperType.call(this, "zhangsan") this.age = 20 } var instance = new SubType() console.log(instance.name) // zhangsan console.log(instance.age) // 20
缺點(diǎn):和構(gòu)造函數(shù)模式存在一樣的問題,函數(shù)無法復(fù)用。3. 組合繼承(最常用的繼承模式)
原型鏈和借用構(gòu)造函數(shù)的技術(shù)結(jié)合到一塊,發(fā)揮兩者之長的繼承模式
基本思想:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。這樣既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)的復(fù)用,又能夠保證每個(gè)函數(shù)都有自己的屬性。
function SuperType(name) { this.name = name this.color = ["red", "blue"] } SuperType.prototype.getName = function() { console.log(this.name) } function SubType(name, age) { SuperType.call(this, name) // 繼承屬性 this.age = age } SubType.prototype.getAge = function() { console.log(this.age) } SubType.prototype = new SuperType() // 繼承方法 SubType.prototype.constructor = SubType var instance1 = new SubType("zhangsan", 18) instance1.colors.push("black") console.log(instance1.colors) // "red", "blue", "black" console.log(instance1.getName) // "zhangsan" console.log(instance1.getAge) // 18 var instance2 = new SubType("lisi", 20) console.log(instance2.colors) // "red", "blue" console.log(instance2.getName) // "lisi" console.log(instance2.getAge) // 20
Object.create()
javascript主要是通過原型鏈實(shí)現(xiàn)繼承。原型鏈的構(gòu)建是通過將一個(gè)類型的實(shí)例賦值給另一個(gè)構(gòu)造函數(shù)的原型實(shí)現(xiàn)的。這樣,子類型能夠訪問超類型的所有屬性和方法。原型鏈的問題是對(duì)象實(shí)例共享所有繼承的屬性和方法,因此不適合多帶帶使用。解決這個(gè)問題的技術(shù)是借用構(gòu)造函數(shù),即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。這樣就可以做到每個(gè)實(shí)例都有自己的屬性,同時(shí)還能保證只是用構(gòu)造函數(shù)模式來定義類型。使用最多的繼承模式是組合繼承,這種模式使用原型鏈繼承共享的屬性和方法,而通過借用構(gòu)造函數(shù)繼承實(shí)例屬性。
ES6: 1.創(chuàng)建對(duì)象1. class關(guān)鍵字 2. 定義屬性:constructor(xxx) { this.xxx = xxx } 3. 定義方法,方法之間不需要“;”
class Person{ // 使用class,而不是function constructor(name, age=18) { // 類的傳參 this.name = name // 定義此類的屬性 this.age = age } introduce() { // 定義方法 return `我叫${this.name},今年${this.age}歲` } sayName() { console.log(this.name) } sayAge() { console.log(this.age) } } const me = new Person("張三", 20) console.log(me.introduce())2.繼承
class Coder extends Person{ constructor(name, age, job="Html") { // 繼承父類屬性,并新加屬性 super(name, age) // 必須傳參;子類必須在constructor中調(diào)用super,否則報(bào)錯(cuò)(因?yàn)樽宇悰]有自己的this對(duì)象,而是繼承父類的this對(duì)象并對(duì)其加工,如果不調(diào)用super,子類得不到this對(duì)象) this.job = job } showJob() { // 子類的新方法 console.log(this.job) } } // 調(diào)用 const coder1 = new Coder("李四", 22, "js") coder1.sayName() coder1.showJob()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107776.html
摘要:簡(jiǎn)單回顧一下構(gòu)造函數(shù)原型和實(shí)例對(duì)象之間的關(guān)系每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象。找到生成構(gòu)造函數(shù)的原型對(duì)象的構(gòu)造函數(shù),搜索其原型對(duì)象,找到了。 JS面向?qū)ο蟮某绦蛟O(shè)計(jì)之繼承的實(shí)現(xiàn) - 原型鏈 前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方翻譯的差強(qiáng)人意,所以用自己所理解的,嘗試解讀下。如有紕漏或錯(cuò)誤,會(huì)非常感謝您的指出。文中絕大部分內(nèi)容引用自《JavaS...
摘要:構(gòu)造函數(shù)所以,就有了畸形的繼承方式原型鏈繼承三原型鏈繼承改變構(gòu)造函數(shù)的原型對(duì)象繼承了屬性以上例子中,暴露出原型鏈繼承的兩個(gè)問題包含引用類型數(shù)據(jù)的原型屬性,會(huì)被所有實(shí)例共享,基本數(shù)據(jù)類型則不會(huì)。 前言 眾所周知,JavaScript 中,沒有 JAVA 等主流語言類的概念,更沒有父子類繼承的概念,而是通過原型對(duì)象和原型鏈的方式實(shí)現(xiàn)繼承。 于是,我們這一篇講一講 JS 中的繼承(委托)。 ...
摘要:繼承了如上,我們通過方法借調(diào)了超類的構(gòu)造函數(shù),實(shí)際上是在新創(chuàng)建的實(shí)力環(huán)境下調(diào)用了構(gòu)造函數(shù)。組合繼承組合繼承的基本思想將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮二者之長的一種繼承模式。繼承方法在上面這個(gè)例子中,構(gòu)造函數(shù)定義了兩個(gè)屬性和。 在ECMAScript中只支持實(shí)現(xiàn)繼承,而且實(shí)現(xiàn)繼承主要是依靠原型鏈來實(shí)現(xiàn)的。 1. 什么是原型鏈 繼承基本思想:利用原型讓一個(gè)引用類型繼承另一個(gè)...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來。注意中,對(duì)象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來。注意中,對(duì)象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
閱讀 4077·2021-10-08 10:04
閱讀 3060·2021-08-11 11:20
閱讀 2730·2021-07-25 21:37
閱讀 2680·2019-08-30 12:44
閱讀 2306·2019-08-30 11:12
閱讀 1313·2019-08-26 13:45
閱讀 2338·2019-08-26 11:53
閱讀 3056·2019-08-26 11:32