成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

深入淺析js原型鏈和vue構(gòu)造函數(shù)

一、什么是原型鏈?

發(fā)展壯大離不開廣大客戶長(zhǎng)期以來的信賴與支持,我們將始終秉承“誠(chéng)信為本、服務(wù)至上”的服務(wù)理念,堅(jiān)持“二合一”的優(yōu)良服務(wù)模式,真誠(chéng)服務(wù)每家企業(yè),認(rèn)真做好每個(gè)細(xì)節(jié),不斷完善自我,成就企業(yè),實(shí)現(xiàn)共贏。行業(yè)涉及成都石雕等,在網(wǎng)站建設(shè)、成都全網(wǎng)營(yíng)銷、WAP手機(jī)網(wǎng)站、VI設(shè)計(jì)、軟件開發(fā)等項(xiàng)目上具有豐富的設(shè)計(jì)經(jīng)驗(yàn)。

深入淺析js原型鏈和vue構(gòu)造函數(shù)

簡(jiǎn)單回顧下構(gòu)造函數(shù),原型和實(shí)例的關(guān)系:

     每個(gè)構(gòu)造函數(shù)(constructor)都有一個(gè)原型對(duì)象(prototype),原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例(instance)都包含一個(gè)指向原型對(duì)象的內(nèi)部指針.

然鵝,在js對(duì)象里有這么一個(gè)規(guī)則:

如果試圖引用對(duì)象(實(shí)例instance)的某個(gè)屬性,會(huì)首先在對(duì)象內(nèi)部尋找該屬性,直至找不到,然后才在該對(duì)象的原型(instance.prototype)里去找這個(gè)屬性.

少?gòu)U話,先來看個(gè)例子:

function Fun1 () {
  this.win = "skt"
 }
 Fun1.prototype.getVal = function () {
  return this.win
 }
 function Fun2 () {
  this.other_win = "rng"
 }
 Fun2.prototype = new Fun1 ()
 Fun2.prototype.getOtherVal = function () {
  return this.other_win
 }
 let instance = new Fun2()
 console.log(instance.getVal()) //skt

在上述例子中,有一個(gè)很有意思的操作,我們讓原型對(duì)象指向了另一個(gè)類型的實(shí)例,即: constructor1.property = instance2

那么他是怎么找到instance.getVal()的?這中間又發(fā)生了什么?

1).首先會(huì)在instance1內(nèi)部屬性中找一遍;

2).接著會(huì)在instance1.__proto__(constructor1.prototype)中找一遍,而constructor1.prototype 實(shí)際上是instance2, 也就是說在instance2中尋找該屬性;

3).如果instance2中還是沒有,此時(shí)程序不會(huì)灰心,它會(huì)繼續(xù)在instance2.__proto__(constructor2.prototype)中尋找...直至Object的原型對(duì)象

    搜索軌跡: instance1--> instance2 --> constructor2.prototype…-->Object.prototype

這種搜索的軌跡,形似一條長(zhǎng)鏈, 又因prototype在這個(gè)游戲規(guī)則中充當(dāng)鏈接的作用,于是我們把這種實(shí)例與原型的鏈條稱作 原型鏈

二、prototype 和 __proto__ 都是個(gè)啥?

1.prototype是函數(shù)才有的屬性

 let fun = function () {}
 console.log(fun.prototype) // object
 console.log(fun.__proto__) // function

2.__proto__是對(duì)象具有的屬性,但__proto__不是一個(gè)規(guī)范的屬性,對(duì)應(yīng)的標(biāo)準(zhǔn)屬性是 [[Prototype]]

 let obj = {}
 console.log(obj.prototype) // underfined
 console.log(obj.__proto__) // object

我們可以把__proto__理解為構(gòu)造器的原型,大多數(shù)情況下 __proto__ === constructor.prototype      ( Object.create()除外 )

三、new又是個(gè)什么鬼?

我們都知道new是一個(gè)實(shí)例化的過程,那么他是怎么實(shí)例化的?下面我們來看一個(gè)簡(jiǎn)單的例子:

 function Fun() {
  this.team = "rng"
 }
 let f = new Fun()
 console.log(f.team) // rng

上述代碼中,我們通過new命令實(shí)例化了一個(gè)叫Fun的函數(shù)并賦值給f,這個(gè)新生成的實(shí)例對(duì)象f從構(gòu)造函數(shù)Fun中得到了team屬性,其實(shí)構(gòu)造函數(shù)內(nèi)部的this,就代表了新生成的實(shí)例對(duì)象,所以我們打印f.team的值就取到了rng這個(gè)值

這又是哪門子原理?答案如下?

1.創(chuàng)建一個(gè)空對(duì)象,作為將要返回的對(duì)象實(shí)例。
2.將這個(gè)空對(duì)象的原型,指向構(gòu)造函數(shù)的prototype屬性。
3.將這個(gè)空對(duì)象賦值給函數(shù)內(nèi)部的this關(guān)鍵字。
4.開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼

也就是說,構(gòu)造函數(shù)內(nèi)部,this指的是一個(gè)新生成的空對(duì)象,所有針對(duì)this的操作,都會(huì)發(fā)生在這個(gè)空對(duì)象上。這也是為什么構(gòu)造函數(shù)叫"構(gòu)造函數(shù)"的原因,就是操作一個(gè)空對(duì)象(即this對(duì)象),將其“構(gòu)造”為所需要的樣子。

如果我不加new呢?

 function Fun() {
  this.team = "rng"
 }
 let f = Fun()
 console.log(f) // undefined
 console.log(team) // rng

我們可以看出上面打印f為undefined,而team卻有值,這又是為什么?

其實(shí)在這種情況下,構(gòu)造函數(shù)就變成了普通的函數(shù),而且不會(huì)被實(shí)例.而此時(shí)的this指向了全局,team就變成了全局變量,因此我們?nèi)〉搅酥?/p>

四、 __proto__指向哪?

說到__proto__的指向問題,還得取決于該對(duì)象創(chuàng)建時(shí)的實(shí)現(xiàn)方式.

辣么,到底有那些實(shí)現(xiàn)方式?

1.字面量方式

 let obj = {}
 console.log(obj.__proto__) // object
 console.log(obj.__proto__ === obj.constructor.prototype) // true 證明用字面量創(chuàng)建的函數(shù),他的__proto__ 等于 該對(duì)象構(gòu)造器的原型

2.構(gòu)造器方式

 function Func () {}
 let a = new Func()
 console.log(a.__proto__) // object
 console.log(a.__proto__ === a.constructor.prototype) // true

3.Object.create()方式

 let obj1 = {name:"rng"}
 let obj2 = Object.create(obj1)
 console.log(obj2.__proto__) //{name: "rng"}
 console.log(obj2.__proto__ === obj2.constructor.prototype) // false

注: Object.create(prototype, descriptors) 創(chuàng)建一個(gè)具有指定原型且可選擇性地包含指定屬性的對(duì)象

五、如何確定原型和實(shí)例的關(guān)系?

想要確定原型和實(shí)例的關(guān)系,坦率的講,有兩種方式:  instance  和  isPrototype()

1.instanceof

我們用這個(gè)操作符來測(cè)試實(shí)例(instance)與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),如果出現(xiàn)過則返回true,反之則為false

來來來,我們來測(cè)試一下:

 function Fun1 () {
  this.laji = "uzi"
 }
 function Fun2 () {
  this.strong = "faker"
 }
 Fun2.prototype = new Fun1()

 let fun2 = new Fun2 ()

 console.log(fun2 instanceof Fun1) // true
 console.log(fun2 instanceof Fun2) // true
 console.log(fun2 instanceof Object) // true

由于原型鏈的關(guān)系,我們可以說fun2是一個(gè)對(duì)象Object,Fun1或是Fun2中任何一個(gè)類型的實(shí)例,所以這三個(gè)結(jié)果都返回了true

2.isPrototype()

這個(gè)方法同樣,只要是原型鏈中出現(xiàn)過的原型,該方法就會(huì)返回true,用法如下

 console.log(Fun1.prototype.isPrototypeOf(fun2)) // true
 console.log(Fun2.prototype.isPrototypeOf(fun2)) // true
 console.log(Object.prototype.isPrototypeOf(fun2))// true

六、原型鏈的問題

什么?原型鏈還有問題?買了佛冷,why?

原因一: 當(dāng)原型鏈中包含引用類型值的原型時(shí),該引用類型值會(huì)被所有實(shí)例共享;

原因二:在創(chuàng)建子類型時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù).

七、如何解決原型鏈問題?

1.借用構(gòu)造函數(shù),也叫經(jīng)典繼承

基本思想: 在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)

函數(shù)只是在特定環(huán)境中執(zhí)行的代碼的對(duì)象,因此通過使用 apply() 和 call() 方法也可以在(將來)新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)

看例子:

 function Father () {
  this.team = ["letme","mlxg"]
 }
 function Son () {
  Father.call(this)
 }
 let son = new Son()
 son.team.push("uzi")
 console.log(son.team)  // ["letme", "mlxg", "uzi"]
 let little_son = new Son() 
 console.log(little_son.team) // ["letme", "mlxg"]

我們可以看出,借用構(gòu)造函數(shù)一舉解決了原型鏈的兩大問題:

其一, 保證了原型鏈中引用類型值的獨(dú)立,不再被所有實(shí)例共享;

其二, 子類型創(chuàng)建時(shí)也能夠向父類型傳遞參數(shù).

但是還還還有一個(gè)問題,如果僅僅借用構(gòu)造函數(shù),那么將無法避免構(gòu)造函數(shù)模式存在的問題:

方法都在構(gòu)造函數(shù)中定義, 因此函數(shù)復(fù)用也就不可用了.而且超類型(如Father)中定義的方法,對(duì)子類型而言也是不可見的. so,借用構(gòu)造函數(shù)的技術(shù)也很少單獨(dú)使用.

2.組合繼承

組合繼承, 有時(shí)候也叫做偽經(jīng)典繼承,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮兩者優(yōu)點(diǎn)的一種繼承模式.

基本思想: 使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承.

這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能保證每個(gè)實(shí)例都有它自己的屬性.

接著看例子:

function Father (team) {
  this.team = team
  this.people = ["mlxg","letme"]
 }
 Father.prototype.sayTeam = function () {
  return console.log(this.team)
 }
 function Son (team,age) {
  this.age = age
  Father.call(this,team)
 }
 Son.prototype = new Father()
 Son.prototype.sayAge = function () {
  return console.log(this.age)
 }
 let son = new Son("faker",8)
 son.people.push("uzi")
 console.log(son.people) // ["mlxg", "letme", "uzi"]
 son.sayAge()    //8
 son.sayTeam()    // faker
 let little_son = new Son("bang",3)
 console.log(little_son.people) // ["mlxg", "letme"] 
 little_son.sayAge()    // 3
 little_son.sayTeam()   // bang

我們可以看出,組合繼承既保證了引用類型不再被所有實(shí)例所共享,也能夠讓子類型創(chuàng)建時(shí)向父類型傳參,同時(shí),原型中的方法又能夠被復(fù)用,可以說是避免了原型鏈中的兩大問題以及借用構(gòu)造函數(shù)的缺陷,因此他也是js中最常用的繼承方式,而且

instanceof 和 isPrototypeOf( )也能用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象.

3.原型繼承

基本思想: 借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象, 同時(shí)還不必因此創(chuàng)建自定義類型

繩么意思?

比如我們?cè)趂un()函數(shù)內(nèi)部, 先創(chuàng)建一個(gè)臨時(shí)性的構(gòu)造函數(shù), 然后將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回了這個(gè)臨時(shí)類型的一個(gè)新實(shí)例.

 function fun(o){
   function F(){}
   F.prototype = o;
   return new F();
  }
  let obj = {arr:[11,22]
  fun(obj).arr.push(33)
  console.log(fun(obj).arr) // [11,22,33]

在這個(gè)例子中,可以作為另一個(gè)對(duì)象基礎(chǔ)的是obj對(duì)象,于是我們把它傳入到fun()函數(shù)中,然后該函數(shù)就會(huì)返回一個(gè)新對(duì)象. 這個(gè)新對(duì)象將arr作為原型,因此它的原型中就包含引用類型值屬性. 然后我們向該屬性中又增加了一個(gè)元素,所以我們能夠?qū)⑺蛴〕鰜?/p>

       *在原型繼承中, 包含引用類型值的屬性始終都會(huì)共享相應(yīng)的值, 就像使用原型模式一樣.

4.寄生式繼承

基本思想:創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象

 function fun(o){
  function F(){}
  F.prototype = o;
  return new F();
 }
 let obj = {a:[11,22]}
 function createAnother(z) {
  // 通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
  var clone = fun(z);
  clone.sayHi = function () {
   alert("hi");
  }
  return clone;
 }
    createAnother(obj)

上面的例子中,我們把obj傳入createAnother()函數(shù)中,返回的新對(duì)象clone不僅擁有了該屬性,而且還被增強(qiáng)了,擁有了sayHi()方法;

等一下,這里要注意: 使用寄生式繼承來為對(duì)象添加函數(shù), 會(huì)由于不能做到函數(shù)復(fù)用而降低效率;這一點(diǎn)與構(gòu)造函數(shù)模式類似.

5.寄生組合式繼承

前面講過,組合繼承是 JavaScript 最常用的繼承模式; 不過, 它也有自己的不足. 組合繼承最大的問題就是無論什么情況下,都會(huì)調(diào)用兩次父類構(gòu)造函數(shù): 一次是在創(chuàng)建子類型原型的時(shí)候, 另一次是在子類型構(gòu)造函數(shù)內(nèi)部. 寄生組合式繼承就是為了降低調(diào)用父類構(gòu)造函數(shù)的開銷而誕生的

基本思想:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù)

 function inheritPrototype(subType, superType) {
  var protoType = Object.create(superType.prototype); //創(chuàng)建對(duì)象
  protoType.constructor = subType;      //增強(qiáng)對(duì)象
  subType.prototype = protoType;       //指定對(duì)象
 }
 function Father(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
 }
 Father.prototype.sayName = function () {
  console.log(this.name);
 }
 function Son(name, age) {
  Father.call(this, name);
  this.age = age;
 }
 inheritPrototype(Son, Father)
 Son.prototype.sayAge = function () {
  console.log(this.age);
 }
 var instance = new Son("uzi", 3);
 instance.sayName(); //uzi
 instance.sayAge(); //3

   inheritPrototype函數(shù)接收兩個(gè)參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。

1. 創(chuàng)建超類型原型的副本。

2. 為創(chuàng)建的副本添加constructor屬性,彌補(bǔ)因重寫原型而失去的默認(rèn)的constructor屬性

3. 將新創(chuàng)建的對(duì)象(即副本)賦值給子類型的原型

inheritPrototype的高效率體現(xiàn)在它沒有調(diào)用superClass構(gòu)造函數(shù),因此避免了在subClass.prototype上面創(chuàng)建不必要多余的屬性. 同時(shí),原型鏈還能保持不變,可以說是相當(dāng)奈斯

由于寄生組合式繼承,集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身,是實(shí)現(xiàn)基于類型繼承的最有效方法.

八.vue構(gòu)造函數(shù)

我們?cè)谑褂玫膙ue的時(shí)候,經(jīng)常會(huì)用new操作符去將他實(shí)例化,這說明vue也是一個(gè)構(gòu)造函數(shù),那么他是如何被創(chuàng)建的呢?我懷著無比激動(dòng)的心情clone了vue的源碼,仔細(xì)研究了一番

vue源碼地址

我首先找到了src/core/instance/index.js文件,打開一看,驚了

深入淺析js原型鏈和vue構(gòu)造函數(shù)

在第八行代碼中,創(chuàng)建了一個(gè)Vue的函數(shù),這不就是Vue的構(gòu)造函數(shù)么,而且在12行的警告中我更加肯定了,他說:Vue是一個(gè)構(gòu)造函數(shù),應(yīng)該使用“new”關(guān)鍵字調(diào)用
然后他在下面,他分別在

initMixin()

stateMixin()

eventsMixin()

lifecycleMixin()

renderMixin()

這五個(gè)方法中講Vue作為形參傳入,最后將Vue導(dǎo)出.

那么這五個(gè)方法是干什么的呢?我們先來看看initMixin()方法,打開./init.js文件,找到該方法

深入淺析js原型鏈和vue構(gòu)造函數(shù)

其他的代碼我們先不管,我們就看該方法的前幾行,他在Vue的原型中注入了_init方法,這個(gè)方法有點(diǎn)眼熟,我們好像在哪見過,對(duì),就是剛才的index.js文件中

深入淺析js原型鏈和vue構(gòu)造函數(shù)

這個(gè)this_init(options)看上去像是一個(gè)內(nèi)部初始化的一個(gè)方法,而option應(yīng)該就是初始化時(shí)的一些配置項(xiàng)了,在Vue被實(shí)例化的時(shí)候,this._init()方法就會(huì)執(zhí)行

接下來,我們來看一下./state.js文件,找到stateMixin方法

深入淺析js原型鏈和vue構(gòu)造函數(shù)

總結(jié)

以上所述是小編給大家介紹的js原型鏈和vue構(gòu)造函數(shù),希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!

分享文章:深入淺析js原型鏈和vue構(gòu)造函數(shù)
文章鏈接:http://jinyejixie.com/article42/ipjehc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、微信小程序、企業(yè)網(wǎng)站制作、移動(dòng)網(wǎng)站建設(shè)小程序開發(fā)、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司
叙永县| 秭归县| 德钦县| 盱眙县| 噶尔县| 诸暨市| 印江| 固始县| 民勤县| 宁德市| 察雅县| 阿尔山市| 志丹县| 松桃| 滁州市| 临沂市| 云安县| 临湘市| 红原县| 石渠县| 新蔡县| 兖州市| 资兴市| 烟台市| 临清市| 兖州市| 海门市| 南宫市| 贡山| 古丈县| 海盐县| 威宁| 当雄县| 肥乡县| 镇原县| 南安市| 娱乐| 宿迁市| 咸宁市| 伊吾县| 宁津县|