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

資訊專欄INFORMATION COLUMN

Js基礎(chǔ)知識(shí)(二) - 原型鏈與繼承精彩的講解

mrcode / 386人閱讀

摘要:有了原型鏈,就有了繼承,繼承就是一個(gè)對(duì)象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問(wèn)權(quán)。這里其實(shí)就是一個(gè)原型鏈與繼承的典型例子,開(kāi)發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點(diǎn),屬性定義的多一些,但是原理都是一樣的。

作用域、原型鏈、繼承與閉包詳解
注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類(lèi)的概念,只是在寫(xiě)法上有所不同,原理是一樣的。
幾個(gè)面試常問(wèn)的幾個(gè)問(wèn)題,你是否知道

instanceof的原理

如何準(zhǔn)確判斷變量的類(lèi)型

如何寫(xiě)一個(gè)原型鏈繼承的例子

描述new一個(gè)對(duì)象的過(guò)程

也許有些同學(xué)知道這幾個(gè)問(wèn)題的答案,就會(huì)覺(jué)得很小兒科,如果你還不知道這幾個(gè)問(wèn)題的答案或者背后所涉及到的知識(shí)點(diǎn),那就好好看完下文,想必對(duì)你會(huì)有幫助。先不說(shuō)答案,下面先分析一下涉及到的知識(shí)點(diǎn)。
什么是構(gòu)造函數(shù)

JavaScript沒(méi)有類(lèi)的概念,JavaScript是一種基于對(duì)象的語(yǔ)言,除了五中值類(lèi)型(number boolean string null undefined)之外,其他的三種引用類(lèi)型(object、Array、Function)本質(zhì)上都是對(duì)象,而構(gòu)造函數(shù)其實(shí)也是普通的函數(shù),只是可以使用構(gòu)造函數(shù)來(lái)實(shí)例化對(duì)象。

事實(shí)上,當(dāng)任意一個(gè)普通函數(shù)用于創(chuàng)建一類(lèi)對(duì)象時(shí),它就被稱作構(gòu)造函數(shù)。像js的內(nèi)置函數(shù)Object、Array、Date等都是構(gòu)造函數(shù)。

在定義構(gòu)造函數(shù)有以下幾個(gè)特點(diǎn):

以大寫(xiě)字母開(kāi)頭定義構(gòu)造函數(shù)

在函數(shù)內(nèi)部對(duì)新對(duì)象(this)的屬性進(jìn)行設(shè)置

返回值必須是this,或者其它非對(duì)象類(lèi)型的值

下面定義一個(gè)簡(jiǎn)單的、標(biāo)準(zhǔn)的構(gòu)造函數(shù):

function Obj(){
    this.name = "name"
    return this // 默認(rèn)有這一行 
}
var foo = new Obj() // 使用上面定義的構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象實(shí)例
原型特性

js原型有5個(gè)特點(diǎn),記住這5條特點(diǎn),相信你一定會(huì)弄明白長(zhǎng)期困擾你的原型關(guān)系。

除了null所有引用類(lèi)型(Object、Array、Function)都有對(duì)象特性,也就是都可以自由擴(kuò)展屬性。

所有引用類(lèi)型都有一個(gè)_proto_屬性(又稱為:隱式屬性),_proto_是一個(gè)普通的對(duì)象。所有的對(duì)象都會(huì)有一個(gè)constructor屬性,constructor始終指向創(chuàng)建當(dāng)前對(duì)象的構(gòu)造函數(shù)

所有的函數(shù)都有一個(gè)prototype屬性(又稱為:顯式屬性),也是一個(gè)普通對(duì)象,這個(gè)prototype有一個(gè)constructor屬性指向該函數(shù)。

所有的引用類(lèi)型的_proto_屬性指向它的構(gòu)造函數(shù)的prototype屬性(比如:obj._proto_指向Object.prototype,obj是定義的一個(gè)普通對(duì)象,Object是js的內(nèi)置函數(shù))

當(dāng)從一個(gè)對(duì)象中獲得某個(gè)屬性時(shí),如果這個(gè)對(duì)象沒(méi)有該屬性,就會(huì)去它的_proto_(也就是它的構(gòu)造函數(shù)的prototype)中去尋找

先來(lái)解釋一下這幾條:
第一條的自由擴(kuò)展性可以通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)看

var obj = {}
obj.name = "name"
console.log(obj) // {name:"name"}

第二條和第三條是javascript就是這么規(guī)定的,沒(méi)什么好說(shuō)的

第四條可以這么理解,當(dāng)定義一個(gè)引用類(lèi)型的變量var obj = {} 其實(shí)是var obj = new Object()的語(yǔ)法糖,這樣Object就是obj的構(gòu)造函數(shù),根據(jù)第4條規(guī)定,obj._proto_ === Object.prototype,如果不理解可以看看上一章我們講的js內(nèi)置函數(shù)和上面講的構(gòu)造函數(shù)

第五條應(yīng)該好理解,當(dāng)從obj中獲取某個(gè)屬性時(shí),如果obj中沒(méi)有定義該屬性,就會(huì)逐級(jí)去它的_proto_對(duì)象中去尋找,而它的_proto_指向Object的prototype,也就是從Object的prototype對(duì)象中去尋找。

原型鏈與繼承
如果上面明白了原型,那么原型鏈就會(huì)很好理解

根據(jù)原型定義的第4條和第5條,很容易發(fā)現(xiàn)通過(guò)對(duì)象的_proto_和函數(shù)的prototype把我們變量和構(gòu)造函數(shù)(自定義的構(gòu)造函數(shù)以及內(nèi)置構(gòu)造函數(shù))像鏈子一樣鏈接起來(lái),所以又叫他原型鏈。

有了原型鏈,就有了繼承,繼承就是一個(gè)對(duì)象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問(wèn)權(quán)。從下面一個(gè)小例子理解:

function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};
// 原型繼承
function Cat(){ 
}
Cat.prototype = new Animal();
Cat.prototype.name = "cat";

上面例子中在Foo構(gòu)造函數(shù)的prototype中自定義一個(gè)somefn函數(shù)。然后通過(guò)new Foo()創(chuàng)建一個(gè)對(duì)象實(shí)例并賦值給bar變量,此時(shí)bar就等于{name:"bar"}。然后bar.somefn就去bar對(duì)象中尋找somefn這個(gè)屬性,發(fā)現(xiàn)找不到,然后就去它的_proto_(其實(shí)就是Foo的prototype)中尋找,發(fā)現(xiàn)somefn就在Foo的prototype中定義了,就可以愉快的調(diào)用并執(zhí)行somefn了。

這里其實(shí)就是一個(gè)原型鏈與繼承的典型例子,開(kāi)發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點(diǎn),屬性定義的多一些,但是原理都是一樣的。

留一個(gè)問(wèn)題,根據(jù)上面例子,如果執(zhí)行bar.stString(),應(yīng)該去哪里找toString這個(gè)方法? (提示:prototype也是普通對(duì)象,也有自己的_proto_)
幾種繼承方式

這幾種都是es5中的繼承,es6中提供了class類(lèi),繼承起來(lái)更方便。

原型繼承

上述例子就是一個(gè)原型繼承:

function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
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 instanceof Animal); //true 
console.log(cat instanceof Cat); //true

優(yōu)點(diǎn):

非常純粹的繼承關(guān)系,實(shí)例是子類(lèi)的實(shí)例,也是父類(lèi)的實(shí)例

簡(jiǎn)單,易于實(shí)現(xiàn)

缺點(diǎn)

要想為子類(lèi)新增屬性和方法,必須要在new Animal()這樣的語(yǔ)句之后執(zhí)行,不能放到構(gòu)造器中

無(wú)法實(shí)現(xiàn)多繼承

來(lái)自原型對(duì)象的引用屬性是所有實(shí)例共享的(嚴(yán)重缺點(diǎn))

創(chuàng)建子類(lèi)實(shí)例時(shí),無(wú)法向父類(lèi)構(gòu)造函數(shù)傳參(嚴(yán)重缺點(diǎn))

構(gòu)造繼承
function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};
// 構(gòu)造繼承
function Cat(name){
  Animal.call(this);
  this.name = name || "Tom";
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep()); // Tom正在睡覺(jué)!
// console.log(cat.eat("fish")); // cat.eat is not a function
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

優(yōu)點(diǎn)

解決了1中,子類(lèi)實(shí)例共享父類(lèi)引用屬性的問(wèn)題

創(chuàng)建子類(lèi)實(shí)例時(shí),可以向父類(lèi)傳遞參數(shù)

可以實(shí)現(xiàn)多繼承

缺點(diǎn)

實(shí)例并不是父類(lèi)的實(shí)例,只是子類(lèi)的實(shí)例

只能繼承父類(lèi)的實(shí)例屬性和方法,不能繼承原型屬性/方法

無(wú)法實(shí)現(xiàn)函數(shù)復(fù)用,每個(gè)子類(lèi)都有父類(lèi)實(shí)例函數(shù)的副本,影響性能

實(shí)例繼承
function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};

// 實(shí)例繼承
function Cat(name){
  var instance = new Animal();
  instance.name = name || "Tom";
  return instance;
}
var cat = new Cat(); // 或者可以直接var cat = Cat()
console.log(cat.name);
console.log(cat.sleep()); // Tom正在睡覺(jué)!
console.log(cat.eat("fish")); // Tom正在吃:fish
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

優(yōu)點(diǎn)

不限制調(diào)用方式,不管是new Cat()還是Cat(),返回的對(duì)象具有相同的效果

缺點(diǎn)

實(shí)例是父類(lèi)的實(shí)例,不是子類(lèi)的實(shí)例

不支持多繼承

組合繼承
function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};
// 組合繼承
function Cat(name){
  Animal.call(this);
  this.name = name || "Tom";
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep()); // Tom正在睡覺(jué)!
console.log(cat.eat("fish")); // Tom正在吃:fish
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

優(yōu)點(diǎn)

彌補(bǔ)了方式2的缺陷,可以繼承實(shí)例屬性/方法,也可以繼承原型屬性/方法

既是子類(lèi)的實(shí)例,也是父類(lèi)的實(shí)例

不存在引用屬性共享問(wèn)題

可傳參

函數(shù)可復(fù)用

缺點(diǎn)

調(diào)用了兩次父類(lèi)構(gòu)造函數(shù),生成了兩份實(shí)例(子類(lèi)實(shí)例將子類(lèi)原型上的那份屏蔽了)

寄生繼承
var ob = {name:"小明",friends:["小花","小白"]};

function object(o){
  function F(){}//創(chuàng)建一個(gè)構(gòu)造函數(shù)F
  F.prototype = o;
  return new F();
}

//上面再ECMAScript5 有了一新的規(guī)范寫(xiě)法,Object.create(ob) 效果是一樣的  

function createOb(o){
   var newob = object(o);//創(chuàng)建對(duì)象
   newob.sayname = function(){//增強(qiáng)對(duì)象
       console.log(this.name);
   }

   return newob;//指定對(duì)象
}

var ob1 = createOb(ob);
ob1.sayname()
寄生繼承原理尚不明白。
寄生組合繼承

寄生組合繼承有兩種方式:

第一種:利用創(chuàng)建沒(méi)有實(shí)例方法的函數(shù)

function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};

//寄生組合繼承
function Cat(name){
  Animal.call(this);
  this.name = name || "Tom";
}
(function(){
  // 創(chuàng)建一個(gè)沒(méi)有實(shí)例方法的類(lèi)
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //將實(shí)例作為子類(lèi)的原型
  Cat.prototype = new Super();
  Cat.prototype.constructor = Cat;
})();

var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep()); // Tom正在睡覺(jué)!
console.log(cat.eat("fish")); // Tom正在吃:fish
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

第二種:利用Object.create函數(shù)

// 寄生繼承核心方法
function inheritPrototype(Parent, Children){
    var prototype = Object.create(Parent.prototype);
    prototype.constructor = Children;
    Children.prototype = prototype;
}
// 父類(lèi)
function Animal (name) {
  // 屬性
  this.name = name || "Animal";
  // 實(shí)例方法
  this.sleep = function(){
    console.log(this.name + "正在睡覺(jué)!");
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃:" + food);
};

// 子類(lèi)
function Cat(name){
  Animal.call(this);
  this.name = name || "Tom";
}
inheritPrototype(Animal, Cat)

var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep()); // Tom正在睡覺(jué)!
console.log(cat.eat("fish")); // Tom正在吃:fish
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

Object.create其實(shí)與以下代碼等價(jià)

function object(o){
    function f(){}
    f.prototype = o;
    return new f();
}

優(yōu)點(diǎn)

最完美的繼承解決方案

缺點(diǎn)

實(shí)現(xiàn)復(fù)雜

解答一下最一開(kāi)始提出的問(wèn)題

看到這里應(yīng)該對(duì)原型鏈與繼承的原理有所了解了,再回頭看上面的問(wèn)題,你也會(huì)發(fā)現(xiàn)這都是小兒科。
第一個(gè)問(wèn)題:instanceof原理?

var arr = []
arr instanceof Array

instanceof原理就是利用了原型鏈,當(dāng)執(zhí)行arr instanceof Array時(shí),會(huì)從arr的_proto_一層一層往上找,看是否能不能找到Array的prototype。
我們知道var arr = [] 其實(shí)是var arr = new Array()的語(yǔ)法糖,所以arr的_proto_指向Array的prototype,結(jié)果返回true

第二個(gè)問(wèn)題:如何準(zhǔn)確判斷變量類(lèi)型?
可以使用instanceof幫助我們判斷,而不是typeof

第三個(gè)問(wèn)題:如何寫(xiě)一個(gè)原型鏈繼承的例子?

function Foo () {
    this.name = "name"
    this.run = function () {
        console.log(this.name)
    }
}
function Bar () {}
Bar.prototype = new Foo() // 從構(gòu)造函數(shù)Foo中繼承
var baz = new Bar()
baz.run() // 打印出 "name"

第四個(gè)問(wèn)題:描述new一個(gè)對(duì)象的過(guò)程

創(chuàng)建一個(gè)新的對(duì)象,

獲得構(gòu)造函數(shù)的prototype屬性,并把prototype賦值給新對(duì)象的_proto_,this指向這個(gè)新對(duì)象

執(zhí)行構(gòu)造函數(shù),返回構(gòu)造函數(shù)的內(nèi)容

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

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

相關(guān)文章

  • Js基礎(chǔ)知識(shí)) - 原型鏈與繼承精彩講解

    摘要:有了原型鏈,就有了繼承,繼承就是一個(gè)對(duì)象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問(wèn)權(quán)。這里其實(shí)就是一個(gè)原型鏈與繼承的典型例子,開(kāi)發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點(diǎn),屬性定義的多一些,但是原理都是一樣的。 作用域、原型鏈、繼承與閉包詳解 注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類(lèi)的概念,只是在寫(xiě)法上有所不同,原理是一樣的。 幾個(gè)面試常問(wèn)的幾個(gè)問(wèn)題,你是否知道 insta...

    lingdududu 評(píng)論0 收藏0
  • JavaScript系列--淺析原型鏈與繼承

    摘要:綜上所述有原型鏈繼承,構(gòu)造函數(shù)繼承經(jīng)典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身是實(shí)現(xiàn)基于類(lèi)型繼承的最有效方法。 一、前言 繼承是面向?qū)ο螅∣OP)語(yǔ)言中的一個(gè)最為人津津樂(lè)道的概念。許多面對(duì)對(duì)象(OOP)語(yǔ)言都支持兩種繼承方式::接口繼承 和 實(shí)現(xiàn)繼承 。 接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。由于js中方法沒(méi)有簽名...

    draveness 評(píng)論0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠?lái)都是中的主導(dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠?lái)都是JavaScript中的主導(dǎo)范式。JavaScript作為一門(mén)多范式編程語(yǔ)言,然而,近幾年,函數(shù)式編程越來(lái)越多得受到開(kāi)發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評(píng)論0 收藏0
  • JavasScript重難點(diǎn)知識(shí)

    摘要:忍者級(jí)別的函數(shù)操作對(duì)于什么是匿名函數(shù),這里就不做過(guò)多介紹了。我們需要知道的是,對(duì)于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果...

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

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

0條評(píng)論

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