置頂 0%

JS 學習筆記

前言

這幾個禮拜花點時間把大神Kuro的重新認識 JavaScript 系列的文章讀完,過程中跟隨作者的每一篇文章練習編寫JS,自己認為補足了許多之前不熟悉的觀念和技術,因此我這篇就將自己學習遇到的問題和重點記錄下來吧!

指定 this 方式

func使用apply函式將this.t = 100的新變數增加到obj物件,有點像是把func裡面this指定的變數或方法複製到obj裡面去,因為在執行func.apply(obj)的時候,就會執行一次func裡面的code(func還回傳this.x的值123),所以在func裡面的針對this屬性的賦值動作都會定義到參數obj裡面,最後才會有像是複製屬性的行為。
另外call和apply其實結果都相同,只是在傳遞參數的時,call()第二以後的參數會作為參數傳進目標函式中,而apply()第二參數必須是陣列,並將陣列中的每個元素作為參數傳進目標函式中

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
x: 123
};

var func = function () {
var a = 50;
this.t = 100;
this.y = 10;
return this.x;
};
console.log(func.apply(obj)); //123
console.log(obj); // {x: 123, t: 100, y: 10}

bind()也會有一樣的複製效果

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
x: 123
};

var func = function () {
console.log(this);
var a = 50; //有
this.t = 100; //沒有
}.bind(obj);
console.log(obj); // {x: 123} 執行下面func後才會得到t: 100
func(); // {x: 123}
console.log(obj); // {x: 123, t: 100}

函式建構式

Cascade 也有人稱作 Fluent Interface,在function裡面會使用this.變數或this.方法,由於函式也是個物件,同時也可以將其視為 建構子(constructor),透過關鍵字new來建構物件的行為類似複製物件的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
var calNum = function(num){
this.num = num;

this.add = function(newNum) {
this.num += newNum;
return this;
};

this.sub = function(newNum) {
this.num -= newNum;
return this;
};

this.multi = function(newNum) {
this.num *= newNum;
return this;
};

this.division = function(newNum){
this.num /= newNum;
return this;
};
};

//var a = new calNum(100);
//new 如同下面兩個步驟
//-----------------
var a = {};
calNum.call(a, 100);
console.log(a); // {num: 100, add: ƒ, sub: ƒ, multi: ƒ, division: ƒ}
a.add(100).sub(50);
console.log( a.num ); // 150

function Person( name, age, gender ){
this.name = name;
this.age = age;
this.gender = gender;

this.greeting = function(){
console.log('Hello! My name is ' + this.name + '.');
};
}

var kuro = new Person( 'Kuro', 32, 'male');
kuro.greeting(); // "Hello! My name is Kuro."

var John = new Person( 'John', 10, 'male');
kuro.greeting(); // "Hello! My name is John."

defineProperty的get和set意義

如果你定義了 get 與 set 方法,表示你要自行控制屬性的存取,那麼就不能再去定義 value 或 writable 的屬性描述,
get和set只是定義在賦值與取值時候要做什麼行為而已

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var person = {
getName: function () {
return this.name;
}
};

Object.defineProperty(person, 'name', {
get: function(){
console.log('get');
return this._name_;
},
set: function(name){
console.log('set');
this._name_ = name;
}
});
console.log(person);
person.name = 'kevin';
console.log(person.getName());
1
2
3
4
5
6
7
8
9
10
11
var person = {
getName: function () {
console.log(this);
return this.name;
//return name; //定義name會往外開始找name這一個變數
}
};
person.name = 'kevin';
var name = 'test';
console.log(person.getName());
//var name = 'test'; //呼叫方法之後就看不到了

決定 this 的關鍵不在於它屬於哪個物件,而是在於 function「呼叫的時機點」
當你透過物件呼叫某個方法 (method) 的時候,此時 this 就是那個物件 (owner object)

1
2
3
4
5
6
7
8
9
10
var foo = function() {
this.count++;
};

foo.count = 0;

for( var i = 0; i < 5; i++ ) {
foo(); //undefined
}
console.log(foo.count) //還是0

Array常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let arrs = [1, 4, 2, 3, 0];
//var newArr = arrs.map(v => v * 2)
var newArr = arrs.map(function (v, index, arr) {
console.log(index);
return v * 2;
})

//var filterArr = arrs.filter(val => val > 1);
var filterArr = arrs.filter(function (val, index, arr) {
return val > 1;
});

//var sortArr = arrs.sort((a, b) => a - b);
var sortArr = arrs.sort(function (a,b) {
return a - b;
});
console.log(newArr); // [2, 8, 4, 6, 0]
console.log(filterArr); // [4, 2, 3]
console.log(sortArr); //[0, 1, 2, 3, 4]

浮點數轉整數

根據定義在JS中的數字背後都是以浮點數的方式運行 There is no such thing as an int in Javascript. All Numbers are actually doubles behind the scenes,我們習慣上還是會把整數或浮點數方開來看。在stackoverflow有人發問如果要將浮點數轉型成整數,但不希望四捨五入可以怎麼做(Converting a double to an int in Javascript without rounding ),我們可以有下面的作法。

1
2
3
4
5
6
7
8
9
10
var num = 1.85;
//四捨五入
console.log(Math.round(num));// 2
//無視四捨五入
console.log(Math.floor(num));// 1
console.log(num | 0); // 1
console.log(parseInt(num));// 1
//只取整數部分
console.log(Math.trunc(1.6)); // 1
console.log(Math.trunc(-1.6)); // -1

布林值比較

1
2
console.log('true' == true); // false,因為等同於 'true' == 1,但true == 1就會是true
console.log(100 == '100'); // 字串轉型成數字
  1. 比較的a 或 b其中一個為boolean,會在比較相等性之前將false轉0 / true轉1轉成數值型態
  2. 比較的a 或 b其中一個為String,而另一個是數值,同樣會將字符串轉成數值型態
  3. 比較的a 或 b其中一個是物件,另外一個不是,則會調用物件的valueOf()方法得到基本型別(如果其中一方是「物件」型別,而另一方是基本型別的情況下,則會先透過物件的 valueOf() 方法取得對應的基本型別的值,再進行後續的比較

補充:

  • null == undefined 會是true
  • NaN 不等於 NaN,不管是兩個等號或三個等號都一樣

Regular Expression

正規表達式都會包含兩個 /,後面的符號就會用跳脫字元\來表示,

1
2
3
4
5
6
7
8
9
10
11
12
var text = "A apple a day keeps the doctor away.I have pen , I have apple.Uh ! ApplePen!!";
console.log(text.match(/applezzs/ig));
console.log("123abc123zz23".match(/^\d.*3/g)); //123abc123zz23 greedy
console.log("123abc123zz23".match(/^\d.*?3/g)); //123
var match = /(hello) (\S+)/.exec('This is a hello world!');
console.log(match); // ['hello world!', 'hello', 'world!']

var text = "has-a-text";
function upper (match,p1){
return p1.toUpperCase()
}
text = text.replace(/-(\w)/g, upper);//"hasAText"
function funcAs(){
    return new Promise(function(resolve, reject){
        window.setTimeout(function(){
            console.log('A');
            resolve('A_print');
        }, (Math.random() + 1) * 1000);
    });
}

function funcBs(b){
    return new Promise(function(resolve, reject){
        window.setTimeout(function(){
            console.log('B');
            console.log(b);
            resolve('B_print');//成功傳到下一個參數
        }, (Math.random() + 1) * 1000);
    });
}

function funcCs(c){
    return new Promise(function(resolve, reject){
        window.setTimeout(function(){
            console.log('C');
            console.log(c);
            resolve('C_print');
        }, (Math.random() + 1) * 1000);
    });
}

var v = funcAs().then(funcBs).then(funcCs);

參考

  1. MVC 架構演進 — Single Source of Truth
  2. Regex 正規表示法 - 群組與環顧