日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

“约见”面试官系列之常见面试题第四十二篇之原型和原型链(建议收藏)

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 “约见”面试官系列之常见面试题第四十二篇之原型和原型链(建议收藏) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原型和原型鏈的理解:(面試題)

  • 原型:每個函數都有 prototype 屬性,該屬性指向原型對象;使用原型對象的好處是所有對象實例共享它所包含的屬性和方法。
  • 原型鏈:主要解決了繼承的問題;每個對象都擁有一個原型對象,通過__proto__ 指針指向其原型對象,并從中繼承方法和屬性,同時原型對象也可能擁有原型,這樣一層一層,最終指向 null。

原型的作用:
1.數據共享 節約內存內存空間
2.實現繼承
注意:函數也是一個對象,對象不一定是函數。(對象有__proto__屬性,函數有prototype屬性)此處說明,方便大家理解下文。
下面我將舉例說明為什么要使用原型
例1:

function Person(name) {this.name=name;this.eat=function () {console.log(this.name+"吃東西");}this.sleep=function () {console.log(this.name+"睡覺");}}var p1=new Person("小明");p1.eat();//小明吃東西p1.sleep();//小明睡覺var p2=new Person("小利");p2.eat();//小利吃東西p2.sleep();//小利睡覺console.dir(p1);//dir()打印結構console.dir(p2);

每次使用構造函數Person()實例化出對象的時候,就會給每個實例對象的eat()方法和sleep()方法開辟空間??墒钱攲嵗S多對象的時候,就會浪費大量的空間,因為每個實例對象的eat()方法和sleep()的功能都是一樣的,所以我們沒必要為每個實例對象添加eat()方法和sleep()方法。

這時原型就派上用場了,看下面經過改造的例子:
?

function Person(name) {this.name=name;}Person.prototype.eat=function () {console.log(this.name+"吃東西");};Person.prototype.sleep=function () {console.log(this.name+"睡覺");}var p1=new Person("小明");p1.eat();//小明吃東西p1.sleep();//小明睡覺var p2=new Person("小利");p2.eat();//小利吃東西p2.sleep();//小利睡覺console.dir(p1);console.dir(p2);

eat()方法和sleep()被添加到了Person()構造函數的原型(prototype)上了。因此只有一份eat()方法和sleep()方法。當實例對象需要使用這些方法的時候就在自己的__proto__屬性中找到并調用這些方法實現相應的功能。

現在我們來捋一下構造函數,實例對象,原型對象之間的關系。

如以下代碼和圖所示:

Person()構造函數的prototype屬性是一個對象,實例對象p1的__proto__屬性也是一個對象,并且prototype對象和__proto__對象的指向相同。那么我們再回過頭來理解一下為什么添加到原型的方法可以是共享的。因為prototype對象和__proto__對象的指向相同,所以將eat()方法和sleep()添加到Person()構造函數的prototype屬性上之后,實例對象就可以通過自己__proto__屬性去訪問eat()方法和sleep()了。

console.dir(Person);console.dir(p1);console.log(typeof p1.__proto__);//objectconsole.log(typeof Person.prototype);//objectconsole.log(p1.__proto__ === Person.prototype);//true

__proto__指向該對象所在的構造函數的原型對象。

實例對象和構造函數之間沒用直接的關系。原型對象與實例對象之間用原型(__proto__)關聯,這種關系叫做原型鏈。

我是這樣理解原型鏈的(可能不是很準確)我向我爸要零花錢,我爸也沒有錢,那么我就向我奶奶要,奶奶要是也沒有,就繼續找別人要。

那么原型的指向可以改變嗎?答案是可以的。

舉個例子:
?

?
  • function Person(name) {

  • this.name=name;

  • }

  • Person.prototype.eat=function () {

  • console.log(this.name+"吃東西");

  • };

  • Person.prototype.sleep=function () {

  • console.log(this.name+"睡覺");

  • }

  • function Student(school) {

  • this.school=school;

  • }

  • Student.prototype.write=function () {

  • console.log("寫作業");

  • }

  • Student.prototype=new Person("小華");//改變Student()構造函數的指向,讓Student()構造函數的原型對象指向Person的實例對象

  • var s1=new Student("某某高中");

  • s1.eat();//小華吃東西

  • s1.sleep();//小華睡覺

  • s1.write();//Uncaught TypeError: s1.write is not a function,因為Student()的原型的指向改變,所以找不到write()方法

  • console.dir(Student);

  • console.dir(s1);

  • __proto__指向該對象所在的構造函數的原型對象。如上圖所示:Studend()構造函數的原型(prototype)指向了Person()的實例對象(new Person("小華")),所以Studend()的實例對象s1的__proto__也指向了Person()的實例對象((new Person("小華"))。而實例對象((new Person("小華"))的__proto__指向了其所在的構造函數Person()的原型對象在這個原型對象中,找到了eat()方法和sleep()方法。

    從這個例子中,可以發現,利用原型可以實現繼承。面向對象的編程語言中有(class)類的概念,但是JavaScript不是面向對象的語言,所以js中沒有類(class)(ES6中實現了class),但是js可以模擬面向對象的思想編程,js中通過構造函數來模擬類的概念。

    改變原型的指向可以實現方法的繼承。借用構造函數繼承,主要解決屬性的問題
    ?

    function Person(name) {this.name=name;}Person.prototype.eat=function () {console.log(this.name+"吃東西");};Person.prototype.sleep=function () {console.log(this.name+"睡覺");}function Student(name,school) {//name為父類構造器傳參。子類構造器可以添加自己特有的屬性schoolPerson.call(this,name);//調用父類構造器Person的屬性,this.school=school;}Student.prototype.write=function () {console.log("寫作業");}Student.prototype=new Person();//改變Student()構造函數的指向,讓Student()構造函數的原型對象指向Person的實例對象var s1=new Student("zx","某某高中");s1.eat();//小華吃東西s1.sleep();//小華睡覺console.dir(Student);console.dir(s1);

    組合繼承就是指:將改變原型的指向和借用構造函數兩者結合在一起實現繼承。?

    一、原型模式

    我們創建的每一個函數都有一個prototype(原型)屬性,這個屬性指向的是通過調用構造函數來創建出來的對象實例原型對象,這個原型對象可以讓所有對象實例共享它所包含的屬性和方法。

    function Person () {}Person.prototype.name = "xiao";Person.prototype.sayName = function () {alert('this.name')}var person1 = new Person();var person2 = new Person();person1.sayName()console.log(person1.name == person2.name) // "true"

    上面的例子當中我們創建了一個構造函數Person,并通過它的prototype屬性在它的原型對象中定義了name屬性并賦值,然后通過調用構造函數Person實例化出來兩個對象實例,通過打印出來的值我們可以得知,person1和person2共享了原型對象中的屬性和方法。

    構造函數,原型對象和對象實例的關系

    我們知道每個函數都有一個prototype屬性指向函數的原型對象。在默認情況下,所有原型對象都有一個constructor(構造函數)屬性,這個屬性指向了prototype屬性所在的函數,比如前面的例子中,Person.prototype.constructor就指向Person。
    另外,當調用構造函數創建一個新實例后,該實例的內部將包含一個__porto__屬性(僅在Firefox、Safari、Chrome中支持),這個屬性指向的就是構造函數的原型對象。由此我們可以得出以下圖示的結論:

    通過代碼來驗證:

    # 實例和原型對象之間的關系console.log(person.__proto__ == Person.prototype) // true# 也可以通過isPrototypeOf()和ES5中的Object.getPrototypeOf()方法來判斷console.log(Person.prototype.isPrototypeOf(person1)) // trueconsole.log(Object.getPrototypeOf(person) === Person.prototype) // true# 原型對象和構造函數的關系console.log(Person.prototype.constructor == Person) // true

    二、原型鏈

    通過前面我們對構造函數,對象實例和原型對象三者關系的描述可知,實例都包含了指向原型對象的內部指針。
    那么假如現在我們有兩個構造函數AB,我們讓構造函數A的原型對象等于構造函數B的實例,根據前面的推論,這個時候A的原型對象就包含指向B的原型對象的指針,再假如又有一個構造函數C,讓A的原型對象等于C的實例,上述關系依舊成立,以此類推便形成了實例與原型的鏈條,即原型鏈,它主要作為JS中實現繼承的主要方法。

    原型鏈的基本實現

    function SuperType() {this.property = true;}SuperType.prototype.getSuperValue = function() {return this.property;}# 繼承了SuperTypeSubType.prototype = new SuperType();SubType.prototype.getSubValue = function() {return this.subproperty;}var instance = new SubType();console.log(instance.SuperValue()); // true

    在上面的代碼中,我們沒有使用SubType默認的原型,而是將SuperType的實例賦給它,重寫了SubType的原型對象;這樣一來SubType.prototype的內部便具有一個指向SuperType原型的指針,原來存在于SuperType的實例中的所有屬性和方法,現在也存在于SubType.prototype中了。
    instance同理,還要注意的是由于SubType的原型指向了SuperType的原型,而SuperType的原型的constructor屬性指向的是SuperType構造函數,那么instance.constructor也就指向了SuperType

    原型搜索機制:

    當訪問一個實例屬性或方法時,在通過原型鏈實現繼承的情況下,首先會在實例中搜索該屬性,在沒有找到屬性或方法時,便會沿著原型鏈繼續往上搜索,直到原型鏈末端才會停下來。
    這里還有一個重要的點,事實上所有引用類型默認都繼承了Object,而這個繼承也是通過原型鏈實現的,也就是說,所有函數的默認原型都是Object的實例,這也是所有自定義類型都會繼承toString()、valueOf()等默認方法的根本原因。

    Object.prototype的原型

    既然所有類型默認都繼承了Object,那么Object.prototype又指向哪里呢,答案是null,我們可以通過下面的代碼打印試試看:

    console.log(Object.prototype.__proto__ === null) // true

    null即沒有值,也就是說屬性或方法的查找到Object.prototype就結束了。

    本面試題為前端常考面試題,后續有機會繼續完善。我是歌謠,一個沉迷于故事的講述者。

    歡迎一起私信交流。

    “睡服“面試官系列之各系列目錄匯總(建議學習收藏)?

    總結

    以上是生活随笔為你收集整理的“约见”面试官系列之常见面试题第四十二篇之原型和原型链(建议收藏)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 天天澡天天狠天天天做 | 日日干天天操 | 亚洲中文字幕一区 | 日韩黄网 | 91九色丨porny丨国产jk | 成人入口 | 91黄色片 | 久久精彩免费视频 | www.-级毛片线天内射视视 | 亚洲是色 | 亚洲性免费 | av秋霞 | 亚瑟av| 女人的av| 亚洲a在线观看 | 午夜毛片视频 | 国产欧美在线精品日韩 | 夜夜艹 | 在线观看污污视频 | 久久久国产精品一区 | 国产精品久久国产精品99 | 欧美干 | 手机在线毛片 | 男人的天堂免费视频 | 高清av不卡| 夜夜爽夜夜叫夜夜高潮漏水 | 51ⅴ精品国产91久久久久久 | 99有精品| 天天澡天天狠天天天做 | 天天骑夜夜操 | 中文字幕亚洲第一 | 国产女主播福利 | 网站免费视频www | 99久久综合| 实拍澡堂美女洗澡av | 欧美久久影院 | 亚洲午夜精品视频 | 性生交大片免费看视频 | 亚洲伦理在线 | 午夜神马影院 | 久久成人动漫 | youjizz欧美| 久草最新 | 激情欧美在线 | 日本一区二区精品 | 久久a毛片| 成人av高清在线观看 | 亚洲熟妇一区二区三区 | 岳乳丰满一区二区三区 | 精品动漫av| 国产综合av| 好吊视频一区二区 | 黄频在线 | 日韩欧美综合在线 | 大又大粗又爽又黄少妇毛片 | 亚洲精品天堂在线观看 | 91精品国产色综合久久不卡蜜臀 | 天天综合在线观看 | 欧美变态口味重另类在线视频 | 3d动漫精品啪啪一区二区三区免费 | 免费一区视频 | 在线欧美激情 | 天天想你在线观看完整版电影高清 | 久久久久久久中文字幕 | 91肉色超薄丝袜脚交一区二区 | 欧美黑人又粗又大高潮喷水 | 噜噜色av | 最近中文字幕免费mv视频7 | 亚洲天天操 | xxxwww在线观看| 成人av在线网站 | 在线观看亚洲成人 | 性高潮久久久久久久久久 | 亚洲av永久无码精品一区二区国产 | 欲求不满在线小早川怜子 | 2019自拍偷拍 | 超碰牛牛 | 波多野吉衣伦理片 | 性欧美极品另类 | 国产综合亚洲精品一区二 | 日韩精品人妻一区二区中文字幕 | 国产毛片网 | 午夜试看120秒 | 中文字幕一区二区人妻痴汉电车 | 免费av日韩 | 久久精品国产亚洲AV黑人 | 亚洲美女视频在线观看 | 99性趣网 | 我和公激情中文字幕 | 亚洲精品国产精品乱码桃花 | 日韩黄色录像 | 国产成人精品午夜福利Av免费 | 一级特黄aaaaaa大片 | 久久久久久国产精品免费免费 | 永久免费未满 | 成人午夜视频在线播放 | 四虎影视免费永久观看在线 | 波多野结衣潜藏淫欲 | 亚洲精品www久久久久久广东 |