是 Ray 不是 Array

Welcome.Web.World
歡迎來到網路世界

這章節主要講解 ES6(JavaScript EcmaScript 2015 或 EcmaScript 6) 的部分,而這章節將講解 ES6 另一種建立物件與設定原型的方法。 class 在其他程式語言是非常受歡迎的,可以用來定義物件的方法、屬性等該做什麼,但前面有講過 JavaScript 本身並沒有類別 (class)。

閱讀全文 »

前面我們已經瞭解使用函數建構子建立物件的方式,我們也看過函數建構子的出現原因是為了模仿其他不能實作原型繼承的程式語言,所以這邊會有點尷尬,在其他的程式語言是使用 `class` 來定義物件該做什麼,然後再用 `new` 來建立物件,而這也就是函數建構子想模仿的事情。

閱讀全文 »

今天面試的時候面試官講到一個東西,但發現自己並不是很熟悉,所以這邊查一下資料試著理解成自己的東西並做一下筆記,方便自己回顧。

閱讀全文 »

前言

我們對於函數建構子已經有一個基本瞭解了,所以這邊就可以來討論一下內建的函數建構子。

內建的函數建構子

這邊將會開始講一下已經存在於 JavaScript 的內建函數建構子,所以我們可以看看內建的函數建構子有什麼,或許我們已經用了許多次,但不一定瞭解它。

來試著撰寫程式碼瞭解吧。

1
var a = new Number(3);

首先這是一個函數,一個函數建構子,用了首字母大寫的傳統。

圖片

我們可以看到輸出的是一個物件,為什麼?函數建構子會建立什麼?物件。

所以我們可以試試看我們所瞭解的內建建構子。

1
2
3
var a = new Number(3);
var b = new String('Hellow');
var c = new Object({firstname: 'jack'});

圖片

那函數建構子本身有原型,所以我們可以查看原型,而它內建一些方法。

1
2
var a = new Number(3);
Number.prototype

圖片

所以我們可以這樣使用

1
2
var a = new Number(3);
a.toFixed(2)

圖片

另外小提一下 b,並不是字串,也不是純值。

1
var b = new String('Hellow');

圖片

它是一個物件,所以我們才能夠這樣子使用 indexOf()

1
2
var b = new String('Hellow');
b.indexOf('e');

圖片

所以這些內建的函數建構子看起來很像是幫我們建議字串,但其實是物件,且包含了字串。

那其實下面這個做法

1
"Hello".length;

等於這個樣子

1
new String("Hello");

所以說下次若我們看到 new,例如 new Date

1
var a = new Date('2019/05/23');

圖片

我們其實是取得了一個物件,然後使用了 JavaScript 內建提供的方法。

圖片

而這些方法實際是存在於 Date

圖片

那如果今天我們要自己加入另一個原型呢?

1
2
3
4
5
String.prototype.isLengthGreaterThan = function (limit) {
return this.length > limit;
}

console.log('jack'.isLengthGreaterThan(3));

圖片

那這時候所有字串就都可以使用 isLengthGreaterThan 這個方法,而這就是原型繼承的強大,許多框架都會這樣做,但是撰寫時要注意不要複寫到原本提供的建構子。

字串可以這樣做,那數字呢?

1
2
3
4
5
6
7
8
9
10
String.prototype.isLengthGreaterThan = function (limit) {
return this.length > limit;
}

console.log('jack'.isLengthGreaterThan(3));

Number.prototype.isPositive = function () {
return this.length > 0;
}
console.log(10.isPositive());

圖片

得到了一個錯誤,為什麼?

雖然 JavaScript 會將字串轉換為物件,但數字並不會。

但是可以這樣寫

1
2
3
4
5
Number.prototype.isPositive = function () {
return this.length > 0;
}
var a = new Number(3);
console.log(a.isPositive());

圖片

所以我們可以替這些原型增加功能,進而方便我們。

圖源

JavaScript 全攻略:克服 JS 奇怪的部分

前言

這章節是關於「new」與函數的危險小叮嚀,在前面我們有大致上講過,當加上 new 時,會建立空的物件,然後 this 會指向空的物件,如果你不回傳任何東西的話,它會回傳新物件,但這邊就是函數危險的地方。

「new」與函數

如果今天我們忘記加上 new 會發生什麼事情呢?

1
2
3
4
5
6
7
8
9
function Person(first, last) {
console.log(this);
this.firstname = first;
this.lastname = last;
}

var john = Person('John', 'Doe');

console.log(john);

圖片

第一個我們可以發現 this 指向了 window,然後 JavaScript 並不知道我們要對這個函數執行,對他來講只是一個函數,也因為這樣子所以他只會回傳 undefined。

那這樣會有甚麼問題?當我們取用 proto 就會出現錯誤。

1
2
3
4
5
6
7
8
9
10
11
12
function Person(first, last) {
console.log(this);
this.firstname = first;
this.lastname = last;
}
Person.prototype.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}

var john = Person('John', 'Doe');

console.log(john.getFullName());

圖片

這個錯誤是因為 john 是一個 undefined,所以無法取得方法。

通常這都是大家認為的函數建構子缺點,但如果我們遵照一些規範來設計的話,就可以減少一些問題,例如任何我們要作為函數建構子的函數首字
母寫成大寫,第一個字母大寫,這樣子會比較方便於 debug,而這是一個傳統方式。

任何我們要作為函數建構子的函數,永遠都要第一個字母大寫作為建構子名稱。

圖源

JavaScript 全攻略:克服 JS 奇怪的部分

前言

我們已經知道函數建構子可以幫助新物件設定屬性及方法,但原型呢?所以接下來就要來做講檢該如何設定原型。

prototype

這是上一章節的範例

1
2
3
4
5
6
7
8
function Person(first, last) {
this.firstname = first;
this.lastname = last;
}

var john = new Person('John', 'Doe');

console.log(john);

當我們使用函數建構子的時候,就已經被 JavaScript 給準備好了,所以我們可以試著輸入 john.__proto__

圖片

我們會得到一個物件,不信?我收合給你看。

圖片

那這個物件是什麼?我們先前有講過函數就是物件,在 JavaScript 函數就是物件,然後所有物件都有原型屬性 (prototype property),但是一般來講我們並不會用到,他只是掛在那裏而已。

圖片

除非我們將函數作為函數建構子來使用。

圖片

讓我們來試試看。

1
2
3
4
5
6
7
8
9
10
11
12
function Person(first, last) {
this.firstname = first;
this.lastname = last;
}

Person.prototype.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}

var john = new Person('John', 'Doe');

console.log(john);

圖片

我們可以看到我們可以原型下有了 getFullName(),換一個角度來看。

圖片

所以我們可以知道,當然函數被當作函數建構子使用時,就會有原型,那為什麼我們要將 getFullName 放進原型內?我們也可以直接放在函數建構子內?

1
2
3
4
5
6
7
8
9
10
11
function Person(first, last) {
this.firstname = first;
this.lastname = last;
this.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = new Person('John', 'Doe');

console.log(john);

圖片

假設今天有一千種物件都放在 getFullName 內,就會佔據比較多的記憶體,但若放在原型上就會比較好。

以效能來講將重複的屬性與方法放在原型上會比較好,因為這樣做我們就不用每一次都在 Person 裡面加入物件,只需要將重複需要使用的放在原型,然後透過原型去取得使用就好了。

所以就可以這樣寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person(first, last) {
this.firstname = first;
this.lastname = last;
}

Person.prototype.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}

Person.prototype.getFormaFullName = function() {
return this.firstname + ', ' + this.lastname;
}

var john = new Person('John', 'Doe');
console.log(john);

var jack = new Person('John', 'Doe');
console.log(jack);

圖片

這樣兩者皆可以使用。

圖源

JavaScript 全攻略:克服 JS 奇怪的部分

0%