国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS核心知識(shí)點(diǎn)梳理——原型、繼承(上)

villainhr / 3426人閱讀

摘要:同理,原型鏈也是實(shí)現(xiàn)繼承的主要方式的只是語(yǔ)法糖。原型對(duì)象也可能擁有原型,并從中繼承方法和屬性,一層一層以此類推。利用構(gòu)造函數(shù)小明張三張三小明缺點(diǎn)每次實(shí)例化都需要復(fù)制一遍函數(shù)到實(shí)例里面。寄生構(gòu)造函數(shù)模式只有被類出來的才能用。

引言

最近又攀登了一下JS三座大山中的第二座。登山過程很酸爽,一路發(fā)現(xiàn)了許多之前沒曾注意到的美景。本著獨(dú)樂樂不如眾樂樂的原則,這里和大家分享一下。

JS的面試對(duì)象
有些人認(rèn)為 JavaScript 不是真正的面向?qū)ο蟮恼Z(yǔ)言,比如它沒有像許多面向?qū)ο蟮恼Z(yǔ)言一樣有用于創(chuàng)建class類的聲明(在 ES2015/ES6 中引入了 class 關(guān)鍵字,但那只是語(yǔ)法糖,JavaScript 仍然是基于原型的)。JavaScript 用一種稱為構(gòu)建函數(shù)的特殊函數(shù)來定義對(duì)象和它們的特征。

不像“經(jīng)典”的面向?qū)ο蟮恼Z(yǔ)言,從構(gòu)建函數(shù)創(chuàng)建的新實(shí)例的特征并非全盤復(fù)制,而是通過一個(gè)叫做原形鏈的參考鏈鏈接過去的。同理,原型鏈也是實(shí)現(xiàn)繼承的主要方式(ES6的extends只是語(yǔ)法糖)。

原型、原型鏈

一直在猶豫,到底是先講創(chuàng)建對(duì)象的方法還是先講原型。為了后面保證講創(chuàng)建對(duì)象方法的連貫性,這里還是先講講原型吧,
這里為了權(quán)威,直接就摘抄MDN的定義了

JavaScript 常被描述為一種基于原型的語(yǔ)言 (prototype-based language)——每個(gè)對(duì)象擁有一個(gè)原型對(duì)象,對(duì)象以其原型為模板、從原型繼承方法和屬性。原型對(duì)象也可能擁有原型,并從中繼承方法和屬性,一層一層、以此類推。這種關(guān)系常被稱為原型鏈 (prototype chain),它解釋了為何一個(gè)對(duì)象會(huì)擁有定義在其他對(duì)象中的屬性和方法。

準(zhǔn)確地說,這些屬性和方法定義在Object的構(gòu)造器函數(shù)(constructor functions)之上的prototype屬性上,而非對(duì)象實(shí)例本身。

這個(gè)__proto__屬性有什么用呢?在傳統(tǒng)的 OOP 中,首先定義“類”,此后創(chuàng)建對(duì)象實(shí)例時(shí),類中定義的所有屬性和方法都被復(fù)制到實(shí)例中。在 JavaScript 中并不如此復(fù)制,而是在對(duì)象實(shí)例和它的構(gòu)造器之間建立一個(gè)鏈接(它是__proto__屬性,是從構(gòu)造函數(shù)的prototype屬性派生的),之后通過上溯原型鏈,在構(gòu)造器中找到這些屬性和方法。

簡(jiǎn)單的說,就是實(shí)例對(duì)象能通過自己的__proto__屬性去訪問“類”原型(prototype)上的方法和屬性,類如果也是個(gè)實(shí)例,就會(huì)不斷往上層類的原型去訪問,直到找到

補(bǔ)充:
1.“類”的原型有一個(gè)屬性叫做constructor指向“類”
2.__proto__已被棄用,提倡使用Object.getPrototypeOf(obj)

舉例:

var arr = [1,2,3] //arr是一個(gè)實(shí)例對(duì)象(數(shù)組類Array的實(shí)例)
arr.__proto__ === Array.prototype //true  實(shí)例上都有一個(gè)__proto__屬性,指向“類”的原型
Array.prototype.__proto__ === Object.prototype //true “類”的原型也是一個(gè)Object實(shí)例,那么就一定有一個(gè)__proto__屬性,指向“類”object的原型

這里補(bǔ)充一個(gè)知識(shí)點(diǎn):
瀏覽器在在Array.prototype上內(nèi)置了pop方法,在Object.prototype上內(nèi)置了toString方法


上圖是我畫的一個(gè)原型鏈圖

[1,2,3].pop() //3
[1,2,3].toString() //"1,2,3"
[1,2,3].constructor.name //"Array" 
[1,2,3].hehe() //[1,2,3].hehe is not a function

當(dāng)我們調(diào)用pop()的時(shí)候,在實(shí)例[1,2,3]上面沒有找到該方法,則沿著原型鏈搜索"類"Array的原型,找到了pop方法并執(zhí)行,同理調(diào)用toString方法的時(shí)候,在"類"Array沒有找到則會(huì)繼續(xù)沿原型鏈向上搜索"類"Object的原型,找到toString并執(zhí)行。
當(dāng)執(zhí)行hehe方法的時(shí)候,由于“類”O(jiān)bject的原型上并沒有找到,搜索“類”O(jiān)bject的__proto__,由于執(zhí)行null,停止搜索,報(bào)錯(cuò)。

注意,[1,2,3].constructor.name顯示‘Array’不是說明實(shí)例上有constructor屬性,而是正是因?yàn)閷?shí)例上沒有,所以搜索到的原型上了,找到了constructor

類,創(chuàng)建對(duì)象的方法

怎么創(chuàng)建對(duì)象,或者說怎么模擬類。這里我就不學(xué)高程一樣,給大家介紹7種方法了,只講我覺得必須掌握的。畢竟都es6 es7了,很多方法基本都用不到,有興趣自己看高程。

利用構(gòu)造函數(shù)
 const Person = function (name) {
        this.name = name
        this.sayHi = function () {
            alert(this.name)
        }
    }
    const xm = new Person("小明")
    const zs = new Person("張三")
    zs.sayHi() //"張三"
    xm.sayHi() //"小明"

缺點(diǎn): 每次實(shí)例化都需要復(fù)制一遍函數(shù)到實(shí)例里面。但是不管是哪個(gè)實(shí)例,實(shí)際上sayHi都是相同的方法,沒必要每次實(shí)例化的時(shí)候都復(fù)制一遍,增加額外開銷。

組合使用原型和構(gòu)造函數(shù)
    //共有方法掛到原型上
    const Person = function () {
         this.name = name
    }
    Person.prototype.sayHi = function () {
            alert(this.name)
        }
    const xm = new Person("小明")
    const zs = new Person("張三")
    zs.sayHi() //"張三"
    xm.sayHi() //"小明"

缺點(diǎn):基本沒啥缺點(diǎn)了,創(chuàng)建自定義類最常見的方法,動(dòng)態(tài)原型模式也只是在這種混合模式下加了層封裝,寫到了一個(gè)函數(shù)里面,好看一點(diǎn),對(duì)提高性能并沒有卵用。

es6的類

es6的‘類’class其實(shí)就是語(yǔ)法糖

class Person {
   constructor(name) {
       this.name = name
  }
  say() {
       alert(this.name)
  }
}
const xm = new Person("小明")
const zs = new Person("張三")
zs.sayHi() //"張三"
xm.sayHi() //"小明"

在es2015-loose模式下用bable看一下編譯

"use strict";

var Person =
/*#__PURE__*/
function () {
  function Person(name) {
    this.name = name;
  }

  var _proto = Person.prototype;

  _proto.say = function say() {
    alert(this.name);
  };

  return Person;
}();

分析:嚴(yán)格模式,高級(jí)單例模式封裝了一個(gè)類,實(shí)質(zhì)就是組合使用原型和構(gòu)造函數(shù)

寄生構(gòu)造函數(shù)模式

比如現(xiàn)在需要?jiǎng)?chuàng)建一些特殊的數(shù)組,這些數(shù)組有sayContent方法,可以打印出自己的內(nèi)容。怎么創(chuàng)建出這個(gè)特殊的數(shù)組類,又不影響Array類

function specialArray() {
        var arr = new Array(...arguments)
        arr.sayContent = function () {
             console.log([...this.values()])
        }
        return arr
    }
    var arr = new specialArray("x","y","z")

這個(gè)和在數(shù)組的原型鏈上增加方法有啥區(qū)別?原型鏈上增加方法,所有數(shù)組都可以用。寄生構(gòu)造函數(shù)模式只有被specialArray類new出來的才能用。

JS世界里的關(guān)系圖

知識(shí)點(diǎn):

Object.getPrototypeOf(Function) === Function.prototype // Function是Function的實(shí)例,沒毛病

Object.getPrototypeOf(Object.prototype)

任何方法上都有prototype屬性以及__proto__屬性
任何對(duì)象上都有__proto__屬性

Function.__proto__.__proto__===Object.prototype

Object.getPrototypeOf(Object)===Function.prototype

最高級(jí)應(yīng)該就是Function.prototype了,因?yàn)?

判斷類型的方法

之前在JS核心知識(shí)點(diǎn)梳理——數(shù)據(jù)篇里面說了一下判斷判斷類型的四種方法,這里借著原型再來分析一下

1. typeof:

只能判斷基礎(chǔ)類型中的非Null,不能判斷引用數(shù)據(jù)類型(因?yàn)槿繛閛bject)它是操作符

2. instanceof:

用于測(cè)試構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在對(duì)象的原型鏈中的任何位置 風(fēng)險(xiǎn)的話有兩個(gè)

//判斷不唯一
[1,2,3] instanceof Array //true
[1,2,3] instanceof Object //true
//原型鏈可以被改寫
const a = [1,2,3]
a.__proto__ = null
a instanceof Array //false

仿寫一個(gè)instanceof,并且掛在Object.prototype上,讓所有對(duì)象都能用

//仿寫一個(gè)instance方法
    Object.prototype.instanceof = function (obj) {
        let curproto = this.__proto__
        while (!Object.is(curproto , null)){
            if(curproto === obj.prototype){
                return true
            }
            curproto = curproto.__proto__
        }
        return false
    }
   
[1,2,3].instanceof(Array) //true
[1,2,3].instanceof(Object) //true
[1,2,3].instanceof(Number) //false
[1,2,3].instanceof(Function) //false
1..instanceof(Function) //false
(1).instanceof(Number) //true
3. constructor:

constructor 這玩意已經(jīng)介紹過了,“類”的原型執(zhí)行constructor指向“類”
風(fēng)險(xiǎn)的話也是來自原型的改寫

[1,2,3].constructor.name //"Array"

// 注意下面兩種寫法區(qū)別
Person.protorype.xxx = function //為原型添加方法,默認(rèn)constructor還是在原型里
Person.protorype = { //原型都被覆蓋了,沒有constructor了,所要要手動(dòng)添加,要不然constructor判斷失效
   xxx:function
   constructor:Person
}
4.Object.prototype.toString.call(xxx)

試了下,好像這個(gè)方法也不是很準(zhǔn)
null 可以用object.is(xxx,null)代替
Array 可以用Array.isArray(xxx)代替

Object.prototype.toString.call([1,2,3])   //"[object Array]"
Object.prototype.toString.call(function(){}) //"[object Function]"
Object.prototype.toString.call(1) //"[object Number]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call({}) //"[object Object]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(true) // 特別注意 特別注意 特別注意"[object Object]"
Object.prototype.toString.call("string") //  特別注意 特別注意 特別注意 "[object Undefined]" 
in操作符

對(duì)于for in 和in 都是沿著原型鏈查找屬性是否存在,可以利用hasOwnProperty進(jìn)行相關(guān)過濾

// "in" operation test
class Person {
        constructor (name) {
            this.name = name
        }
        sayHi() {
            console.log("Hi")
        }
    }
    var p1 = new Person("小明")


"name" in p1 //true
"sayHi" in p1 //true 

for (var i in p1) {
        if (p1.hasOwnProperty(i)) {
            console.log("ownProperty:" + i)
        } else {
            console.log("prototypeProperty: " + i)
        }
    }
//"ownProperty: name"
// prototypeProperty: sayHi
總結(jié)

參照各種資料,結(jié)合自己的理解,在盡量不涉及到繼承的情況下,詳細(xì)介紹了原型及其衍生應(yīng)用。由于本人技術(shù)有限,如果有說得不對(duì)的地方,希望在評(píng)論區(qū)留言。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/109739.html

相關(guān)文章

  • JS核心識(shí)點(diǎn)梳理——原型繼承(下)

    摘要:引言上篇文章介紹原型,這篇文章接著講繼承,嘔心瀝血之作,大哥們點(diǎn)個(gè)贊呀明確一點(diǎn)并不是真正的面向?qū)ο笳Z(yǔ)言,沒有真正的類,所以我們也沒有類繼承實(shí)現(xiàn)繼承有且僅有兩種方式,和原型鏈在介紹繼承前我們先介紹下其他概念函數(shù)的三種角色一個(gè)函數(shù),有三種角色。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 上篇文章介紹原型,...

    joyqi 評(píng)論0 收藏0
  • js知識(shí)梳理4.繼承的模式探究

    摘要:而且在超類型的原型中定義的方法,對(duì)子類型而言也是不可見的,結(jié)果所有類型都只能使用構(gòu)造函數(shù)模式。在主要考慮對(duì)象而不是自定義類型和構(gòu)造函數(shù)的情況下,這個(gè)模式也不錯(cuò)。 寫在前面 注:這個(gè)系列是本人對(duì)js知識(shí)的一些梳理,其中不少內(nèi)容來自書籍:Javascript高級(jí)程序設(shè)計(jì)第三版和JavaScript權(quán)威指南第六版,感謝它們的作者和譯者。有發(fā)現(xiàn)什么問題的,歡迎留言指出。 1.原型鏈 將原型鏈作...

    wenshi11019 評(píng)論0 收藏0
  • JS核心識(shí)點(diǎn)梳理——變量篇

    摘要:核心知識(shí)點(diǎn)梳理數(shù)據(jù)篇看了一些資料,結(jié)合高程和對(duì)核心知識(shí)點(diǎn)進(jìn)行了梳理。所以,一共有種聲明變量的方法。凡是在聲明之前就使用這些變量,就會(huì)報(bào)錯(cuò)。還是那句話,建議大家掌握核心知識(shí)點(diǎn),細(xì)枝末節(jié)的東西就隨意啦。 JS核心知識(shí)點(diǎn)梳理——數(shù)據(jù)篇 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 看了一些資料,結(jié)合ES6、高程和MD...

    aristark 評(píng)論0 收藏0
  • JS核心識(shí)點(diǎn)梳理——下文、作用域、閉包、this(中)

    摘要:引言滿滿的干貨,面試必系列,參考大量資料,并集合自己的理解以及相關(guān)的面試題,對(duì)核心知識(shí)點(diǎn)中的作用域閉包上下文進(jìn)行了梳理。本篇重點(diǎn)介紹閉包和。所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 滿滿的干貨,面試必bei系列,參考大量資料,并集...

    rottengeek 評(píng)論0 收藏0
  • JS開發(fā)中函數(shù)識(shí)點(diǎn)梳理(二)

    摘要:英文原文中本來是,而翻譯成第一類公民其實(shí)就是一種比喻。所以,通過上述的結(jié)果,我們發(fā)現(xiàn)在中不管我們是用構(gòu)造函數(shù)創(chuàng)建的對(duì)象還是用本身提供的數(shù)據(jù)類型創(chuàng)建的對(duì)象都源自于。使用可以解除函數(shù)體內(nèi)代碼和函數(shù)名的耦合狀態(tài)。 作為一個(gè)Jser,不光要會(huì)用js,還要明白它的運(yùn)行原理,不然就會(huì)一直停留在表面。 函數(shù)在JavaScript中被稱作第一等公民,這個(gè)第一等公民是什么鬼?看看知乎上是怎么回答的。就像...

    appetizerio 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<