亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入理解JavaScript系列(18):面向對象編程之ECMAScript實現

2019-11-20 13:00:44
字體:
來源:轉載
供稿:網友

介紹

本章是關于ECMAScript面向對象實現的第2篇,第1篇我們討論的是概論和CEMAScript的比較,如果你還沒有讀第1篇,在進行本章之前,我強烈建議你先讀一下第1篇,因為本篇實在太長了(35頁)。

英文原文:http://dmitrysoshnikov.com/ecmascript/chapter-7-2-oop-ecmascript-implementation/
注:由于篇幅太長了,難免出現錯誤,時刻保持修正中。

在概論里,我們延伸到了ECMAScript,現在,當我們知道它OOP實現時,我們再來準確定義一下:

復制代碼 代碼如下:

ECMAScript is an object-oriented programming language supporting delegating inheritance based on prototypes.

ECMAScript是一種面向對象語言,支持基于原型的委托式繼承。
我們將從最基本的數據類型來分析,首先要了解的是ECMAScript用原始值(primitive values)和對象(objects)來區分實體,因此有些文章里說的“在JavaScript里,一切都是對象”是錯誤的(不完全對),原始值就是我們這里要討論的一些數據類型。

數據類型

雖然ECMAScript是可以動態轉化類型的動態弱類型語言,它還是有數據類型的。也就是說,一個對象要屬于一個實實在在的類型。
標準規范里定義了9種數據類型,但只有6種是在ECMAScript程序里可以直接訪問的,它們是:Undefined、Null、Boolean、String、Number、Object。

另外3種類型只能在實現級別訪問(ECMAScript對象是不能使用這些類型的)并用于規范來解釋一些操作行為、保存中間值。這3種類型是:Reference、List和Completion。

因此,Reference是用來解釋delete、typeof、this這樣的操作符,并且包含一個基對象和一個屬性名稱;List描述的是參數列表的行為(在new表達式和函數調用的時候);Completion是用來解釋行為break、continue、return和throw語句的。

原始值類型
回頭來看6中用于ECMAScript程序的數據類型,前5種是原始值類型,包括Undefined、Null、Boolean、String、Number、Object。
原始值類型例子:

復制代碼 代碼如下:

var a = undefined;
var b = null;
var c = true;
var d = 'test';
var e = 10;

這些值是在底層上直接實現的,他們不是object,所以沒有原型,沒有構造函數。

大叔注:這些原生值和我們平時用的(Boolean、String、Number、Object)雖然名字上相似,但不是同一個東西。所以typeof(true)和typeof(Boolean)結果是不一樣的,因為typeof(Boolean)的結果是function,所以函數Boolean、String、Number是有原型的(下面的讀寫屬性章節也會提到)。

想知道數據是哪種類型用typeof是最好不過了,有個例子需要注意一下,如果用typeof來判斷null的類型,結果是object,為什么呢?因為null的類型是定義為Null的。

復制代碼 代碼如下:

alert(typeof null); // "object"

顯示"object"原因是因為規范就是這么規定的:對于Null值的typeof字符串值返回"object“。

規范沒有想象解釋這個,但是Brendan Eich (JavaScript發明人)注意到null相對于undefined大多數都是用于對象出現的地方,例如設置一個對象為空引用。但是有些文檔里有些氣人將之歸結為bug,而且將該bug放在Brendan Eich也參與討論的bug列表里,結果就是任其自然,還是把typeof null的結果設置為object(盡管262-3的標準是定義null的類型是Null,262-5已經將標準修改為null的類型是object了)。

Object類型

接著,Object類型(不要和Object構造函數混淆了,現在只討論抽象類型)是描述 ECMAScript對象的唯一一個數據類型。

Object is an unordered collection of key-value pairs.
對象是一個包含key-value對的無序集合

對象的key值被稱為屬性,屬性是原始值和其他對象的容器。如果屬性的值是函數我們稱它為方法 。

例如:

復制代碼 代碼如下:

var x = { // 對象"x"有3個屬性: a, b, c
  a: 10, // 原始值
  b: {z: 100}, // 對象"b"有一個屬性z
  c: function () { // 函數(方法)
    alert('method x.c');
  }
};
 
alert(x.a); // 10
alert(x.b); // [object Object]
alert(x.b.z); // 100
x.c(); // 'method x.c'

動態性

正如我們在第17章中指出的,ES中的對象是完全動態的。這意味著,在程序執行的時候我們可以任意地添加,修改或刪除對象的屬性。

例如:

復制代碼 代碼如下:

var foo = {x: 10};
 
// 添加新屬性
foo.y = 20;
console.log(foo); // {x: 10, y: 20}
 
// 將屬性值修改為函數
foo.x = function () {
  console.log('foo.x');
};
 
foo.x(); // 'foo.x'
 
// 刪除屬性
delete foo.x;
console.log(foo); // {y: 20}

有些屬性不能被修改――(只讀屬性、已刪除屬性或不可配置的屬性)。 我們將稍后在屬性特性里講解。

另外,ES5規范規定,靜態對象不能擴展新的屬性,并且它的屬性頁不能刪除或者修改。他們是所謂的凍結對象,可以通過應用Object.freeze(o)方法得到。

復制代碼 代碼如下:

var foo = {x: 10};
 
// 凍結對象
Object.freeze(foo);
console.log(Object.isFrozen(foo)); // true
 
// 不能修改
foo.x = 100;
 
// 不能擴展
foo.y = 200;
 
// 不能刪除
delete foo.x;
 
console.log(foo); // {x: 10}

在ES5規范里,也使用Object.preventExtensions(o)方法防止擴展,或者使用Object.defineProperty(o)方法來定義屬性:

復制代碼 代碼如下:

var foo = {x : 10};
 
Object.defineProperty(foo, "y", {
  value: 20,
  writable: false, // 只讀
  configurable: false // 不可配置
});
 
// 不能修改
foo.y = 200;
 
// 不能刪除
delete foo.y; // false
 
// 防治擴展
Object.preventExtensions(foo);
console.log(Object.isExtensible(foo)); // false
 
// 不能添加新屬性
foo.z = 30;
 
console.log(foo); {x: 10, y: 20}

內置對象、原生對象及宿主對象

有必要需要注意的是規范還區分了這內置對象、元素對象和宿主對象。

內置對象和元素對象是被ECMAScript規范定義和實現的,兩者之間的差異微不足道。所有ECMAScript實現的對象都是原生對象(其中一些是內置對象、一些在程序執行的時候創建,例如用戶自定義對象)。內置對象是原生對象的一個子集、是在程序開始之前內置到ECMAScript里的(例如,parseInt, Match等)。所有的宿主對象是由宿主環境提供的,通常是瀏覽器,并可能包括如window、alert等。

注意,宿主對象可能是ES自身實現的,完全符合規范的語義。從這點來說,他們能稱為“原生宿主”對象(盡快很理論),不過規范沒有定義“原生宿主”對象的概念。

Boolean,String和Number對象

另外,規范也定義了一些原生的特殊包裝類,這些對象是:

1.布爾對象
2.字符串對象
3.數字對象

這些對象的創建,是通過相應的內置構造器創建,并且包含原生值作為其內部屬性,這些對象可以轉換省原始值,反之亦然。

復制代碼 代碼如下:

var c = new Boolean(true);
var d = new String('test');
var e = new Number(10);
 
// 轉換成原始值
// 使用不帶new關鍵字的函數
с = Boolean(c);
d = String(d);
e = Number(e);
 
// 重新轉換成對象
с = Object(c);
d = Object(d);
e = Object(e);

此外,也有對象是由特殊的內置構造函數創建: Function(函數對象構造器)、Array(數組構造器) RegExp(正則表達式構造器)、Math(數學模塊)、 Date(日期的構造器)等等,這些對象也是Object對象類型的值,他們彼此的區別是由內部屬性管理的,我們在下面討論這些內容。

字面量Literal

對于三個對象的值:對象(object),數組(array)和正則表達式(regular expression),他們分別有簡寫的標示符稱為:對象初始化器、數組初始化器、和正則表達式初始化器:

復制代碼 代碼如下:

// 等價于new Array(1, 2, 3);
// 或者array = new Array();
// array[0] = 1;
// array[1] = 2;
// array[2] = 3;
var array = [1, 2, 3];
 
// 等價于
// var object = new Object();
// object.a = 1;
// object.b = 2;
// object.c = 3;
var object = {a: 1, b: 2, c: 3};
 
// 等價于new RegExp("^//d+$", "g")
var re = /^/d+$/g;

注意,如果上述三個對象進行重新賦值名稱到新的類型上的話,那隨后的實現語義就是按照新賦值的類型來使用,例如在當前的Rhino和老版本SpiderMonkey 1.7的實現上,會成功以new關鍵字的構造器來創建對象,但有些實現(當前Spider/TraceMonkey)字面量的語義在類型改變以后卻不一定改變。

復制代碼 代碼如下:

var getClass = Object.prototype.toString;
 
Object = Number;
 
var foo = new Object;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
var bar = {};
 
// Rhino, SpiderMonkey 1.7中 - 0, "[object Number]"
// 其它: still "[object Object]", "[object Object]"
alert([bar, getClass.call(bar)]);
 
// Array也是一樣的效果
Array = Number;
 
foo = new Array;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
bar = [];
 
// Rhino, SpiderMonkey 1.7中 - 0, "[object Number]"
// 其它: still "", "[object Object]"
alert([bar, getClass.call(bar)]);
 
// 但對RegExp,字面量的語義是不被改變的。 semantics of the literal
// isn't being changed in all tested implementations
 
RegExp = Number;
 
foo = new RegExp;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
bar = /(?!)/g;
alert([bar, getClass.call(bar)]); // /(?!)/g, "[object RegExp]"

正則表達式字面量和RegExp對象

注意,下面2個例子在第三版的規范里,正則表達式的語義都是等價的,regexp字面量只在一句里存在,并且再解析階段創建,但RegExp構造器創建的卻是新對象,所以這可能會導致出一些問題,如lastIndex的值在測試的時候結果是錯誤的:

復制代碼 代碼如下:

for (var k = 0; k < 4; k++) {
  var re = /ecma/g;
  alert(re.lastIndex); // 0, 4, 0, 4
  alert(re.test("ecmascript")); // true, false, true, false
}
 
// 對比
 
for (var k = 0; k < 4; k++) {
  var re = new RegExp("ecma", "g");
  alert(re.lastIndex); // 0, 0, 0, 0
  alert(re.test("ecmascript")); // true, true, true, true
}

注:不過這些問題在第5版的ES規范都已經修正了,不管是基于字面量的還是構造器的,正則都是創建新對象。

關聯數組

各種文字靜態討論,JavaScript對象(經常是用對象初始化器{}來創建)被稱為哈希表哈希表或其它簡單的稱謂:哈希(Ruby或Perl里的概念), 管理數組(PHP里的概念),詞典 (Python里的概念)等。

只有這樣的術語,主要是因為他們的結構都是相似的,就是使用“鍵-值”對來存儲對象,完全符合“關聯數組 ”或“哈希表 ”理論定義的數據結構。 此外,哈希表抽象數據類型通常是在實現層面使用。

但是,盡管術語上來描述這個概念,但實際上這個是錯誤,從ECMAScript來看:ECMAScript只有一個對象以及類型以及它的子類型,這和“鍵-值”對存儲沒有什么區別,因此在這上面沒有特別的概念。 因為任何對象的內部屬性都可以存儲為鍵-值”對:

復制代碼 代碼如下:

var a = {x: 10};
a['y'] = 20;
a.z = 30;
 
var b = new Number(1);
b.x = 10;
b.y = 20;
b['z'] = 30;
 
var c = new Function('');
c.x = 10;
c.y = 20;
c['z'] = 30;
 
// 等等,任意對象的子類型"subtype"

此外,由于在ECMAScript中對象可以是空的,所以"hash"的概念在這里也是不正確的:

復制代碼 代碼如下:

Object.prototype.x = 10;
 
var a = {}; // 創建空"hash"
 
alert(a["x"]); // 10, 但不為空
alert(a.toString); // function
 
a["y"] = 20; // 添加新的鍵值對到 "hash"
alert(a["y"]); // 20
 
Object.prototype.y = 20; // 添加原型屬性
 
delete a["y"]; // 刪除
alert(a["y"]); // 但這里key和value依然有值 亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩av在线免播放器| 久久亚洲精品国产亚洲老地址| 久久人人看视频| 国产精品美女免费看| 久久国产精彩视频| 亚洲系列中文字幕| 日韩精品视频免费| 一区二区三区动漫| 欧美成人免费全部| 久久久久女教师免费一区| 欧美人与性动交| 国产精品久久久久久影视| 国产精品爽黄69| 欧美在线精品免播放器视频| 亚洲日本欧美中文幕| 欧美自拍视频在线观看| 欧美大全免费观看电视剧大泉洋| 欧美日韩美女在线| 欧美日韩在线视频观看| 亚洲va久久久噜噜噜久久天堂| 国产精品视频白浆免费视频| 日韩影视在线观看| 68精品久久久久久欧美| 91九色视频导航| 国产91精品久久久久| 亚洲美女av在线播放| 欧美日韩在线免费| 久久九九全国免费精品观看| 91亚洲精品视频| 国产精品九九九| 一区二区欧美亚洲| 久久免费视频网站| 亚洲国产精品福利| 亚洲最大在线视频| 欧美一区二区.| 久久久av亚洲男天堂| 日韩成人网免费视频| 亚洲毛片在线看| 国产精品久久97| 久久精彩免费视频| 欧美激情极品视频| 国产精品老女人精品视频| 亚洲第一精品自拍| 欧美在线免费视频| 精品国产视频在线| 日韩性生活视频| 国产亚洲精品久久久久久牛牛| 国产精品久久久久久久久久小说| 欧洲成人免费视频| 国产精品视频在线观看| 亚洲一区免费网站| 国产97在线|亚洲| 欧美色videos| 久久97精品久久久久久久不卡| 欧美激情免费在线| 久久久久久91| 欧美性猛交xxxx乱大交3| 国语自产偷拍精品视频偷| 国产成人精品av| 日韩在线不卡视频| 2019最新中文字幕| 日韩精品免费在线视频| 亚洲天堂av电影| 91精品国产综合久久久久久久久| 永久555www成人免费| 成人免费福利在线| xvideos成人免费中文版| 精品久久久久久国产| 欧美性猛交xxxxx免费看| 亚洲小视频在线观看| 亚洲人精选亚洲人成在线| 97精品在线视频| 亚洲精品福利资源站| 国内精品国产三级国产在线专| 国产91精品青草社区| 国产精品一香蕉国产线看观看| 亚洲国产天堂网精品网站| 日本人成精品视频在线| 精品偷拍一区二区三区在线看| 欧美激情视频播放| 欧美激情在线视频二区| 亚洲第一av网| 日韩中文字幕免费| 欧美激情欧美狂野欧美精品| 欧美在线免费视频| 国产香蕉一区二区三区在线视频| 在线看欧美日韩| 国产99视频在线观看| 精品美女久久久久久免费| 欧美野外猛男的大粗鳮| 亚洲一级免费视频| 欧美日韩免费在线观看| 一个人看的www久久| 国产精品国产福利国产秒拍| 国产成人激情视频| 一区二区福利视频| 欧洲中文字幕国产精品| 日韩av在线天堂网| 亚洲香蕉成人av网站在线观看| 国产女同一区二区| 亚洲性视频网站| 精品欧美一区二区三区| 日本成人免费在线| 亚洲第一精品自拍| 欧美黄色成人网| 日韩亚洲在线观看| 亚洲区中文字幕| 欧美激情女人20p| 中文字幕国产精品久久| 欧美成人免费小视频| 中文字幕亚洲一区二区三区| 俺去亚洲欧洲欧美日韩| 久久精品国产久精国产思思| 欧美午夜性色大片在线观看| 久久久久久综合网天天| 精品日韩中文字幕| 成人午夜高潮视频| 久久久人成影片一区二区三区| 久久免费精品视频| 精品一区二区电影| 国产成人精品久久亚洲高清不卡| 66m—66摸成人免费视频| 日韩av影院在线观看| 麻豆精品精华液| 欧美又大又硬又粗bbbbb| 欧美俄罗斯性视频| 亚洲第一福利网站| 欧美自拍视频在线观看| 久久色精品视频| 激情懂色av一区av二区av| 亚洲理论在线a中文字幕| 亚洲午夜性刺激影院| 国产做受高潮69| 成人精品在线视频| 3344国产精品免费看| 国产xxx69麻豆国语对白| 国产精品视频99| 91精品视频一区| 国产亚洲人成a一在线v站| 国产福利精品在线| 日韩电影在线观看中文字幕| 欧美成人在线免费视频| 深夜福利国产精品| 91精品啪在线观看麻豆免费| 欧美在线免费视频| 日韩av手机在线| 日韩网站免费观看| 日韩精品免费综合视频在线播放| 国产精品va在线播放| 精品久久久久久久久国产字幕| 亚洲精品美女视频| 在线观看日韩视频| 一夜七次郎国产精品亚洲| 久久久久久久久久国产| 日韩精品在线免费观看视频| 日本精品久久久久影院| 亚洲人成网站在线播| 亚州欧美日韩中文视频| 国产精品2018| 成人免费xxxxx在线观看| 国产精品影院在线观看| 精品亚洲永久免费精品| 国内揄拍国内精品| 国产一区二区三区欧美|