
Javascript是一門很靈活的語言,我們可以使用它動態地實現各種各樣的功能。但是動態帶來便利的同時,也存在一些令人費解的行為,稍不注意就會進入誤區一個接著一個的坑。雖然我使用JavaScript的時間還不算長,也是遇到了一些有意思的場景,一開始百思不得其解,弄清楚之后又讓我哭笑不得。現在就來跟大家一起分享一下。
語法糖帶來的淺拷貝
先來預測一下下面代碼的輸出內容:
const user = {name: 'zong',location: {city: 'Shanghai',state: 'Shanghai'}
};
const copy = Object.assign({}, user);
// 或者
// const copy = { ...user };
copy.location.city = 'Suzhou';
console.log('original: ', user.location);
console.log('copy:', copy.location);
輸出結果應該是:
original: {city: 'Shanghai',state: 'Shanghai'
}
copy: {city: 'Shanghai',state: 'Shanghai'
}
咦?為什么操作復制的對象會修改原來的對象呢?這是因為Object.assign
跟spread operator
只做了一層淺拷貝
,這意味著只有對象的第一層屬性會被復制,如果某個屬性是個嵌套的對象,那么只有引用會被復制,所以我們操作修改的對象的屬性影響到了原來的對象。
所以在我們這個例子中copy
的location
屬性將仍然指向原來user
對象對應的location
屬性。
JavaScript從右向左賦值的行為
function display() {var a = b = 10;
}display();console.log('b', typeof b === 'undefined');
console.log('a', typeof a === 'undefined');
輸出是:
b false
a true
這是因為JavaScript賦值操作符是從右向左的,這意味著我們的賦值操作也是從右向左來的,手先b
會被賦值10
,然后它被賦給了a
。
所以:
function display() {var a = b = 10;
}
等同于:
function display() {b = 10;var a = b;
}
所以b
沒有用var
聲明成了一個全局變量,所以在外部可以被訪問到,而a
只是個局部變量,所以外部會打印出a === undefined
為true
。

但是如果上面的代碼在嚴格模式
中執行的話,情況又不一樣了,由于嚴格模式不允許創建全局變量所以這段代碼會直接拋出異常。
提升
var num = 8;var display = function () {console.log(num);var number = 20;
};display();
猜猜這里的輸出結果是什么?它不是8
而是undefined
,這又是為什么?
這是因為JavaScript里面有個現象叫提升
。提升
是JavaScript中把變量聲明移到當前作用域最頂部的一種行為。
所以上面的代碼可以轉換成如下:
var num = 8;var display = function () {var num;console.log(num);num = 20;
};display();
我們可以看到只有聲明被移到了函數的最頂端,而賦值操作還在原地,所以這邊num
由于還未賦值會打印出undefined
。
delete的作用對象
const num = 1;const result = (function () {delete num;return num;
})();console.log(result);
這邊的代碼不會報出任何錯,因為我們是在number
類型上使用的delete
,它還是會打印出1
。
The delete
操作符被用來刪除一個對象的屬性,在這兒num
并不是一個對象所以它會返回這個變量對應的值,也就是1
。
const num = 1;const result = (function (num) {delete num;return num;
})(10);console.log(result);
上面的代碼將輸出10
。
這邊我們把10
作為參數傳給函數,同樣地delete
在這里對原始類型也不起作用,所以會照常打印出10
。
好啦,今天的分享就到這里啦,主要是在使用JavaScript的過程中可能會經常遇到的一些細節問題,希望能給大家帶來一丟丟的收獲,happy coding~