摘要:但是該方法有個(gè)缺點(diǎn)就是看不出該對(duì)象的類型,于是乎構(gòu)造函數(shù)模式應(yīng)運(yùn)而生。當(dāng)然,如果細(xì)心的朋友應(yīng)該會(huì)發(fā)現(xiàn)函數(shù)名首字母大寫了,這是約定在構(gòu)造函數(shù)時(shí)將首字母大寫。這時(shí)候,聰明的人應(yīng)該都可以想到,將構(gòu)造函數(shù)模式和原型模式組合起來就可以了。
一.什么是js對(duì)象 1.簡單理解js對(duì)象
在了解原型鏈之前,我們先要弄清楚什么是JavaScript的對(duì)象,JavaScript對(duì)象又由哪些組成。有人說一個(gè)程序就是一個(gè)世界,那么我們可以把對(duì)象稱之為這個(gè)世界的組成類型,可以是生物,植物,生活用品等等。我們?cè)?strong>java中管這些類型叫做類,但是在JavaScript中沒有類的說法,當(dāng)然ES6新標(biāo)準(zhǔn)中開始出現(xiàn)了類。但是在此之前,我們都管這些類型叫做對(duì)象。那么對(duì)象創(chuàng)建出來的實(shí)例就是就是組成該世界的各個(gè)元素,如一個(gè)人、一只小狗、一棵樹等等。這些就稱之為對(duì)象的實(shí)例。那么每種類型都有它不同的屬性和方法,同樣的JavaScript對(duì)象也是由對(duì)象屬性和對(duì)象方法組成。當(dāng)然了每個(gè)實(shí)例還可以存在與對(duì)象不一樣的方法與屬性。
var person = { name:"xiaoming", //對(duì)象屬性 sayName:function(){ //對(duì)象方法 console.log(this.name); } }2.js對(duì)象屬性的特性
在JavaScript對(duì)象中,每個(gè)屬性都有其各自的特性,比如你的性別具有不可修改的特性。那么下面簡單粗略介紹一下這幾個(gè)特性。這些特性在JavaScript中是不能直接訪問的,特性是內(nèi)部值。
[[Configurable]]: 表示能不能刪除重新定義屬性,能不能修改屬性等 默認(rèn)true
[[Enumerable]]: 表示能不能通過for-in遍歷等 默認(rèn)true
[[Writeable]]: 表示能不能修改屬性值 默認(rèn)true
[[Value]]: 表示屬性的值,寫入到這里,讀從這里讀 默認(rèn)undefined
如果要修改屬性的默認(rèn)特性,可以使用Object.defineProperty()方法,當(dāng)然在這里就不再繼續(xù)展開了。接下來我們開始介紹對(duì)象的創(chuàng)建
二.創(chuàng)建JavaScript對(duì)象 1.工廠模式function createPerson(name,sex){ let obj = new Object(); obj.name = name; obj.sex = sex; obj.sayName = function(){ console.log(this.name); } return obj; } let p1 = new createPerson("小明","男");
這就是工廠模式,在函數(shù)內(nèi)創(chuàng)建對(duì)象,然后在函數(shù)內(nèi)封裝好后返回該對(duì)象。但是該方法有個(gè)缺點(diǎn)就是看不出該對(duì)象的類型,于是乎構(gòu)造函數(shù)模式應(yīng)運(yùn)而生。
2.構(gòu)造函數(shù)模式function Cat(name,color){ this.name = name; this.color = color; this.sayName = { console.log("我是"+name+"貓"); } } let Tom = new Cat("Tom","灰白"); let HelloKity = new Cat("HelloKity","粉紅");
構(gòu)造函數(shù)模式和工廠模式的區(qū)別在于,構(gòu)造函數(shù)模式?jīng)]有用return語句,直接把屬性賦給了this語句,并且沒有顯式的創(chuàng)建對(duì)象。當(dāng)然,如果細(xì)心的朋友應(yīng)該會(huì)發(fā)現(xiàn)函數(shù)名首字母大寫了,這是約定在構(gòu)造函數(shù)時(shí)將首字母大寫。
用構(gòu)造函數(shù)創(chuàng)建新實(shí)例時(shí),必須要用new操作符。同時(shí),每個(gè)由構(gòu)造函數(shù)創(chuàng)建的實(shí)例都會(huì)有一個(gè)constructor指向該構(gòu)造函數(shù)
Tom.constructor == Cat //true
這時(shí)候我們就會(huì)想一個(gè)問題,我們?cè)趧?chuàng)建不同的Cat實(shí)例時(shí),我們就會(huì)創(chuàng)建多個(gè)不同sayName函數(shù),但是他們執(zhí)行的功能都是一樣的,這時(shí)候我們就會(huì)想要一種更優(yōu)化的方法。這時(shí),我們需要引入原型屬性(prototype)的概念了
3.原型模式我們創(chuàng)建的每個(gè)函數(shù)里面都會(huì)有個(gè)prototype屬性,這個(gè)就是原型屬性,這個(gè)屬性是個(gè)指針,指向一個(gè)該函數(shù)的原型對(duì)象。我們可以捋一捋對(duì)象,對(duì)象原型,實(shí)例這三者的關(guān)系,簡單來說,我們可以把對(duì)象想象成爸爸,那么對(duì)象原型就是爺爺,實(shí)例的話好比是兒子。爺爺有的東西(屬性、方法),每個(gè)兒子都會(huì)遺傳到的,當(dāng)然如果爸爸把爺爺?shù)臇|西修改了一下,那么到兒子手上的就是爸爸修改過的東西了(方法重寫)。當(dāng)然,兒子也算是爺爺骨肉嘛,那么兒子就會(huì)有個(gè)指針[[prototype]]指向爺爺,在Chrome、Firefox等瀏覽器上面可以用屬性__proto__可以訪問到。
那么prototype和__proto__區(qū)別在哪?
這么說,簡單的說prototype是指向各自的爸爸,__proto__是指向各自的爺爺。當(dāng)然這說法只是為了更好理解這兩者是有區(qū)別的。接下來我給大家做一個(gè)圖讓大家更好的理解這兩者的區(qū)別。
這大概也是明白為什么對(duì)象實(shí)例存在個(gè)constructor指針指向?qū)ο罅?,因?yàn)閷?duì)象原型上面存在這個(gè)屬性指向該對(duì)象,而且原型最初只包含該constructor屬性。而實(shí)例尋找屬性值的時(shí)候會(huì)向上找,先在實(shí)例中搜索該屬性,沒有的話向?qū)ο笤蛯ふ?。所以最后找到并返回該?/strong>。這樣就能很清楚的分開prototype和__proto__的區(qū)別了。prototype是對(duì)象的屬性,而__proto__是對(duì)象實(shí)例的屬性。
那么我們基本了解prototype屬性以后,我們就可以給大家說說原型模式了。
function Cat(){ } Cat.prototype.name = "Tom"; Cat.prototype.color = "灰白"; Cat.prototype.sayName = function(){ console.log(this.name); } let cat1 = new Cat(); let cat2 = new Cat(); cat1.sayName(); //"Tom" cat2.sayName(); //"Tom" console.log(cat1.color); //"灰白" console.log(cat2.color); //"灰白" //因?yàn)閷?duì)象原型是共享屬性與方法,所以所有實(shí)例都可以訪問到 //接下來玩點(diǎn)更復(fù)雜的 Cat.sayName = function(){ console.log("我是Cat"); } cat1.sayName = function(){ console.log("我是cat1"); } let cat3 = new Cat(); cat1.sayName(); //"我是cat1" cat2.sayName(); //"Tom" cat3.sayName(); //"Tom" Cat.sayName(); //"我是Cat"
這時(shí)候很多人就懵了,為什么cat3說的是"Tom",而不是輸出"我是Cat"。這是因?yàn)?Cat.sayName 這個(gè)函數(shù)是類方法,我們要注意一點(diǎn),Cat也是一個(gè)函數(shù),函數(shù)就是一個(gè)對(duì)象,可以為其添加方法和屬性。所以我們?cè)趯?shí)例中調(diào)用sayName并不是調(diào)用該類方法。我們還需要分清類方法與對(duì)象方法的區(qū)別。
function Person(){ //通過對(duì)象實(shí)例調(diào)用 this.say = function(){ console.log("我是Person對(duì)象方法"); } } Person.say = function(){ //只能通過Person調(diào)用 console.log("我是Person類方法"); } Person.prototype.say = function(){ //通過對(duì)象實(shí)例調(diào)用 console.log("我是Person對(duì)象原型方法"); }
到這里,也許還是會(huì)有點(diǎn)懵,為什么后面的cat1.sayName(); //"我是cat1",因?yàn)閷?duì)象實(shí)例方法會(huì)屏蔽掉原型的方法。我們之前說過,當(dāng)代碼讀取對(duì)象的某個(gè)屬性時(shí),它會(huì)先從該對(duì)象實(shí)例開始搜索,如果找不到再往上搜索。所以當(dāng)你定義了對(duì)象實(shí)例的方法時(shí),如果跟對(duì)象原型中的同名,那么該對(duì)象實(shí)例的方法就會(huì)屏蔽掉對(duì)象原型中的方法。所以cat1第二次輸出的是我是cat1。
到這里,我再總結(jié)一下對(duì)象原型,對(duì)象與對(duì)象實(shí)例之間的關(guān)系。對(duì)象原型內(nèi)的方法與屬性可以供所有的對(duì)象實(shí)例訪問,實(shí)現(xiàn)共享性。
對(duì)象的prototype屬性可以找到對(duì)象原型,而對(duì)象實(shí)例的[[proto]]可以找到對(duì)象原型
對(duì)象實(shí)例可以重寫對(duì)象原型方法,使其屏蔽對(duì)象原型的方法
對(duì)象原型一開始只有constructor屬性,該屬性指向該對(duì)象
分清對(duì)象原型方法,對(duì)象方法,對(duì)象實(shí)例方法,類方法區(qū)別。類方法不需要通過實(shí)例化對(duì)象去訪問,而其他的都要對(duì)象實(shí)例去訪問
那么到這里我們已經(jīng)弄懂了對(duì)象原型,對(duì)象與對(duì)象實(shí)例之間的關(guān)系。下面我再介紹一種簡單的原型語法。
function Cat(){ } Cat.prototype = { name:"Tom", color:"灰白", sayName:function(){ console.log(this.name); }, }
這樣我就以字面量的形式創(chuàng)建了新對(duì)象,但是有個(gè)不一樣的地方就是constructor屬性不指向Cat,因?yàn)槲覀儎?chuàng)建一個(gè)函數(shù)就會(huì)創(chuàng)建它的原型對(duì)象,原型對(duì)象里面自動(dòng)獲得constructor屬性,那么我們?cè)龠@樣的情況下,重寫了整個(gè)原型對(duì)象。所以此時(shí)的constructor屬性指向了Object。那么我們?nèi)绻且@個(gè)屬性怎么辦?很好辦,我們自己給它加上就好。
function Cat(){ } Cat.prototype = { constructor:"Cat", name:"Tom", color:"灰白", sayName:function(){ console.log(this.name); }, }
最后我們講一下原型模式的缺點(diǎn),原型模式的缺點(diǎn)也很明顯,就是它的共享性。成也共享敗也共享。這讓我突然想起共享單車。廢話不多說,直接擼碼上來
function Cat(){ } Cat.prototype.name = "Tom"; Cat.prototype.color = "灰白"; Cat.prototype.catchMouse = ["Jerry"]; Cat.prototype.sayName = function(){ console.log(this.name); } let cat1 = new Cat(); let cat2 = new Cat(); cat1.catchMouse.push("Mickey"); console.log(cat1.catchMouse); //["Jerry", "Mickey"] console.log(cat2.catchMouse); //["Jerry", "Mickey"]
因?yàn)樵蜕厦娴膶傩允撬袑?shí)例都可以訪問的,那么當(dāng)添加往catchMouse屬性添加一個(gè)值時(shí),所有實(shí)例皆可以訪問到該屬性。這就讓人們很頭疼了,每個(gè)實(shí)例的屬性應(yīng)該都是不一樣的才對(duì),起碼正常來說,但是這樣弄得大家都一樣的話,就有問題了。這時(shí)候,聰明的人應(yīng)該都可以想到,將構(gòu)造函數(shù)模式和原型模式組合起來就可以了。
4.組合構(gòu)造函數(shù)模式和原型模式將其組合起來,結(jié)合他們兩的優(yōu)點(diǎn),是普遍認(rèn)同度最高的對(duì)象創(chuàng)建模式
function Cat(name,color){ this.name = name; this.color = color; this.catchMouse = []; } Cat.prototype.sayName = function(){ console.log(this.name); } let cat1 = new Cat("Tom","灰白"); let cat2 = new Cat("HellowKity","粉紅"); cat1.catchMouse.push("Jerry"); cat1.sayName(); //"Tom" cat2.sayName(); //"HellowKity" console.log(cat1.catchMouse); //["Jerry"] console.log(cat2.catchMouse); //[]最后
本篇介紹了對(duì)象與對(duì)象的創(chuàng)建方法。同時(shí)引入并介紹了對(duì)象原型的概念。解析了對(duì)象原型,對(duì)象與對(duì)象實(shí)例間的關(guān)系。我們?cè)谙乱黄獙?huì)解析原型鏈的概念以及對(duì)象的繼承與原型鏈的關(guān)系,帶大家敲開原型鏈的奧秘。
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/94530.html
摘要:不然原型鏈會(huì)斷開。喵喵喵這樣會(huì)使上一條語句失效,從而使原型鏈斷開。這是在原型鏈里面無法做到的一個(gè)功能。屬性使用借用構(gòu)造函數(shù)模式,而方法則使用原型鏈。 一、對(duì)象的繼承 1.了解原型鏈 在上一篇我們講過關(guān)于原型對(duì)象的概念,當(dāng)然如果不了解的建議去翻看第一篇文章,文末附有連接。我們知道每個(gè)對(duì)象都有各自的原型對(duì)象,那么當(dāng)我們把一個(gè)對(duì)象的實(shí)例當(dāng)做另外一個(gè)對(duì)象的原型對(duì)象。。這樣這個(gè)對(duì)象就擁有了另外一...
摘要:函數(shù)式編程,一看這個(gè)詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語言的理解更加融會(huì)貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...
摘要:下圖給出一個(gè)簡單的列表圖什么是哈希和哈希值為理解挖礦的代碼機(jī)制,首先解決幾個(gè)概念。第一個(gè)就是哈希。哈希值為十六進(jìn)制表示的數(shù),且長度固定。也正是哈希值的這些特點(diǎn),賦予了其加密信息時(shí)更高的安全性。 第四期 挖礦的相關(guān)算法(2) 卡酷少Wechat:13260325501 看過(1)篇,相信你一定對(duì)挖礦的機(jī)制有了一點(diǎn)了解。那么本篇,我們來一起看一下挖礦中涉及的算法。 在本篇文章中,如果在...
摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對(duì)方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對(duì)象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對(duì)象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對(duì)于大多數(shù)人來說,我們更多的是在使用框架,對(duì)于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...
閱讀 2961·2021-11-24 09:39
閱讀 3269·2021-11-19 10:00
閱讀 1609·2021-10-27 14:17
閱讀 1888·2021-10-14 09:43
閱讀 1048·2021-09-03 10:30
閱讀 3486·2019-08-30 15:54
閱讀 2818·2019-08-30 13:05
閱讀 2108·2019-08-30 11:02