1. 程式人生 > >再說說__proto__和prototype以及js的繼承

再說說__proto__和prototype以及js的繼承

1.__proto__和prototype

JS中的原型鏈已經是一個老生常談的問題,畢竟也是JS 這門語言的特色之一了。

這裡寫圖片描述
首先“萬物皆物件“,雖然這句話一直有爭議,但是有它的道理的,null型別這些的爭論這裡就不說了。
物件中有個屬性__proto__,被稱為隱式原型,這個隱式原型指向構造改物件的建構函式的原型,這也保證了例項能夠訪問在建構函式原型中定義的屬性和方法。這個例項可能是如圖中的new Foo()出來的例項。

構造該物件的f1,f2建構函式是fuction Foo(),它的原型是Foo.prototype,那麼f1,f2就指向了構造該物件的建構函式的原型,也就是Foo.prototype,那麼建構函式Foo()它的proto指向哪裡了,還是找它的建構函式,它的建構函式是Function(),那麼它的proto就指向了Fuction.prototype,沿著proto這條路最上就是Object.prototype,Object的proto就是null了。

剛剛說的物件有個proto屬性,方法也是物件,方法中除了有proto之外(這個proto指向構造該函式/物件的構造原型,也就是上一層了),還有prototype,這個屬性就是原型屬性,他是一個指標,指向一個物件,這個物件就叫原型物件,這裡放著包含所有例項共享的屬性和方法,這個原型物件裡面有一個屬性constructor,這個屬性也包含一個指標,指回了原建構函式。

1.建構函式Foo()建構函式的原型屬性Foo.prototype指向了原型物件,在原型物件裡有共有的方法,所有建構函式宣告的例項(這裡是f1,f2)都可以共享這個方法。

2.原型物件Foo.prototypeFoo.prototype儲存著例項共享的方法,有一個指標constructor指回建構函式。

3.例項f1和f2是Foo這個物件的兩個例項,這兩個物件也有屬性__proto__,指向建構函式的原型物件,這樣子就可以像上面1所說的訪問原型物件的所有方法。

4.建構函式Foo()除了是方法,也是物件,它也有__proto__屬性,指向誰呢?指向它的建構函式的原型物件。函式的建構函式不就是Function嘛,因此這裡的__proto__指向了Function.prototype。其實除了Foo(),Function(), Object()也是一樣的道理。原型物件也是物件,它的__proto__屬性,又指向誰呢?同理,指向它的建構函式的原型物件。這裡是Object.prototype.最後,Object.prototype的__proto__屬性指向null。

5.物件有屬性__proto__,指向該物件的建構函式的原型物件。
方法除了有屬性__proto__,還有屬性prototype,prototype指向該方法的原型物件。

6.再看圖。

2.繼承

1.父類的例項作為子類的原型

function Animal(name) {
  // 屬性
  this.name =  name || "Animal";
  // 例項方法
  this.sleep = function() {
    console.log(this.name + '正在睡覺!');
  }
}

// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃' + food);
};


function Cat() { 
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

**cat.__proto__ === Cat.prototype //true**

構造cat物件的建構函式是Cat(),它的原型是Cat.prototype,那麼隱式原型__proto__就指向構造該物件的建構函式的原型物件,那麼cat的__proto__就指向的是Cat.prototype。

**Cat.prototype.__proto__ === Animal.prototype //true**
原型物件也是物件,是物件就有__proto__,Animal的例項返回給了這個原型物件,那麼這個原型物件的隱式原型__proto__就指向的是構造該物件的建構函式的原型,我們看看這個原型物件的建構函式是誰
這裡寫圖片描述

那麼Animal()建構函式的原型物件就是Animal.prototype了。自然就有上面true的結果了。

這種方法的繼承的缺點:

  1. 父類的引用屬性和原型物件的引用屬性是所有例項共享的
  2. 建立子類例項時,無法向父類建構函式傳參
  3. 不能多繼承
    第一個致命缺點,因為我們每個例項各自的屬性互不干擾才對:
    這裡寫圖片描述

注意原型上的方法/屬性是共享的
這裡寫圖片描述

2.構造繼承

沒有用到原型,使用父類的建構函式來增強子類例項,等於直接是複製父類的例項屬性給子類。

經典繼承也叫做 “借用建構函式” 或 “偽造物件” 。其基本思想是:在子型別建構函式的內部呼叫超型別建構函式。函式只不過是在特定環境中執行程式碼的物件,因此可以通過使用apply() 和call() 方法也可以在新建立的物件上執行建構函式。(JS高程)

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特點:

解決了1中,子類例項共享父類引用屬性的問題
建立子類例項時,可以向父類傳遞引數(通過call的後面引數)
可以實現多繼承(call多個父類物件)

缺點:

例項並不是父類的例項,只是子類的例項
只能繼承父類的例項屬性和方法,不能繼承原型屬性/方法
無法實現函式複用,每個子類都有父類例項函式的副本,影響效能

3.組合繼承

通過呼叫父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現函式複用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

//組合繼承也是需要修復建構函式指向的。

Cat.prototype.constructor = Cat;

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

這種方式看似是原型繼承和構造繼承的組合,彌補了構造繼承只能繼承例項屬性/方法,不能繼承原型屬性/方法的缺點,也彌補了原型繼承引用屬性共享的問題,可向父類傳參,函式可複用,即是子類的例項,也是父類的例項。

缺點就是呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)
這裡寫圖片描述

相關推薦

再說說__proto__prototype以及js繼承

1.__proto__和prototype JS中的原型鏈已經是一個老生常談的問題,畢竟也是JS 這門語言的特色之一了。 首先“萬物皆物件“,雖然這句話一直有爭議,但是有它的道理的,null型別這些的爭論這裡就不說了。 物件中有個屬性__proto__,被稱為隱式原型,這個隱式原型指向構造改物件的建構函式的

Js__proto__prototype的區別關係

在知乎上看到了一篇寫得還挺好的文章,能夠很好的說明這兩者之間的關係,之前一直也有關注這方面的知識,但是如果重新複習一遍的話,時間久了之後就會忘記,所以前端還是需要經常複習,經常使用,經常理解。 首先,要明確幾個點: 1.在JS裡,萬物都是物件,方法(Function)是物件

js__proto__prototype的區別關係?

正好這段時間在重新看這部分,寫一篇回答來梳理一下吧。 proto(隱式原型)與prototype(顯式原型) 1.是什麼顯式原型 explicit prototype property:每一個函式在建立之後都會擁有一個名為prototype的屬性,這個屬性指向函式的原型物件。

__proto__prototype

pre 批評 理由 所有 tro text blank bar 初學 __proto__(隱式原型)與prototype(顯式原型) 每一個函數在創建之後都會擁有一個名為prototype的屬性,這個屬性指向函數的原型對象。 初學javascript的時候也

對象&內置對象& 對象構造 &JSON&__proto__prototype

false cto 但是 查找 define 常用 修改 ans man 原型是一個對象,其他對象可以通過它實現屬性繼承 原型鏈:每個對象都會在其內部初始化一個屬性,就是__proto__,當我們訪問一個對象的屬性 時,如果這個對象內部不存在這個屬性,那麽他就會去__pr

原型__proto__prototype

    1.在JS裡,萬物皆物件。方法(Function)是物件,方法的原型(Function.prototype)是物件。因此,它們都會具有物件共有的特點。即:物件具有屬性__proto__,可稱為隱式原型,一個物件的隱式原型指向構造該物件的建構函式的原型,這也保證了例項能夠訪問在建構函式

__proto__ prototype 深度剖析

為什麼要進行深度剖析 proto 和 prototype 是一個老生常談的話題,也是作為一個前端開發人員必須搞懂的問題,且不應該有任何的折扣,這是通往高階前端開發的必經之路和必備技能。雖然實際開發中用的並不多,但是當你學習一些新的js框架乃至自己封裝一些高效能的元件時是及奇有用的

Javascript中的原型鏈,__proto__prototype等問題總結

creat prototype 解釋 數據 問題總結 const style 兩個 rip 1.js中除了原始數據類型 都是對象。 包括函數也是對象,可能類似於C++函數對象把 應該是通過解釋器 進行()操作符重載或其他操作, 用的時候把它當函數用就行 但是實際上本質

js高階建構函式,例項物件原型物件——prototype__proto__constructor構造器

一、前言   瞭解JavaScript面向物件,需要先了解三個名詞: 建構函式,例項物件和原型物件。   注意:JavaScript中沒有類(class)的概念,取而代之的是建構函式,兩者類似卻又有很大的差別。   先上程式碼,最常用的: function Person(name, age) {

[JS]JS物件的內部原型(__proto__)構造器的原型(prototype)

prototype和__proto__的概念prototype是每個函式物件的一個屬性,這個屬性是一個指標,指向一個物件。它是顯示修改物件的原型的屬性,當然它的作用也是顯示修改物件的原型的屬性。__proto__是每個物件擁有的內建屬性,包含對指定物件的內部原型的引用,是JS

jsprototype 屬性用法,外加__proto__ JavaScript中__proto__prototype的關係

var ob = { };//超級簡單的空物件 alert(JSON.stringify(ob.prototype));// undefined 能夠引用prototype的東西絕對是函式,絕對是函式,絕對是函式,prototype是屬於函式的一個屬性,prototype是屬於函式的一個屬性,prototy

JS點滴】substringsubstr以及slicesplice的用法區別。

[0 相等 交換 top subst char ima cas 負數 那麽就由一道筆試題引入吧,已知有字符串a=”get-element-by-id”,寫一個function將其轉化成駝峰表示法”getElementById”; var a = "get-element-

Java繼承概述 以及Java繼承案例繼承的好處

自己 復用 dem void dsd 屬性 關鍵字 相同屬性 pre Java繼承概述 1.多個類中存在相同屬性和行為時,將這些內容抽取到單獨一個類中,那麽多個類無需再定義這些相同屬性和行為,只要繼承那個類即可。 2.在Java中通過extends關鍵字可以實現類與類的繼承

關於prototype以及__proto__的一些理解

神奇 lin 等等等 .proto ... AR func 個數字 under prototype屬性只有函數對象才擁有,可以稱之為顯性屬性; __proto__每個對象都擁有包括函數對象,而這個稱之為隱性屬性。 function Lxy (){}; //一個構造函數 v

JS檔案的**.js**.min.js的區別,以及js函式執行的順序

①**.js和**.min.js的區別 引用 Q: .js和.min.js檔案分別是什麼? A: .js是JavaScript 原始碼檔案, .min.js是壓縮版的js檔案。 Q:為什麼要壓縮為.min.js檔案? 減小體積 .min.js檔案經過壓縮,相對編譯前的js檔案體積較小

js獲取當前域名、Url、相對路徑引數以及指定引數 js獲取當前域名、Url、相對路徑引數以及指定引數

js獲取當前域名、Url、相對路徑和引數以及指定引數    一、js獲取當前域名有2種方法   二、獲取當前Url的4種方法

jQuery的檔案引入、入口函式以及js物件jquery物件之間的互相轉換

JavaScript與jquery的區別 JavaScript是一門程式語言,用來編寫客戶端瀏覽器指令碼。 jQuery是javascript的一個庫,包含多個可重用的函式,用來輔助簡化javascript開發 jQuery能做的javascript都能做到,而JavaScript能做的事情,

jQuery的文件引入、入口函數以及js對象jquery對象之間的互相轉換

現象 length 一個 cti 編寫 3.3 方法 使用 ntb JavaScript與jquery的區別 JavaScript是一門編程語言,用來編寫客戶端瀏覽器腳本。 jQuery是javascript的一個庫,包含多個可重用的函數,用來輔助簡化javascript

js中的constructorprototype

本文轉載自:https://www.cnblogs.com/zjunet/p/4559895.html 在學習JS的面向物件過程中,一直對constructor與prototype感到很迷惑,看了一些部落格與書籍,覺得自己弄明白了,現在記錄如下: 我們都知道,在JS中有一個funct

JS Jquery 中 的遍歷 $.each()$().each(),以及forEach()的用法

  $.each()和$().each(),以及forEach()的用法