成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript由淺及深了解原型鏈(一)

YorkChen / 2586人閱讀

摘要:但是該方法有個(gè)缺點(diǎn)就是看不出該對象的類型,于是乎構(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對象 1.簡單理解js對象

在了解原型鏈之前,我們先要弄清楚什么是JavaScript的對象,JavaScript對象又由哪些組成。有人說一個(gè)程序就是一個(gè)世界,那么我們可以把對象稱之為這個(gè)世界的組成類型,可以是生物,植物,生活用品等等。我們在java中管這些類型叫做,但是在JavaScript中沒有類的說法,當(dāng)然ES6新標(biāo)準(zhǔn)中開始出現(xiàn)了類。但是在此之前,我們都管這些類型叫做對象。那么對象創(chuàng)建出來的實(shí)例就是就是組成該世界的各個(gè)元素,如一個(gè)人、一只小狗、一棵樹等等。這些就稱之為對象的實(shí)例。那么每種類型都有它不同的屬性和方法,同樣的JavaScript對象也是由對象屬性和對象方法組成。當(dāng)然了每個(gè)實(shí)例還可以存在與對象不一樣的方法與屬性。

var person = {
    name:"xiaoming",    //對象屬性
    sayName:function(){    //對象方法
        console.log(this.name);
    }
}
2.js對象屬性的特性

在JavaScript對象中,每個(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ù)展開了。接下來我們開始介紹對象的創(chuàng)建

二.創(chuàng)建JavaScript對象 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)建對象,然后在函數(shù)內(nèi)封裝好后返回該對象。但是該方法有個(gè)缺點(diǎn)就是看不出該對象的類型,于是乎構(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)建對象。當(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è)問題,我們在創(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ù)的原型對象。我們可以捋一捋對象,對象原型,實(shí)例這三者的關(guān)系,簡單來說,我們可以把對象想象成爸爸,那么對象原型就是爺爺,實(shí)例的話好比是兒子。爺爺有的東西(屬性、方法),每個(gè)兒子都會(huì)遺傳到的,當(dāng)然如果爸爸把爺爺?shù)臇|西修改了一下,那么到兒子手上的就是爸爸修改過的東西了(方法重寫)。當(dāng)然,兒子也算是爺爺骨肉嘛,那么兒子就會(huì)有個(gè)指針[[prototype]]指向爺爺,在Chrome、Firefox等瀏覽器上面可以用屬性__proto__可以訪問到。

那么prototype__proto__區(qū)別在哪?

這么說,簡單的說prototype是指向各自的爸爸,__proto__是指向各自的爺爺。當(dāng)然這說法只是為了更好理解這兩者是有區(qū)別的。接下來我給大家做一個(gè)圖讓大家更好的理解這兩者的區(qū)別。

這大概也是明白為什么對象實(shí)例存在個(gè)constructor指針指向?qū)ο罅?,因?yàn)閷ο笤蜕厦娲嬖谶@個(gè)屬性指向該對象,而且原型最初只包含該constructor屬性。而實(shí)例尋找屬性值的時(shí)候會(huì)向上找,先在實(shí)例中搜索該屬性,沒有的話向?qū)ο笤蛯ふ摇K宰詈笳业讲⒎祷卦撝?/strong>。這樣就能很清楚的分開prototype__proto__的區(qū)別了。prototype是對象的屬性,而__proto__是對象實(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)閷ο笤褪枪蚕韺傩耘c方法,所以所有實(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è)對象,可以為其添加方法和屬性。所以我們在實(shí)例中調(diào)用sayName并不是調(diào)用該類方法。我們還需要分清類方法與對象方法的區(qū)別。

function Person(){      //通過對象實(shí)例調(diào)用
    this.say = function(){
        console.log("我是Person對象方法");
    }
}

Person.say = function(){        //只能通過Person調(diào)用
    console.log("我是Person類方法");
}

Person.prototype.say = function(){      //通過對象實(shí)例調(diào)用
    console.log("我是Person對象原型方法");
}

到這里,也許還是會(huì)有點(diǎn)懵,為什么后面的cat1.sayName(); //"我是cat1",因?yàn)閷ο髮?shí)例方法會(huì)屏蔽掉原型的方法。我們之前說過,當(dāng)代碼讀取對象的某個(gè)屬性時(shí),它會(huì)先從該對象實(shí)例開始搜索,如果找不到再往上搜索。所以當(dāng)你定義了對象實(shí)例的方法時(shí),如果跟對象原型中的同名,那么該對象實(shí)例的方法就會(huì)屏蔽掉對象原型中的方法。所以cat1第二次輸出的是我是cat1。

到這里,我再總結(jié)一下對象原型,對象與對象實(shí)例之間的關(guān)系。

對象原型內(nèi)的方法與屬性可以供所有的對象實(shí)例訪問實(shí)現(xiàn)共享性。

對象的prototype屬性可以找到對象原型而對象實(shí)例的[[proto]]可以找到對象原型

對象實(shí)例可以重寫對象原型方法,使其屏蔽對象原型的方法

對象原型一開始只有constructor屬性該屬性指向該對象

分清對象原型方法,對象方法,對象實(shí)例方法,類方法區(qū)別。類方法不需要通過實(shí)例化對象去訪問,而其他的都要對象實(shí)例去訪問

那么到這里我們已經(jīng)弄懂了對象原型,對象與對象實(shí)例之間的關(guān)系。下面我再介紹一種簡單的原型語法。

function Cat(){
    
}
Cat.prototype = {
    name:"Tom",
    color:"灰白",
    sayName:function(){
        console.log(this.name);
    },
}

這樣我就以字面量的形式創(chuàng)建了新對象,但是有個(gè)不一樣的地方就是constructor屬性不指向Cat,因?yàn)槲覀儎?chuàng)建一個(gè)函數(shù)就會(huì)創(chuàng)建它的原型對象,原型對象里面自動(dòng)獲得constructor屬性,那么我們再這樣的情況下,重寫了整個(gè)原型對象。所以此時(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)該都是不一樣的才對,起碼正常來說,但是這樣弄得大家都一樣的話,就有問題了。這時(shí)候,聰明的人應(yīng)該都可以想到,將構(gòu)造函數(shù)模式和原型模式組合起來就可以了。

4.組合構(gòu)造函數(shù)模式和原型模式

將其組合起來,結(jié)合他們兩的優(yōu)點(diǎn),是普遍認(rèn)同度最高的對象創(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);       //[]
最后

本篇介紹了對象與對象的創(chuàng)建方法。同時(shí)引入并介紹了對象原型的概念。解析了對象原型,對象與對象實(shí)例間的關(guān)系。我們在下一篇將會(huì)解析原型鏈的概念以及對象的繼承與原型鏈的關(guān)系,帶大家敲開原型鏈的奧秘。

原創(chuàng)文章,轉(zhuǎn)載請注明出處

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94530.html

相關(guān)文章

  • JavaScript由淺及深敲開原型(二)

    摘要:不然原型鏈會(huì)斷開。喵喵喵這樣會(huì)使上一條語句失效,從而使原型鏈斷開。這是在原型鏈里面無法做到的一個(gè)功能。屬性使用借用構(gòu)造函數(shù)模式,而方法則使用原型鏈。 一、對象的繼承 1.了解原型鏈 在上一篇我們講過關(guān)于原型對象的概念,當(dāng)然如果不了解的建議去翻看第一篇文章,文末附有連接。我們知道每個(gè)對象都有各自的原型對象,那么當(dāng)我們把一個(gè)對象的實(shí)例當(dāng)做另外一個(gè)對象的原型對象。。這樣這個(gè)對象就擁有了另外一...

    Carbs 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)式編程

    摘要:函數(shù)式編程,一看這個(gè)詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對編程語言的理解更加融會(huì)貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評論0 收藏0
  • 區(qū)塊概念 That You Must Know 第四期(2)

    摘要:下圖給出一個(gè)簡單的列表圖什么是哈希和哈希值為理解挖礦的代碼機(jī)制,首先解決幾個(gè)概念。第一個(gè)就是哈希。哈希值為十六進(jìn)制表示的數(shù),且長度固定。也正是哈希值的這些特點(diǎn),賦予了其加密信息時(shí)更高的安全性。 第四期 挖礦的相關(guān)算法(2) 卡酷少Wechat:13260325501 看過(1)篇,相信你一定對挖礦的機(jī)制有了一點(diǎn)了解。那么本篇,我們來一起看一下挖礦中涉及的算法。 在本篇文章中,如果在...

    Sourcelink 評論0 收藏0
  • JavaScript 進(jìn)階之深入理解數(shù)據(jù)雙向綁定

    摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對于大多數(shù)人來說,我們更多的是在使用框架,對于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...

    sarva 評論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...

    tuniutech 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<