整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          這篇文章,讓你了解 JavaScript 中的原型(

          這篇文章,讓你了解 JavaScript 中的原型(基礎篇-圖文)

          avaScript - Prototype

          JavaScript是一門動態語言, 你可以在任何時候向對象上添加屬性,如下

          function Student() {
           this.name='LeBron James';
           this.gender='Male';
           }
           var studObj1=new Student();
           studObj1.age=15;
           alert(studObj1.age); // 15
           var studObj2=new Student();
           alert(studObj2.age); // undefined
          

          正如上面的實例, age 屬性附加在 studObj1 實例上. 然而 studObj2 實例沒有這個屬性, 因為 age 屬性只在 studObj1 實例上定義了.

          那么, 如果想在后期添加一個屬性且能被所有的實例所共享, 該怎么辦? 答案這就今天主角 Prototype.

          Prototype 是一個對象, 默認情況下與JavaScript中的任何一個函數或對象有關, 只是唯一區別在于函數的prototype 屬性是可訪問和可修改的,而對象的prototype屬性是不可見的.

          默認情況下任何一個函數包含 Prototype 對象, 如下圖:

          prototype 對象是一種特殊類型的可枚舉對象, 可以將需要附加屬添加到其上,這些屬性將在其構造函數的所有實例之間共享。

          我自己是一名從事了多年開發的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年年初我花了一個月整理了一份最適合2019年學習的web前端學習干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關注我的頭條號并在后臺私信我:前端,即可免費獲取。

          因此, 把上面的示例中使用函數的 prototype 來添加屬性,以便于所有對象中都可以訪問到, 如下:

          function Student() {
           this.name='LeBron James';
           this.gender='M';
           }
           Student.prototype.age=15;
           var studObj1=new Student();
           alert(studObj1.age); // 15
           var studObj2=new Student();
           alert(studObj2.age); // 15
          

          使用 字面量 或 通過 new關鍵字和構造函數 的方式創建的每一個對象都包含 __proto__ 屬性, 該屬性指向創建此對象的函數的 原型對象.

          你可以在谷歌和火狐開發者調試工具中查看該屬性(__proto__) , 根據下面的示例:

          function Student() {
           this.name='LeBron James';
           this.gender='M';
           }
           var studObj=new Student();
           console.log(Student.prototype); // object
           console.log(studObj.prototype); // undefined
           console.log(studObj.__proto__); // object
           console.log(typeof Student.prototype); // object
           console.log(typeof studObj.__proto__); // object
           console.log(Student.prototype===studObj.__proto__ ); // true
          

          正如上面例子看到, 函數通過 [[函數名稱]].prototype 方式訪問到原型對象. 但是, 對象(實例)并沒有暴露出 prototype 屬性,而是使用 __proto__ 來訪問它.

          Object 對象的原型

          前面提及到, 原型對象在對象中是不可見. 使用 Object.getPrototypeOf(obj) 方法來訪問實例的原型對象. (這也是推薦方式, __proto__ 并不是標準屬性, 在IE11以下其它瀏覽器中沒有實現).

          function Student() {
           this.name='LeBron James';
           this.gender='M';
           }
           var studObj=new Student();
           Student.prototype.sayHi=function(){
           alert("Hi");
           };
           var studObj1=new Student();
           var proto=Object.getPrototypeOf(studObj1); 
           // returns Student's prototype object
           
           alert(proto.constructor); 
           // returns Student function 
          

          Object 原型對象包含如下 屬性 和 方法

          屬性描述constructor返回創建該實例的構造函數__proto__指向創建該實例的構造函數的原型對象.方法描述hasOwnProperty()返回一個布爾值,指示對象是否包含指定的屬性作為該對象的直接屬性,而不是通過原型鏈繼承。isPrototypeOf()返回一個布爾值,指示指定的對象是否位于調用此方法的對象的原型鏈中。propertyIsEnumerable()返回一個布爾值,該布爾值指示指定的屬性是否可枚舉。toLocaleString()返回本地格式的字符串.toString()返回對象字符串形式.valueOf()返回指定對象的原始值.

          Chrome 和 Firfox 將對象的原型表示為 __proto__, 而內部引用為 [[Prototype]]. IE不支持,只有IE11包含它.

          修改原型

          如上所述, 每個對象都能鏈接到函數的原型對象. 如果您更改了函數的原型, 則只有新對象將鏈接到更改后的原型. 所有其他現有對象仍然鏈接到舊的函數原型. 下面實例來演示這個場景:

          function Student() {
           this.name='LeBron James';
           this.gender='M';
           }
           Student.prototype.age=15;
           var studObj1=new Student();
           alert('studObj1.age=' + studObj1.age); // 15
           var studObj2=new Student();
           alert('studObj2.age=' + studObj2.age); // 15
           Student.prototype={ age : 20 };
           var studObj3=new Student();
           alert('studObj3.age=' + studObj3.age); // 20
           alert('studObj1.age=' + studObj1.age); // 15
           alert('studObj2.age=' + studObj2.age); // 15
          

          使用原型

          原型對象被JavaScript引擎用來做兩件事:

          • 查找對象的屬性和方法在JavaScript中實現繼承
          function Student() {
           this.name='LeBron James';
           this.gender='M';
           }
           Student.prototype.sayHi=function(){
           alert("Hi");
           };
           var studObj=new Student();
           studObj.toString();
          

          在上面的示例, toString() 方法在 Student 中沒有定義, 那么它是如何以及從哪里找到 toString() 的呢?

          在這里,原型出現了. 首先, JavaScript 引擎檢查 studObj 是否存在 toString 方法?. 如果沒有找到,那么它使用 studObj 的 __proto__ 鏈接指向 Student函數 的 原型對象. 如果它仍然無法找到它那么它會在往上層并檢查 Object 函數的原型對象,因為所有對象都是從 JavaScript 中的 Object 派生的,并查找 toString() 方法. 因此, 它在Object函數的原型對象中找到 toString()方法,因此我們可以調用 studObj.toString().

          查找方式,如下圖所示

          上述就是原型基本知識點以及應用.

          原作者姓名:任重道遠

          原出處:SenmentFault

          原文鏈接:人類身份驗證 - SegmentFault

          接修改原型可能會影響所有繼承自 HTMLElement 的元素,因此需要謹慎操作。

          以下是一個簡單的示例,展示如何在 HTMLElement 的原型上添加一個新的方法:



          // 添加一個新的方法到 HTMLElement 的原型
          HTMLElement.prototype.sayHello=function() {
          console.log(`Hello from ${this.tagName}`);
          };
          // 使用新的方法
          document.body.sayHello(); // 輸出: Hello from BODY

          不過,更推薦的方式是使用 自定義元素 來擴展功能,這樣可以避免對全局原型的修改,減少潛在的沖突和問題。 通過繼承 HTMLElement 來創建自定義元素:

          理解原型鏈,繞不開constructor、prototype、__proto__這幾個核心的知識點,它們的關系如下:

          上面的圖是一個最簡單的原型鏈,先有一個直觀的認識。下面將圍繞上面3個點一步步對原型鏈抽絲剝繭,最后在來總結究竟什么是原型鏈,自然就清晰了。

          2. 課前預習

          再正式進入主題之前,先了解幾個知識點

          2.1 函數對象與普通對象

          JavaScript 中,萬物皆對象,但對象也是有區別的。分為普通對象和函數對象, Object 、Function 是 JS 自帶的函數對象

          • 函數對象
          //f1,f2,歸根結底都是通過 new Function()的方式進行創建的
          function f1(){};//console.log(typeof f1)==function 
          var f2=function(){};//同上
          var f3=new Function('str','console.log(str)');//同上
          • 普通對象
          var o1={}; // console.log(typeof o1)==object 
          var o2=new Object();//同上
          var o3=new f1();//同上

          簡單的說,凡是使用 function 關鍵字或 Function 構造函數創建的對象都是函數對象,其他的都是普通對象

          2.2 幾個專業術語

          • 顯式原型:prototype
          • 隱式原型:__ proto __
          • 原型對象:每個函數對象都有一個prototype 屬性,這個屬性指向函數的原型對象

          3. prototype和contructor

          • prototype指向函數的 原型對象 ,只有函數或者說函數對象才擁有該屬性。
          • contructor指向原型對象的構造函數。

          可能很多人對什么是原型對象比較迷惑,個人是按照下面的模版記得:

          原型對象=構造函數名.prototype

          //Person.prototype就是原型對象
          function Person() {}
          Person.prototype={
             name:  'Zaxlct',
             sayName: function() {
             }
          }

          3.1 prototype和contructor關系

          主要從三個緯度來分析:自定義的構造函數(Person)、Object函數、Function函數

          // 可以思考一下打印結果
          function Person() {}
          console.log(Person.prototype)//[object Object]
          console.log(Person.prototype.constructor)//function Person() {}

          3.2 prototype創建時機

          在定義函數時自動添加的, 默認值是一個空Object對象

          //定義構造函數
          function Fn() {   // 內部語句: this.prototype={}
          }

          3.3 prototype作用

          • 通過給 Person.prototype 設置屬性和方法之后,Person 的實例都會繼承相應的屬性和方法,所有的實列例共享一份,不會開辟新的空間。
          • prototype用來實現基于原型的繼承與屬性的共享

          4. proto

          JS 在創建對象(不論是普通對象還是函數對象)的時候,都有一個叫做__proto__ 的內置屬性,用于指向創建它的構造函數的原型對象。

          由于js中是沒有類的概念,而為了實現繼承,通過 __ proto __ 將對象和原型聯系起來組成原型鏈,就可以讓對象訪問到不屬于自己的屬性。

          4.1 函數和對象的關系

          所有函數都是Function的實例(包含Function),所有構造器都繼承了Function.prototype的屬性及方法。

          4.2 原型對象間的關系

          所有的原型對象__proto__最終指向了Object.prototype(除了Object.prototype的__proto__之外)。

          js原型鏈最終指向的是Object原型對象

          4.3 proto創建時機

          對象的__proto__屬性: 創建對象時自動添加的, 默認值為構造函數的prototype屬性值

          function Fn() {  } 
          // 內部語句: this.__proto__=Fn.prototype
          var fn=new Fn()  

          4.4 總結

          • 當你new一個構造函數的時候,創建一個函數實例,那么 『 函數實例.__ proto __===該構造函數.prototype 』
          • 所有的函數都是由Function構造出來的,那么 『被構造出來的其他函數.__ proto __===Function.prototype 』
          • 所有的構造函數的原型對象都是由Object構造出來的,那么 『所有的構造函數.prototype.__ proto __===Object.prototype 』

          5. 完整原型鏈結構圖

          • 所有的實例對象都有__proto__屬性, 它指向的就是原型對象
          • 這樣通過__proto__屬性就形成了一個鏈的結構---->原型鏈
          • 當查找對象內部的屬性方法時, js引擎自動沿著這個原型鏈查找
          • 當給對象屬性賦值時不會使用原型鏈, 而只是在當前對象中進行操作

          6. 原型鏈的查找和內存表現

          function Person() {
              this.test1=function () {
                console.log('test1()')
              }
            }
            console.log(Person.prototype)
            Person.prototype.test2=function () {
              console.log('test2()')
            }
            Object.prototype.test3=function () {
              console.log('test3()')
            }
            const  personObj=new Person()
            personObj.test1()//test1
            personObj.test2()//test2
            personObj.test3()//test3
            

          對應到內存中的原型鏈如下圖:

          7.總結

          • 顯式原型與隱式原型的關系函數的prototype: 定義函數時被自動賦值, 值默認為{}, 即用為原型對象實例對象的__proto__: 在創建實例對象時被自動添加, 并賦值為構造函數的prototype值原型對象即為當前實例對象的父對象
          • 原型鏈的作用避免相同函數重復聲明,減少空間占用,節省內存實現繼承構造函數的所有實例都可以訪問構造函數原型中的方法和屬性

          主站蜘蛛池模板: 一区二区乱子伦在线播放| 人妻内射一区二区在线视频| 日韩免费无码视频一区二区三区 | 亚洲AV午夜福利精品一区二区 | 无码少妇精品一区二区免费动态| 久久精品视频一区| 曰韩人妻无码一区二区三区综合部 | 国产成人综合一区精品| 亚洲日韩一区精品射精| 国产一区精品视频| 一区二区三区免费视频播放器 | 亚洲综合一区二区精品久久| 少妇无码一区二区三区免费| 成人在线观看一区| 精品一区二区三区在线视频观看| 国产成人精品无码一区二区三区| 国产美女一区二区三区| 色多多免费视频观看区一区| 无码一区二区三区在线观看| 蜜桃AV抽搐高潮一区二区| 国产一区二区三区夜色| 中文字幕精品一区二区日本| 精品一区二区三区四区电影| 亚洲国产成人一区二区精品区| 午夜性色一区二区三区不卡视频| 丝袜美腿高跟呻吟高潮一区| 无码av免费毛片一区二区| 极品少妇伦理一区二区| 麻豆文化传媒精品一区二区 | 日本不卡一区二区三区视频| 国产成人精品一区二区A片带套| 亚洲老妈激情一区二区三区| 无码av中文一区二区三区桃花岛 | 久久人妻无码一区二区| 久久国产香蕉一区精品| 手机福利视频一区二区| 78成人精品电影在线播放日韩精品电影一区亚洲 | 国产成人一区二区三区精品久久| 久久精品国产一区二区三区肥胖| 国产嫖妓一区二区三区无码| 日韩免费一区二区三区在线播放|