摘要:要知道,面向?qū)ο笾皇且环N手段,最終目的是為了提高我們項目的重用性靈活性和擴展性。兩個參數(shù)分別是子類和父類,第一段代碼這段代碼就是將父類上面的屬性拷貝到子類上,因為當中函數(shù)也是對象,可以擴展屬性的。
概述
自從面向?qū)ο蟮木幊趟枷氤霈F(xiàn)以來,這個概念已經(jīng)被炒爛了,只要編程開發(fā)大家都會拿面向?qū)ο髞碚f事,好像只要跟面向?qū)ο笳催吘蜁@得逼格很高一樣,不過確實逼格提高了。要知道,面向?qū)ο笾皇且环N手段,最終目的是為了提高我們項目的重用性、靈活性和擴展性。
為了迎合面向?qū)ο蟮某绦蛟O(shè)計思想,JavaScript也通過自己的語法實現(xiàn)了自己的一套面向?qū)ο髾C制。不過我想問下,前端開發(fā)當中有多少人使用過面向?qū)ο螽斨械睦^承?
JavaScript面向?qū)ο蟮膶崿F(xiàn)確實有點不倫不類的感覺。下面先簡單說明下JavaScript當中面向?qū)ο蟮膶崿F(xiàn),涉及的東西比較深,要對constructor、prototype有一定的理解,不然看起來會很吃力,或者你也可以跳開這部分內(nèi)容,直接看CoffeeScript面向?qū)ο蟮膶崿F(xiàn)。
JavaScript面向?qū)ο缶幊?/b> 類JavaScript的實現(xiàn)一個類,可以采用下面的方式:
function Animal(name) { this.name = name; } Animal.prototype.printName = function () { console.log(this.name); }; var animal = new Animal("animal"); animal.printName();
C++、Java...某些程序員可能就吐槽了,我TM都連個關(guān)鍵字class都沒看到,這就是類了?
作為一個前端開發(fā),我竟無言以對。。。
繼承選取JavaScript當中幾種繼承方式,作一個簡單的說明,想要學習更深的內(nèi)容,請通過搜索引擎吧。
對象冒充function Animal(name) { this.name = name; this.printName = function () { console.log(this.name); }; } function Cat(name) { this.inherit = Animal; this.inherit(name); //Animal.call(this, name); //Animal.apply(this, [name]); } var cat = new Cat("cat"); cat.printName();//cat
注釋是通過call和apply實現(xiàn)的方式,其實本質(zhì)是一樣的。繼承實現(xiàn)了,閑著無聊,我們來打印下:
console.log(cat instanceof Animal);//false
這次別說后端開發(fā)看不下去,我都忍不了了。這種方式只能說是通過JavaScript的語法機制,模擬實現(xiàn)繼承,看起來好像是那么回事,不然怎么叫對象冒充呢。
原型鏈實現(xiàn)function Animal(name) { this.name = name; } Animal.prototype.printName = function () { console.log(this.name); }; function Cat() { } Cat.prototype = new Animal("cat"); var cat = new Cat(); cat.printName();//cat
打?。?/p>
console.log(cat instanceof Animal);//true
這次對了,cat也是Animal類的實例了,有點面向?qū)ο蟮牡囊馑剂?。我又閑著無聊了(約么?),再來打印
console.log(cat.constructor); //[Function: Animal]
咦,又不對了,為啥cat的constructor指向Animal,不應(yīng)該指向Cat么?
問題出在Cat.prototype = new Animal("cat")上,直接給prototype賦值,改變了constructor的指向,這個時候,我們還要做個處理
function Animal(name) { this.name = name; } Animal.prototype.printName = function () { console.log(this.name); }; function Cat() { } Cat.prototype = new Animal("cat"); Cat.prototype.constructor = Cat; var cat = new Cat(); console.log(cat.constructor); //[Function: Cat]
但是又有人吐槽了,new Cat()為啥把名稱放到new Animal()里面,看起來太奇怪了,綜合一下就有了第三中——混合型。
混合實現(xiàn)實際上instanceof的判斷原理是跟原型鏈是相關(guān)的。大家自行腦洞!
function Animal(name) { this.name = name; } Animal.prototype.printName = function () { console.log(this.name); }; function Cat(name) { Animal.call(this, name); } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat = new Cat("cat"); cat.printName();//cat
看起來舒服點了,也就是舒服那么一點點。
多態(tài)直接拿混合型的繼承來說明了,這個比較簡單
function Animal(name) { this.name = name; } Animal.prototype.printName = function () { console.log(this.name); }; function Cat(name) { Animal.call(this, name); } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; Cat.prototype.printName = function () { console.log("The name is:" + this.name); }; var cat = new Cat("cat"); cat.printName();//The name is:catCoffeeScript面向?qū)ο缶幊?/b>
CoffeeScript的面向編程的語法同JavaScript比較起來,真是天上地下。一個陽春白雪,一個下里巴人。但是有一點我們要記住:CoffeeScript只是編譯到JavaScript,它只是在JavaScript的基礎(chǔ)上進行了語法的抽象,本質(zhì)上還是JavaScript。
類CoffeeScript采用class關(guān)鍵字聲明類,整個語法看起來更加簡明流暢。
#編譯前 class Animal constructor: (name)-> @name = name printName: -> console.log(@name) animal = new Animal "animal" animal.printName() #animal #編譯后 var Animal, animal; Animal = (function () { function Animal(name) { this.name = name; } Animal.prototype.printName = function () { return console.log(this.name); }; return Animal; })(); animal = new Animal("animal"); animal.printName();
constructor是構(gòu)造函數(shù),就上面的例子來說,還可以簡寫,實際上效果是一樣的
class Animal constructor: (@name)-> printName: -> console.log(@name) animal = new Animal "animal" animal.printName() #animal
CoffeeScript將我們習慣性的書寫方式變成豐富的語法糖。說到這里我就想說一句了,能不能把構(gòu)造函數(shù)換個字符,constructor丫太長了。
繼承繼承使用的是extends關(guān)鍵字
#編譯前 class Animal constructor: (@name)-> printName: -> console.log(@name) class Cat extends Animal cat = new Cat "cat" cat.printName() #cat #編譯后 var Animal, Cat, cat, extend = function (child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Animal = (function () { function Animal(name) { this.name = name; } Animal.prototype.printName = function () { return console.log(this.name); }; return Animal; })(); Cat = (function (superClass) { extend(Cat, superClass); function Cat() { return Cat.__super__.constructor.apply(this, arguments); } return Cat; })(Animal); cat = new Cat("cat"); cat.printName();extend函數(shù)解析
我們簡單分析下編譯后的extend函數(shù),對JavaScript原型鏈不是很熟的可以跳過這段。兩個參數(shù)分別是子類child和父類parent,第一段代碼:
for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; }
這段代碼就是將父類上面的屬性拷貝到子類上,因為JavaScript當中函數(shù)也是對象,可以擴展屬性的。什么意思?看代碼
class Animal constructor: (@name)-> printName: -> console.log(@name) Animal.prop = "Animal prop" class Cat extends Animal console.log Cat.prop #Animal prop
第二段代碼:
function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor();
可能大家看不大明白,我稍微改動下,換種寫法
child.prototype = new parent(); child.prototype.constructor=child;
這里就是我們上面提到的原型鏈繼承。再看最后段代碼:
child.__super__ = parent.prototype;
這里是為了在子類中調(diào)用父類的方法,實現(xiàn)多態(tài),看下面的例子就知道了。
多態(tài)編譯后的代碼太長,就不粘貼了,看CoffeeScript代碼更易于學習。
直接重寫父類方法class Animal constructor: (@name)-> printName: -> console.log(@name) class Cat extends Animal printName: -> console.log "Cat name:" + @name cat = new Cat "cat" cat.printName() #Cat name:cat重寫父類方法,在重寫的方法中調(diào)用父類方法
class Animal constructor: (@name)-> move: (meter)-> console.log(meter) class Cat extends Animal move: -> console.log "Cat move" super 4 cat = new Cat "cat" cat.move() #Cat move 4
有任何問題,歡迎大家批評指出,我們共同進步。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85565.html
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:而造成一些莫名其妙的錯誤。寫一個文件打印出編譯命令會在同級目錄下生成一個同名的文件。將包裹在了一個匿名函數(shù)當中,并用調(diào)用,這樣使得代碼隔離,不會和外部混淆。其中的表示的就是為了方便使用,可以使用雙冒號來替代。 很早就知道這CoffeeScript一門語言,但是一直沒有機會系統(tǒng)的學習下,那天趁在公司沒有什么要緊的項目做,就根據(jù)CoffeeScript首頁的例子學了一下。 引用Coffe...
閱讀 2558·2021-10-12 10:12
閱讀 1738·2019-08-30 15:52
閱讀 2479·2019-08-30 13:04
閱讀 1759·2019-08-29 18:33
閱讀 987·2019-08-29 16:28
閱讀 475·2019-08-29 12:33
閱讀 2076·2019-08-26 13:33
閱讀 2380·2019-08-26 11:36