xia的小窩

一起來coding和碼字吧

0%

js-函式

函式是一個多樣化的集合體,它會被視為一個單位去做執行。可以把它想程式一個副程式。

傳入值 → 函式 → 回傳值 ( 結果 )

首先是回傳值

呼叫函式是一種運算式,那現在我們撰寫一個簡單的函式

1
2
3
4
5
function hello(){
return ["hello"]
}

console.log(hello())

如果沒有回傳值將會出現 undefined

呼叫 vs 參考

1
2
3
4
5
function hello(){
return ["hello"]
}

console.log(hello())

現在我們知道執行這個程式的回傳值是 [ 'hello' ]

如果我們沒有加上括號……

1
2
console.log(hello)
// [Function: hello]

這個東西它在說明它只是在參考函式,和其他任何值一樣,不會被呼叫

現在我們使用別的方法呼叫函式

1
2
3
4
const test = hello;

console.log(test())
// [ 'hello' ]

也可以指派給物件

1
2
3
4
5
6
const test = {};

test.cat = hello;

console.log(test.cat());
// [ 'hello' ]

放進陣列…….

1
2
3
4
5
6
7
function hello(){
return ['hello']
}
const arr = [0, 1, 2, 3];
arr[1] = hello;
console.log(arr[1]());
// ['hello']

引數

也就是參數,我們直接來看一個例子

1
2
3
4
5
function test(a, b){
return [b, a * b]
}

console.log(test(2, 5))

括號裡面的 a, b 就是參數,這個參數只會在函式裡運作,而且只會在函式裡生存。

我們可以用下面這個例子證明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function main(x){
console.log(`在裡面 : x = ${x}`);
x = 5;
console.log(`傳值後: x = ${x}`);
}

const x = 3;
console.log(`傳值前: x = ${x}`);
main(x);
console.log(`傳值結束 : x = ${x}`);

// 傳值前 : x = 3
// 在裡面 : x = 3
// 傳值後 : x = 5
// 傳值結束 : x = 3

如果我們使用這種方式來修改函式內的物件型態

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function main(o){
o.msg = `test in func`
}

let o = {
msg : "msg",
}

console.log(`呼叫前的 o.msg : ${o.msg}`)
main(o)
console.log(`呼叫後的 o.msg : ${o.msg}`)

// 呼叫前的 o.msg : msg
// 呼叫後的 o.msg : test in func

這邊你就必須了解基本物件和值本身的差異~~

引數構成函式 ??

我們可以知道 f ( )f ( x ) 是不同的函式,但是在 JavaScript 沒有這種區別….

1
2
3
4
5
6
function main(x){
return `my word is ${x}`;
}

console.log(main());
// my word is undefined

這告訴我們可以用眾多數量的引數去呼叫任何函式,如果沒有提供的話電腦會自動生出 undefined

解構引數

我們可以解構賦值,也可以解構引數

1
2
3
4
5
6
7
8
9
10
11
12
13
function main({ sub, ver, obj, eas }) {
return `${sub} ${ver} ${obj} ${eas}`
}

const test = {
sub : "t",
ver : "e",
obj : "s",
eas : "t"
};

console.log(main(test));
// t e s t

上面的範例是物件,當然也可以使用陣列……

我們可以使用 擴張運算子 ,但是必須放在最後面……

1
2
3
4
5
6
7
8
9
10
function add(add, ...nums){
const test = [];
for (let i = 0; i < nums.length; i++){
test[i] = add + nums[i];;
}
return test;
};

console.log(add("1", "2", "3"));
// ['12', '13']

將函式當成物件

1
2
3
4
5
6
7
8
9
10
const test = {
name : "rex",
myFunc : function(){
return 'myFunc is loaded'
},
// or ......
myFuncA(){
return 'myFunc is loaded'
},
}

下面那種是新的簡寫語法,跟上面的原始版本的共用相同

this 關鍵字

當我們呼叫方法時,this 就代表呼叫的方法所屬物件的值

1
2
3
4
5
6
7
8
9
const test = {
name : 'rex',
great() {
return `my name is ${this.name}`
}
}

console.log(test.great())
// my name is rex

當我們呼叫 test.great() 時,this 關鍵字會綁定 test

重點在於,這種綁定是根據 呼叫函式的方式 ,而不是宣告函式的地方 。

this 會綁定 test 不是因為 great 是 test 的特性,而是因為我們用 test 呼叫它。

如果我們將同一個函式指派給一個變數時……

1
2
3
4
5
6
7
8
9
10
11
12
13
const test = {
name : 'rex',
great() {
return `my name is ${this.name}`
}
}

const cat = test.great;
console.log(cat === test.great);
console.log(cat());

// true
// my name is undefined

因為我們的呼叫方式改變了,JavaScript 不知道函式是在 test 裡宣告的,所以才會有 undefined 出現

function 裡的 function

使用 嵌套 的函式

1
2
3
4
5
6
7
8
9
10
11
12
13
const test = {
name : 'rex',
great : function(){
const x = 50
function crap(){
return x
}
return `cost ${ crap(x) }`;
},
};

console.log(test.great());
// cost 50

箭頭標記法

大家應該都看過類似的寫法,比如…..

1
const test1 = () => "hello world" 

這是在 ES6 才加入的語法糖

  • 可以省略 function 這個字
  • 如果只有一個引數可以省略括號
  • 如果只有一個運算式,可以省略 大括號 與 return 陳述式

箭頭函式一般函式 之間有兩個細微差異 :

  1. 都不能當成物件建構式來使用
  2. 箭頭函式不能使用 arguments 變數

call、apply 與 bind

我們使用 call 開始看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const test = {
name : 'test'
}

const great = {
name : 'great',
}

function com(){
return `for the test name : ${this.name}`
}

console.log(com());
console.log(com.call(test));
console.log(com.call(great));

// for the test name : undefined
// for the test name : test
// for the test name : great

在這邊可以看到藉由提供綁定一個 this 物件, call 可讓我們呼叫一個函式,注意, call 的第一個引數式你想要綁定的 this 值。

再舉個例子

1
2
3
4
5
6
7
8
9
10
11
12
13
function Day(dir, tue) { 
this.dir = dir;
this.tue = tue;
}

const cat = {
name: 'rex',
}

Day.call(cat, 1505, 'dig');
console.log(cat)

//{ name: 'rex', dir: 1505, tue: 'dig' }

現在換 apply 的部分

1
2
Day.apply(cat, [1505, 'dig']);
console.log(cat)

apply 跟 call 不同的地方在於它處理函式引數的方式不一樣。call 會直接處理引數, apply 則會使用陣列的方式。

至於 bind 的部分

1
2
3
4
5
const testbind = Day.bind(cat);
testbind(1501, '5566');
console.log(cat);

// { name: 'rex', dir: 1501, tue: '5566' }

bind 可以讓你 永遠 將一個函式指派給 this 。所以會產生很難發現的 bug ……