JS作用域&值類型與引用類型

01作用域以及值類型與引用類型

主題目(一)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var foo = 55
var bar = 66

function baz(num, foo) {
num = 100
foo = 100
bar = 100
console.log(num);
console.log(foo);
console.log(bar);
}

baz(foo, bar)
console.log(foo);
console.log(bar);

詳解

上面那幾行都只是在聲明變量以及函數,直到第13行。

在執行時,開始在全局作用域查找,找到之後把foo以及bar傳入參數內部,相當於

1
2
3
function baz(num = foo = 55 , foo = bar = 66) {
...
}

如果對值引用不懂得可以看我這篇文章

https://s95050937.github.io/2020/08/02/JS-post03/

從那篇文章可以知道絕對沒有一個變量指向另一個變量的情況發生,因此其實接下來對基本類型來說基本上不管怎麼改變引用的東西對外部也沒什麼改變,(當然引用對象會把指針賦值給他有可能藉由參數改變影響外部)

1
2
3
4
5
6
7
8
function baz(num, foo) {
num = 100 // 因為已經有參數num當然改變的是num
foo = 100 // 因為已經有參數foo當然改變的是foo
bar = 100 // 這裡可以發現在函數作用域裡面沒有bar因此到外部查找變量bar並改變他
console.log(num); // 100
console.log(foo); // 100
console.log(bar); // 100
}

從上面第四行的註解可想而知外部已經發生改變

1
2
console.log(foo); // 55
console.log(bar); // 100

可以發現若是函數沒有在自己的作用域定義自身的變量,很容易發生意想不到的結果

主題目二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name, age, height) {
this.name = name
this.age = age
this.height = height
}

function baz(person) {
person.name = 'foo'
person = new Person('Mike', 15, 1.85)
}

let Student1 = new Person('Banny', 25, 1.75)
console.log(Student1.name);
baz(Student1)
console.log(Student1.name);

詳解

基本上如果有看過上面我寫的那篇文章這題也是秒解

當第12行對象創建,接下來打印Student1.name 可以很直觀的知道會打印出Banny,也與事實相符

第14行

調用函數並把該對象轉給了baz裡面的參數baz(注意這時候傳入的是引用對象)

到這裡先看一下是內部的值是怎麼引用的

第八行

改寫name

1
person.name = 'foo'

可以發現下圖的Banny已經被改寫了,所以最後打印student.name才會變foo

第九行

改寫 person

1
person = new Person('Mike', 15, 1.85)

題外話(基本上開發也不會這樣搞)

函數若定義變量跟自身一樣情況

例子:

如果用let的話會報錯:

1
2
3
4
function foo(bar) {
let bar = 'haha'
console.log(bar);
}

但假如用var則不會,甚至會改變參數

1
2
3
4
5
6
function foo(bar) {
var bar = 'haha'
console.log(bar);
}

foo(30)