是 Ray 不是 Array

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

前言

JavaScript 用了原型繼承,所以代表有個叫作原型(prototype)的概念。

瞭解原型

首先我們知道物件可以有屬性和方法,然後我們可以使用點運算子取得屬性或方法,JavaScript 中所有物件、函數,都有原型屬性,而這個屬性會參考到另一個屬性通常被稱為 proto。

假設今天我們有一個 obj 的物件,底下有一個叫 prop1,所以我們可以透過 obj.prop1 來取得。

圖片

JavaScript 中所有物件、函數,都有原型屬性。

圖片

而這個屬性會參考到另一個物件,稱之為 proto,而 proto 也可以有屬性,例如 prop2,所以當我們要取用 prop2時就可以這樣寫 obj.prop2

圖片

而我們使用點運算子去取用 obj 中的 prop2 時,會找不到,所以他會往原型裡面找。

圖片

那原型物件也可以指向到另一個物件。

圖片

每個物件都可以有自己的原型,當這個 proto 裡面有一個 prop3,我們就可以用 obj.prop3 取得。

圖片

而這過程就像一個鏈子,所以又稱為原型鏈 (prototype chain),但是不要把他跟範圍鏈搞混了,雖然很相似,可是範圍鏈是尋找可以取用的變數,但原型鏈是尋找屬性及方法。

圖片

而一般來講這 proto 是隱藏起來的,所以我們才不用這樣撰寫 obj.proto.proto.prop3,只需要 obj.prop3 就好。

但是 JavaScript 中有一個很有趣的狀況,當若有第二個 obj 時,他可以指向同一個原型。

圖片

所以當我們呼叫 obj2.prop2,他一樣會回傳相同位子。

圖片

而以上這些就是原型及原型鏈個概念,只需要想簡單一點只是有一個特別的參考到我們的物件而已,那接下來我們直接來看點範例。

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}

這邊我們有兩個物件,接下來我們要將 john 設定成原型,但以下範例千萬不要使用於現實中,這只是為了簡單理解觀念而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}
// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
john.__proto__ = person;
console.log(john.getFullName());

圖片

為什麼不是抓到 Default?因為原型鏈的原因導致,所以點運算子會在 john 裡面找到 firstname,所以就會停下來不會再找了,接下來在加一點物件上去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}
// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
john.__proto__ = person;
console.log(john.getFullName());

var jane = {
firstname: 'jane',
}

// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
jane.__proto__ = person;
console.log(jane.lastname);
console.log(jane.getFullName());

圖片

相信看到這邊已經越來越清楚怎麼跑了。

圖源

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

古典和原型繼承

圖片

繼承表示一個物件取用另一個物件屬性或方法,只要了解其簡單觀念就好了,許多人在解釋這區塊時常會用各種火車、汽車等等例子來做舉例,但講師認為直接講清楚會比較簡顯易懂。

那古典繼承和原型繼承是什麼呢?古典繼承在 C#、Java 裡都有,而且非常熱門。

而古典繼承裡面有非常多方法可以用

  • friend
  • protected
  • private
  • interface

但我們必須了解他才能夠知道該如何操作。

原型繼承呢?東西就簡單許多了

  • 彈性 (flexible)
  • 可擴充性 (extensible)
  • 簡單易懂 (east to understand)

古典和原型繼承各自都有他的好壞,所以並沒有一定,所以當有人在講繼承時,就是在講

一個物件取用另一個物件屬性或方法

圖源

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

物件與函數的章節結尾

圖片

以往我對於 IFFE 及閉包的觀念其實並不是很清楚,儘管先前已經寫過一些文章有類似,但是總覺得哪邊好像怪怪的?

而且其實我也沒想過在 JavaScript 函數就是物件這個想法,經過深入了解才知道這個問題,更不用說自動插入分號了。

最後的兩堂課其實我覺得非常不錯,但是說真的必須要多花點時間去練習就是了…

好哩,那就繼續往下深入吧。

圖源

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

前言

前面我們已經了解到 函數程式設計 的強大,所以這堂課將會花點時間來講一些資源例子。

underscore.js

underscore.js 是一個滿有名的 JavaScript 資源庫,可以幫助我們處理陣列及物件。

講師也建議我們可以從這些開源資料來了解進而學習,但要挑戰之前我們一定要有觀念,所以這堂課也希望我們可以藉由開源的資料來幫助我們學習了解函數程式設計。

Lodash

Lodash與 underscore 類似,但執行速度比 underscore 快。

但作者建議我們去 underscore 看一下學習了解 underscore 如何撰寫,這可以協助我們更加深了解函數程式設計。

最後我附上我找的幾個資源

underscore.js (1.7.0) 中文版

Underscore.js (1.9.1) 中文版

UnderscoreJS精巧而强大工具包

圖源

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

前言

在討論完一級函數及各種 JavaScript 之後準備來討論講師喜歡的主題【函數程式設計 (function Programmin)】

函數程式設計 (function Programmin)

以往我們很多人都會以為 JavaScript 會跟 Java 有關係,甚至看起來很像 C++、C#等,但講師是說 JavaScript 和函數程式語言比較有關係(Lisp、Scheme、ML),所以我們從範例來了解什麼是 函數程式設計 (function Programmin)。

1
2
3
4
5
6
7
var arr1 = [1, 2, 3];
console.log(arr1);
var arr2 = [];
for (var i = 0; i< arr1.length; i++) {
arr2.push(arr1[i] * 2);
}
console.log(arr2);

圖片

通常身為程式設計師我們都會盡可能減少自己的工作量,所以都會將重複性較高的動作包裝至一個函數內,那如果在沒有一級函數的狀況下我們所做的事情是有限的,所以我們可以利用一級函數來製作函數程式設計,然後將上面這個範例做修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function mapForEach(arr, fu) {
var newArr = [];
for (var i = 0; i< arr1.length; i++) {
newArr.push(
fu(arr[i])
);
}
return newArr;
}
var arr1 = [1, 2, 3];
var arr2 = mapForEach(arr1, function(item) {
return item * 2;
});
console.log(arr2)

圖片

我們可以看到 函數程式設計 的強大,所以也可以拿來做比較。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function mapForEach(arr, fu) {
var newArr = [];
for (var i = 0; i< arr1.length; i++) {
newArr.push(
fu(arr[i])
);
}
return newArr;
}
var arr1 = [1, 2, 3];
var arr2 = mapForEach(arr1, function(item) {
return item > 2;
});

console.log(arr2);

圖片

這樣就可以重複不停地利用函數,而這就是 函數程式設計 的經典例子。

那如果拿來檢查是否有超過特定數值呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function mapForEach(arr, fu) {
var newArr = [];
for (var i = 0; i< arr1.length; i++) {
newArr.push(
fu(arr[i])
);
}
return newArr;
}
var arr1 = [1, 2, 3];

var checkPastLimt = function (limiter, item) {
return item > limiter;
}

var arr2 = mapForEach(arr1, checkPastLimt.bind(this, 1));
console.log(arr2);

圖片

但是有些時候 bind 很煩,所以這邊可以試著不要在 mapForEach(arr1, checkPastLimt.bind(this, 1)) 使用 bind 來限制值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function mapForEach(arr, fu) {
var newArr = [];
for (var i = 0; i< arr1.length; i++) {
newArr.push(
fu(arr[i])
);
}
return newArr;
}
var arr1 = [1, 2, 3];

var checkPastLimt = function (limiter, item) {
return item > limiter;
}

var checkPastLimtSimplified = function (limiter) {
return function (limiter, item) {
return item > limiter;
}.bind(this, limiter)
}

var arr2 = mapForEach(arr1, checkPastLimtSimplified(2));
console.log(arr2);

圖片

後記

從課程範例下來其實可以發現函數程式設計真的很強大,但是需要很強大的觀念,不常常練習是很難的,現階段自己也很難做出來,希望遲早自己也能夠寫出函數程式設計。

圖源

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

前面講完了閉包、一級函數等等,說真的就跟課程老師講的一樣,腦袋快有點爆炸了,所以這邊只延續上一章節的的相關資訊做延伸,一般來講如果我們在 JavaScript 使用過 setTimeout、jQuery,這些其實都是使用了閉包,所以這章節要來聊聊閉包和回呼 (callback)。

閱讀全文 »
0%