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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascript 本地对象和内置对象_JavaScript 的面向对象

發(fā)布時(shí)間:2024/10/14 javascript 93 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript 本地对象和内置对象_JavaScript 的面向对象 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

圖片來源于 DigitalOcean

1. 什么是類

在說 JavaScript 的面向?qū)ο蟮膶?shí)現(xiàn)方法之前,我們先來看面向?qū)ο缶幊痰囊粋€(gè)核心概念——類(class)。類是對擁有同樣屬性(property)和行為的一系列對象(object)的抽象。?這里說的“行為”,在基于類的面向?qū)ο蟮恼Z言中通常叫做類的方法(method)。而在 JavaScript 里,函數(shù)也是“一等公民”,可以被直接賦值給一個(gè)變量或一個(gè)對象的屬性,因此在本文后續(xù)的討論中,把“行為”也歸入“屬性”的范疇。

2. JavaScript 對“類”的實(shí)現(xiàn)

JavaScript 一開始是被設(shè)計(jì)成在網(wǎng)頁上對表單進(jìn)行校驗(yàn)或者對網(wǎng)頁上的元素進(jìn)行操縱的一種腳本語言,沒有像 C++ 和 Java 那樣用?class、private、protected?等關(guān)鍵字來定義類的語法。JavaScript 采用的是一種更簡單的實(shí)現(xiàn)方式:既然類就是擁有同樣屬性的一系列對象,那么只要通過一種方式能使某一些對象擁有同樣的屬性就行了。

JavaScript 規(guī)定每一個(gè)對象都可以有一個(gè)原型([[prototype]]?內(nèi)部屬性)。(在實(shí)現(xiàn) ECMAScript 5.1 規(guī)范以前,除了?Object.prototype?以外的對象都必須有一個(gè)原型。)每個(gè)對象都“共享”其原型的屬性:在訪問一個(gè)對象的屬性時(shí),如果該對象本身沒有這個(gè)屬性,則 JavaScript 會(huì)繼續(xù)試圖訪問其原型的屬性。這樣,就可以通過指定一些對象的原型來使這些對象都擁有同樣的屬性。從而我們可以這樣認(rèn)為,在 JavaScript 中,以同一個(gè)對象為原型的對象就是屬于同一個(gè)類的對象

2.1 JavaScript 中對象的原型的指定方式

那么 JavaScript 中的對象與其原型是怎樣被關(guān)聯(lián)起來的呢?或者說,JavaScript 中的對象的原型是怎樣被指定的呢?

2.1.1 new 操作符

JavaScript 有一個(gè) new 操作符(operator),它基于一個(gè)函數(shù)來創(chuàng)建對象。這個(gè)用 new 操作符創(chuàng)建出來的對象的原型就是 new 操作符后面的函數(shù)(稱為“構(gòu)造函數(shù)”)的 prototype 屬性。例如:

var?a?=?{"aa":?1};
function?B()?{}
B.prototype?=?a;
var?b?=?new?B();

此時(shí) b 對象的原型就是 a 對象。我在另一篇文章中介紹了 new 操作符的具體實(shí)現(xiàn)邏輯,供大家參考。

2.1.2 Object.create 方法

Object.create 方法直接以給定的對象作為原型創(chuàng)建對象。一個(gè)代碼例子:

var?a?=?{"aa":?1};
var?b?=?Object.create(a);

此時(shí) b 對象的原型就是 a 對象。關(guān)于 Object.create 方法的實(shí)現(xiàn)細(xì)節(jié),大家可參考我的這篇文章。

2.1.3 Object.setPrototypeOf 方法

new 操作符和 Object.create 方法都是在創(chuàng)建一個(gè)對象的同時(shí)就指定其原型。而 Object.setPrototypeOf 方法則是指定一個(gè)已被創(chuàng)建的對象的原型。代碼例子:

var?a?=?{"aa":?1};
var?b?=?Object.create(a);
//?此時(shí)?b?的原型是?a
var?c?=?{"cc":?2};
Object.setPrototypeOf(b,?c);
//?此時(shí)?b?的原型變?yōu)?c?了

2.1.4 隱式指定

數(shù)字、布爾值、字符串、數(shù)組和函數(shù)在 JavaScript 中也是對象,而它們的原型是被 JavaScript 隱式指定的:

1. 數(shù)字(例如?1、1.1、NaN、Infinity)的原型是?Number.prototype;

2. 布爾值(true?和?false)的原型為?Boolean.prototype;

3. 字符串(例如?""、"abc")的原型為?String.prototype;

4. 函數(shù)(例如?function () {}、function (a) { return a + '1'; }) 的原型為?Function.prototype;

5. 數(shù)組(如?[]、[1, '2'])的原型是?Array.prototype;

6. 用花括號直接定義的對象(如?{},?{"a": 1})的原型是?Object.prototype。

2.2 JavaScript 中定義類的代碼示例

下面給出定義一個(gè)類的一段 JavaScript 代碼的示例。它定義一個(gè)名為 Person 的類,它的構(gòu)造函數(shù)接受一個(gè)字符串的名稱,還一個(gè)方法 introduceSelf 會(huì)輸出自己的名字。

//?----====?類定義開始?====----
function?Person(name)?{
????this.name?=?name;
}
Person.prototype.introduceSelf?=?function?()?{
????console.log("My?name?is?"?+?this.name);
};
//?----====?類定義結(jié)束?====----
//?下面實(shí)例化一個(gè)?Person?類的對象
var?someone?=?new?Person("Tom");
//?此時(shí)?someone?的原型為?Person.prototype
someone.introduceSelf();?//?輸出?My?name?is?Tom

如果轉(zhuǎn)換為 ECMAScript 6 引入的類聲明(class declaration)語法,則上述 Person 類的定義等同于:

class?Person?{
????constructor(name)?{
????????this.name?=?name;
????}
????introduceSelf()?{
????????console.log("My?name?is?"?+?this.name);
????}
}

2.3 對“構(gòu)造函數(shù)”的再思考

在上面的例子中,假如我們不通過?Person.prototype?來定義 introduceSelf 方法,而是在構(gòu)造函數(shù)中給對象指定一個(gè) introduceSelf 屬性:

function?Person(name)?{
????this.name?=?name;
????this.introduceSelf?=?function?()?{
????????console.log("My?name?is?"?+?this.name);
????};
}
var?someone?=?new?Person("Tom");
someone.introduceSelf();?//?也會(huì)輸出?My?name?is?Tom

雖然這種方法中,通過 Person 構(gòu)造函數(shù) new 出來的對象也都有 introduceSelf 屬性,但這里 introduceSelf 變成了 someone 自身的一個(gè)屬性而不是 Person 類的共有的屬性:

function?Person1(name)?{
????this.name?=?name;
}
Person1.prototype.introduceSelf?=?function?()?{
????console.log("My?name?is?"?+?this.name);
};
var?a?=?new?Person1("Tom");
var?b?=?new?Person1("Jerry");
console.log(a.introduceSelf?===?b.introduceSelf);?//?輸出?true
delete?a.introduceSelf;
a.introduceSelf();?//?仍然會(huì)輸出?My?name?is?Tom,因?yàn)?introduceSelf?不是?a?自身的屬性,不會(huì)被?delete?刪除
b.introduceSelf?=?function?()?{
????console.log("I?am?a?pig");
};
Person1.prototype.introduceSelf.call(b);?//?輸出?My?name?is?Jerry
//?即使?b?的?introduceSelf?屬性被覆蓋,我們?nèi)匀豢梢酝ㄟ^?`Person1.prototype`?來讓?b?執(zhí)行?Person1?類規(guī)定的行為。
function?Person2(name)?{
????this.name?=?name;
????this.introduceSelf?=?function?()?{
????????console.log("My?name?is?"?+?this.name);
????};
}
a?=?new?Person2("Tom");
b?=?new?Person2("Jerry");
console.log(a.introduceSelf?===?b.introduceSelf);?//?輸出?false
//?a?的?introduceSelf?屬性與?b?的?introduceSelf?屬性是不同的對象,分別占用不同的內(nèi)存空間。
//?因此這種方法會(huì)造成內(nèi)存空間的浪費(fèi)。
delete?a.introduceSelf;
a.introduceSelf();?//?會(huì)拋?TypeError
b.introduceSelf?=?function?()?{
????console.log("I?am?a?pig");
};
//?此時(shí)?b?的行為已經(jīng)與?Person2?類規(guī)定的脫節(jié),對象?a?和對象?b?看起來已經(jīng)不像是同一個(gè)類的對象了

但是這種方法也不是一無是處。例如我們需要利用閉包來實(shí)現(xiàn)對 name 屬性的封裝時(shí):

function?Person(name)?{
????this.introduceSelf?=?function?()?{
????????console.log("My?name?is?"?+?name);
????};
}
var?someone?=?new?Person("Tom");
someone.name?=?"Jerry";
someone.introduceSelf();?//?輸出?My?name?is?Tom
//?introduceSelf?實(shí)際用到的?name?屬性已經(jīng)被封裝起來,在?Person?構(gòu)造函數(shù)以外的地方無法訪問
//?name?相當(dāng)于?Person?類的一個(gè)私有(private)成員屬性

3. JavaScript 的類繼承

類的繼承實(shí)際上只需要實(shí)現(xiàn):

1. 子類的對象擁有父類定義的所有成員屬性;

2. 子類的任何一個(gè)構(gòu)造函數(shù)都必須在開頭調(diào)用父類的構(gòu)造函數(shù)。

實(shí)現(xiàn)第 2 點(diǎn)的方式比較直觀。而怎樣實(shí)現(xiàn)第 1 點(diǎn)呢?其實(shí)我們只需要讓子類的構(gòu)造函數(shù)的 prototype 屬性?(子類的實(shí)例對象的原型)?的原型是父類的構(gòu)造函數(shù)的 prototype 屬性?(父類的實(shí)例對象的原型),簡而言之就是:把父類實(shí)例的原型作為子類實(shí)例的原型的原型。這樣在訪問子類的實(shí)例對象的屬性時(shí),JavaScript 會(huì)沿著原型鏈找到子類規(guī)定的成員屬性,再找到父類規(guī)定的成員屬性。而且子類可在子類構(gòu)造函數(shù)的 prototype 屬性中重載(override)父類的成員屬性

3.1 代碼示例

下面給出一個(gè)代碼示例,定義一個(gè) ChinesePerson 類繼承上文中定義的 Person 類:

function?ChinesePerson(name)?{
????Person.apply(this,?name);?//?調(diào)用父類的構(gòu)造函數(shù)
}
ChinesePerson.prototype.greet?=?function?(other)?{
????console.log(other?+?"你好");
};
Object.setPrototypeOf(ChinesePerson.prototype,?Person.prototype);?//?將?Person.prototype?設(shè)為?ChinesePerson.prototype?的原型

var?someone?=?new?ChinesePerson("張三");
someone.introduceSelf();?//?輸出“My?name?is?張三”
someone.greet("李四");?//?輸出“李四你好”

上述定義 ChinesePerson 類的代碼改用 ECMAScript 6 的類聲明語法的話,就變成:

class?ChinesePerson?extends?Person?{
????constructor(name)?{
????????super(name);
????}

????greet(other)?{
????????console.log(other?+?"你好");
????}
}

3.1.1 重載父類成員屬性的代碼示例

你會(huì)不會(huì)覺得上面代碼示例中,introduceSelf 輸出半英文半中文挺別扭的?那我們讓 ChinesePerson 類重載 introduceSelf 方法就好了:

ChinesePerson.prototype.introduceSelf?=?function?()?{
????console.log("我叫"?+?this.name);
};
var?someone?=?new?ChinesePerson("張三");
someone.introduceSelf();?//?輸出“我叫張三”

var?other?=?new?Person("Ba?Wang");
other.introduceSelf();?//?輸出?My?name?is?Ba?Wang
//?ChinesePerson?的重載并不會(huì)影響父類的實(shí)例對象

文中的兔紙圖片由作者提供,


推薦閱讀:

前端項(xiàng)目框架搭建隨筆 --- Webpack 踩坑記

freeCodeCamp 高級算法

[譯文] 如何在 JavaScript 中更好地使用數(shù)組

與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的javascript 本地对象和内置对象_JavaScript 的面向对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。