成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript中的面向?qū)ο螅╫bject-oriented)編程

JerryZou / 3536人閱讀

摘要:對(duì)象在中,除了數(shù)字字符串布爾值這幾個(gè)簡(jiǎn)單類(lèi)型外,其他的都是對(duì)象。那么在函數(shù)對(duì)象中,這兩個(gè)屬性的有什么區(qū)別呢表示該函數(shù)對(duì)象的原型表示使用來(lái)執(zhí)行該函數(shù)時(shí)這種函數(shù)一般成為構(gòu)造函數(shù),后面會(huì)講解,新創(chuàng)建的對(duì)象的原型。這時(shí)的函數(shù)通常稱(chēng)為構(gòu)造函數(shù)。。

本文原發(fā)于我的個(gè)人博客,經(jīng)多次修改后發(fā)到sf上。本文仍在不斷修改中,最新版請(qǐng)?jiān)L問(wèn)個(gè)人博客。

最近工作一直在用nodejs做開(kāi)發(fā),有了nodejs,前端、后端、腳本全都可以用javascript搞定,很是方便。但是javascript的很多語(yǔ)法,比如對(duì)象,就和我們常用的面向?qū)ο蟮木幊陶Z(yǔ)言不同;看某個(gè)javascript開(kāi)源項(xiàng)目,也經(jīng)常會(huì)看到使用this關(guān)鍵字,而這個(gè)this關(guān)鍵字在javascript中因上下文不同而意義不同;還有讓人奇怪的原型鏈。這些零零碎碎的東西加起來(lái)就很容易讓人不知所措,所以,有必要對(duì)javascript這門(mén)語(yǔ)言進(jìn)行一下深入了解。

我這篇文章主要想說(shuō)說(shuō)如何在javascript中進(jìn)行面向?qū)ο蟮木幊?,同時(shí)會(huì)講一些javascript這門(mén)語(yǔ)言在設(shè)計(jì)之初的理念。下面讓我們開(kāi)始吧。

首先強(qiáng)調(diào)一下,我們現(xiàn)在廣泛使用的javascript都是遵循了ECMAScript 5.1標(biāo)準(zhǔn)的,正在制定中的版本為6.0,這個(gè)版本變化很大,增加了很多新的語(yǔ)法與函數(shù),大家可以去Mozilla Developer Network上查看。

設(shè)計(jì)理念

javascript1.0 最初是由網(wǎng)景公司的Brendan Eich在1995年5月花了十天搞出來(lái)的,Eich的目標(biāo)是設(shè)計(jì)出一種即輕量又強(qiáng)大的語(yǔ)言,所以Eich充分借鑒了其他編程語(yǔ)言的特性,比如Java的語(yǔ)法(syntax)、Scheme的函數(shù)(function)、Self的原型繼承(prototypal inheritance)、Perl的正則表達(dá)式等。

其中值得一提的是,為什么繼承借鑒了Self語(yǔ)言的原型機(jī)制而不是Java的類(lèi)機(jī)制?首先我們要知道:

Self的原型機(jī)制是靠運(yùn)行時(shí)的語(yǔ)義

Java的類(lèi)機(jī)制是靠編譯時(shí)的類(lèi)語(yǔ)法

Javascript1.0的功能相對(duì)簡(jiǎn)單,為了在今后不斷豐富javascript本身功能的同時(shí)保持舊代碼的兼容性,javascript通過(guò)改變運(yùn)行時(shí)的支持來(lái)增加新功能,而不是通過(guò)修改javascript的語(yǔ)法,這就保證了舊代碼的兼容性。這也就是javascript選擇基于運(yùn)行時(shí)的原型機(jī)制的原因。

wikipedia這樣描述到:JavaScript is classified as a prototype-based scripting language with dynamic typing and first-class functions。這些特性使得javascript是一種多范式的解釋性編程語(yǔ)言,支持面向?qū)ο?、命令?imperative)、函數(shù)式(functional)編程風(fēng)格。

對(duì)象

在javascript中,除了數(shù)字、字符串、布爾值(true/false)、undefined這幾個(gè)簡(jiǎn)單類(lèi)型外,其他的都是對(duì)象。

數(shù)字、字符串、布爾值這些簡(jiǎn)單類(lèi)型都是不可變量,對(duì)象是可變的鍵值對(duì)的集合(mutable keyed conllections),對(duì)象包括數(shù)組Array、正則表達(dá)式RegExp、函數(shù)Function,當(dāng)然對(duì)象Object也是對(duì)象。

對(duì)象在javascript中說(shuō)白了就是一系列的鍵值對(duì)。鍵可以是任何字符串,包括空串;值可以是除了undefined以外的任何值。在javascript中是沒(méi)有類(lèi)的概念(class-free)的,但是它有一個(gè)原型鏈(prototype linkage)。javascript對(duì)象通過(guò)這個(gè)鏈來(lái)實(shí)現(xiàn)繼承關(guān)系。

javascript中有一些預(yù)定義對(duì)象,像是Object、Function、Date、Number、String、Array等。

字面量(literal)

javascript中的每種類(lèi)型的對(duì)象都可以采用字面量(literal)的方式創(chuàng)建。

對(duì)于Object對(duì)象,可以使用對(duì)象字面量(Object literal)來(lái)創(chuàng)建,例如:

var empty_object = {};//創(chuàng)建了一個(gè)空對(duì)象
//創(chuàng)建了一個(gè)有兩個(gè)屬性的對(duì)象
var stooge = {
    "first-name": "Jerome",
    "last-name": "Howard"
};

當(dāng)然,也可以用new Object()Object.create()的方式來(lái)創(chuàng)建對(duì)象。

對(duì)于Function、Array對(duì)象都有其相應(yīng)的字面量形式,后面會(huì)講到,這里不再贅述。

原型鏈(prototype linkage)

javascript中的每個(gè)對(duì)象都隱式含有一個(gè)[[prototype]]屬性,這是ECMAScript中的記法,目前各大瀏覽器廠商在實(shí)現(xiàn)自己的javascript解釋器時(shí),采用的記法是__proto__,也就是說(shuō)每個(gè)對(duì)象都隱式包含一個(gè)__proto__屬性。舉個(gè)例子:

var foo = {
    x: 10,
    y: 20
};

foo這個(gè)對(duì)象在內(nèi)存中的存儲(chǔ)結(jié)構(gòu)大致是這樣的:


當(dāng)有多個(gè)對(duì)象時(shí),通過(guò)__proto__屬性就能夠形成一條原型鏈??聪旅娴睦樱?/p>

var a = {
    x: 10,
    calculate: function (z) {
        return this.x + this.y + z;
    }
};
var b = {
    y: 20,
    __proto__: a
};
var c = {
    y: 30,
    __proto__: a
};
// call the inherited method
b.calculate(30); // 60
c.calculate(40); // 80

上面的代碼在聲明對(duì)象b、c時(shí),指明了它們的原型為對(duì)象a(a的原型默認(rèn)指向Object.prototye,Object.prototype這個(gè)對(duì)象的原型指向null),這幾個(gè)對(duì)象在內(nèi)存中的結(jié)構(gòu)大致是這樣的:


這里需要說(shuō)明一點(diǎn),我們?nèi)绻朐诼暶鲗?duì)象時(shí)指定它的原型,一般采用Object.create()方法,這樣效率更高。
除了我們這里說(shuō)的__proto__屬性,相信大家平常更常見(jiàn)的是prototype屬性。比如,Date對(duì)象中沒(méi)有加幾天的函數(shù),那么我們可以這么做:

Date.prototype.addDays = function(n) {
    this.setDate(this.getDate() + n);
}

那么以后所有的Date對(duì)象都擁有addDays方法了(后面講解繼承是會(huì)解釋為什么)。那么__proto__屬性與prototype屬性有什么區(qū)別呢?

  

javascript的每個(gè)對(duì)象都有__proto__屬性,但是只有函數(shù)對(duì)象prototype屬性。

那么在函數(shù)對(duì)象中, 這兩個(gè)屬性的有什么區(qū)別呢?

__proto__表示該函數(shù)對(duì)象的原型

prototype表示使用new來(lái)執(zhí)行該函數(shù)時(shí)(這種函數(shù)一般成為構(gòu)造函數(shù),后面會(huì)講解),新創(chuàng)建的對(duì)象的原型。例如:

var d = new Date();
d.__proto__ === Date.prototype; //這里為true

看到這里,希望大家能夠理解這兩個(gè)屬性的區(qū)別了。

在javascript,原型和函數(shù)是最重要的兩個(gè)概念,上面說(shuō)完了原型,下面說(shuō)說(shuō)函數(shù)對(duì)象。

函數(shù)對(duì)象Function

首先,函數(shù)在javascript中無(wú)非也是個(gè)對(duì)象,可以作為value賦值給某個(gè)變量,唯一不同的是函數(shù)能夠被執(zhí)行。

使用對(duì)象字面量方式創(chuàng)建的對(duì)象的__proto__屬性指向Object.prototype(Object.prototype__proto__屬性指向null);使用函數(shù)字面量創(chuàng)建的對(duì)象的__proto__屬性指向Function.prototype(Function.prototype對(duì)象的__proto__屬性指向Object.prototype)。

函數(shù)對(duì)象除了__proto__這個(gè)隱式屬性外,還有兩個(gè)隱式的屬性:

函數(shù)的上下文(function’s context)

實(shí)現(xiàn)函數(shù)的代碼(the code that implements the function’s behavior)

和對(duì)象字面量一樣,我們可以使用函數(shù)字面量(function literal)來(lái)創(chuàng)建函數(shù)。類(lèi)似于下面的方式:

//使用字面量方式創(chuàng)建一個(gè)函數(shù),并賦值給add變量
var add = function (a, b) { 
    return a + b;
};

一個(gè)函數(shù)字面量有四個(gè)部分:

function關(guān)鍵字,必選項(xiàng)。

函數(shù)名,可選項(xiàng)。上面的示例中就省略了函數(shù)名。

由圓括號(hào)括起來(lái)的一系列參數(shù),必選項(xiàng)。

由花括號(hào)括起來(lái)的一系列語(yǔ)句,必選項(xiàng)。該函數(shù)執(zhí)行時(shí)將會(huì)執(zhí)行這些語(yǔ)句。

函數(shù)調(diào)用與this

一個(gè)函數(shù)在被調(diào)用時(shí),除了聲明的參數(shù)外,還會(huì)隱式傳遞兩個(gè)額外的參數(shù):thisarguments

this在OOP中很重要,this的值隨著調(diào)用方式的不同而不同。javascript中共有四種調(diào)用方式:

method invocation pattern。當(dāng)函數(shù)作為某對(duì)象一個(gè)屬性調(diào)用時(shí),this指向這個(gè)對(duì)象。this賦值過(guò)程發(fā)生在函數(shù)調(diào)用時(shí)(也就是運(yùn)行時(shí)),這叫做late binding

function invocation pattern。當(dāng)函數(shù)不作為屬性調(diào)用時(shí),this指向全局對(duì)象,這是個(gè)設(shè)計(jì)上的錯(cuò)誤,正確的話(huà),內(nèi)部函數(shù)的this應(yīng)該指向外部函數(shù)??梢酝ㄟ^(guò)在函數(shù)中定義一個(gè)變量來(lái)解決這個(gè)問(wèn)題。

var add = function(a, b) {return a+b;}
var obj = {
    value: 3,
    double: function() {
        var self = this;//把this賦值給了self
        this.value = add(self.value, self.value);
    }
}
obj.double(); //obj.value現(xiàn)在為6

construct invocation pattern。javascript是一門(mén)原型繼承語(yǔ)言,這也就意味著對(duì)象可以直接從其他對(duì)象中繼承屬性,沒(méi)有類(lèi)的概念。這和java中的繼承不一樣。但是javascript提供了一種類(lèi)似與java創(chuàng)建對(duì)象的語(yǔ)法。當(dāng)一個(gè)函數(shù)用new來(lái)調(diào)用時(shí),this指向新創(chuàng)建的對(duì)象。這時(shí)的函數(shù)通常稱(chēng)為構(gòu)造函數(shù)。

apply invocation pattern。使用函數(shù)對(duì)象的apply方法來(lái)執(zhí)行時(shí),this指向apply的第一個(gè)參數(shù)。

除了this外,函數(shù)在調(diào)用是額外傳入的另一個(gè)參數(shù)是arguments。它是函數(shù)內(nèi)部的一個(gè)變量,包含函數(shù)調(diào)用處的所有參數(shù),甚至包含函數(shù)定義時(shí)沒(méi)有的參數(shù)。

var sum = function () { 
    var i, sum = 0;
    for (i = 0; i < arguments.length; i += 1) {
        sum += arguments[i];
    }
    return sum;
};
sum(4, 8, 15, 16, 23, 42); // 108

需要注意的是,這里的arguments不是一個(gè)數(shù)組,它只是一個(gè)有l(wèi)ength屬性的類(lèi)數(shù)組對(duì)象(Array-like),它并不擁有數(shù)組的其他方法。

關(guān)于對(duì)象,最后說(shuō)一下數(shù)組,javascript中的數(shù)組和平常編程中的數(shù)組不大一樣。

數(shù)組對(duì)象Array

數(shù)組是一種在內(nèi)存中線(xiàn)性分配的數(shù)據(jù)結(jié)構(gòu),通過(guò)下標(biāo)計(jì)算出元素偏移量,從而取出元素。數(shù)組應(yīng)該是一個(gè)快速存取的數(shù)據(jù)結(jié)構(gòu),但是在javascript中,數(shù)組不具備這種特性。

數(shù)組在javascript中一個(gè)具有傳統(tǒng)數(shù)組特性的對(duì)象,這種對(duì)象能夠把數(shù)組下標(biāo)轉(zhuǎn)為字符串,然后把這個(gè)字符串作為對(duì)象的key,最后對(duì)取出對(duì)應(yīng)該key的value(這又一次說(shuō)明了對(duì)象在javascript中就是一系列鍵值對(duì))。

雖然javascript中的數(shù)組沒(méi)有傳統(tǒng)語(yǔ)言中的數(shù)組那么快,但是由于javascript是弱類(lèi)型的語(yǔ)言,所以javascript中的數(shù)組可以存放任何值。此外Array有很多實(shí)用的方法,大家可以去MDN Array查看。

javascript也為數(shù)組提供了很方便的字面量(Array Literal)定義方式:

var arr = [1,2,3]

通過(guò)數(shù)組字面量創(chuàng)建的數(shù)組對(duì)象的__proto__指向Array.prototype。

繼承Inheritance

在Java中,對(duì)象是某個(gè)類(lèi)的實(shí)例,一個(gè)類(lèi)可以從另一個(gè)類(lèi)中繼承。但是在基于原型鏈的javascript中,對(duì)象可以直接從另一個(gè)對(duì)象創(chuàng)建。

在上面講解對(duì)象時(shí),我們知道了在創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象會(huì)自動(dòng)賦予一個(gè)__proto__屬性,使用各種類(lèi)型的字面量(Literal)時(shí),javascript解釋器自動(dòng)為__proto__進(jìn)行了賦值。當(dāng)我們?cè)趈avascript執(zhí)行使用new操作符創(chuàng)建對(duì)象時(shí),javascript解釋器在構(gòu)造函數(shù)時(shí),同時(shí)會(huì)執(zhí)行類(lèi)似于下面的語(yǔ)句

     this.__proto__ = {constructor: this};

新創(chuàng)建的對(duì)象都會(huì)有一個(gè)__proto__屬性,這個(gè)屬性有一個(gè)constructor屬性,并且這個(gè)屬性指向這個(gè)新對(duì)象。舉個(gè)例子:

var d = new Date()
d.__proto__.constructor === Date //這里為true

如果new不是一個(gè)操作符,而是一個(gè)函數(shù)的話(huà),它的實(shí)現(xiàn)類(lèi)似于下面的代碼:

Function.prototype.new =  function () {
    // Create a new object that inherits from the constructor"s prototype.
    var that = Object.create(this.prototype);
    // Invoke the constructor, binding –this- to the new object.
    var other = this.apply(that, arguments);
    // If its return value isn"t an object, substitute the new object.
    return (typeof other === "object" && other) || that;
};

之前也說(shuō)了,基于原型的繼承機(jī)制是根據(jù)運(yùn)行時(shí)的語(yǔ)義決定的,這就給我們提供了很大的便利。比如,我們想為所有的Array添加一個(gè)map函數(shù),那么我們可以這么做:

Array.prototype.map = function(f) {
    var newArr = [];
    for(i=0; i

因?yàn)樗械臄?shù)組對(duì)象的__proto__都指向Array.prototype對(duì)象,所以我們?yōu)檫@個(gè)對(duì)象增加方法,那么所有的數(shù)組對(duì)象就都擁有了這個(gè)方法。

javascript解釋器會(huì)順著原型鏈查看某個(gè)方法或?qū)傩?。如果想查看某?duì)象的是否有某個(gè)屬性,可以使用Object.prototype.hasOwnProperty方法。

總結(jié)

通過(guò)上面多次講解,希望大家對(duì)對(duì)象在javascript中就是一系列的鍵值對(duì)、原型函數(shù)這三個(gè)概念有更加深刻的認(rèn)識(shí),使用javascript來(lái)寫(xiě)前端、后端與腳本。在React.js 2015大會(huì)上,F(xiàn)acebook公布了即將開(kāi)源的React Native,這意味著今后我們可以用javascript來(lái)寫(xiě)IOS、Android的原生應(yīng)用了,這可真是learn-once, write-anywhere。相信隨著ECMAScript 6的發(fā)布,javascript這門(mén)語(yǔ)言還會(huì)有一系列翻天覆地的變化,Stay Tuned。:-)

參考

JavaScript. The core

《Javascript: The Good Parts》強(qiáng)烈建議大家去看這個(gè)書(shū)。


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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85531.html

相關(guān)文章

  • 每個(gè) JavaScript 工程師都應(yīng)當(dāng)知道的 10 個(gè)面試題

    摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語(yǔ)言之一,而演算則可以說(shuō)是孕育了這門(mén)語(yǔ)言。即使在今天,這個(gè)家族的編程語(yǔ)言應(yīng)用范圍依然很廣。 1. 能說(shuō)出來(lái)兩種對(duì)于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門(mén)多范式(multi-paradigm)的編程語(yǔ)言,它既支持命令式(imperative)/面向過(guò)程(procedural)編程...

    jone5679 評(píng)論0 收藏0
  • 每個(gè) JavaScript 工程師都應(yīng)當(dāng)知道的 10 個(gè)面試題

    摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語(yǔ)言之一,而演算則可以說(shuō)是孕育了這門(mén)語(yǔ)言。即使在今天,這個(gè)家族的編程語(yǔ)言應(yīng)用范圍依然很廣。 1. 能說(shuō)出來(lái)兩種對(duì)于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門(mén)多范式(multi-paradigm)的編程語(yǔ)言,它既支持命令式(imperative)/面向過(guò)程(procedural)編程...

    YorkChen 評(píng)論0 收藏0
  • 每個(gè) JavaScript 工程師都應(yīng)當(dāng)知道的 10 個(gè)面試題

    摘要:所支持的面向?qū)ο缶幊贪ㄔ屠^承。發(fā)明于年的就是首批支持函數(shù)式編程的語(yǔ)言之一,而演算則可以說(shuō)是孕育了這門(mén)語(yǔ)言。即使在今天,這個(gè)家族的編程語(yǔ)言應(yīng)用范圍依然很廣。 1. 能說(shuō)出來(lái)兩種對(duì)于 JavaScript 工程師很重要的編程范式么? JavaScript 是一門(mén)多范式(multi-paradigm)的編程語(yǔ)言,它既支持命令式(imperative)/面向過(guò)程(procedural)編程...

    Gilbertat 評(píng)論0 收藏0
  • JS對(duì)象(1)重新認(rèn)識(shí)面向對(duì)象

    摘要:對(duì)象重新認(rèn)識(shí)面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對(duì)象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過(guò)構(gòu)造器創(chuàng)建對(duì)象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對(duì)象該函數(shù)對(duì)象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對(duì)象(1)重新認(rèn)識(shí)面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對(duì)象是...

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

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

0條評(píng)論

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