深刻理解javascript按值傳遞與按引用傳遞

基本類型與引用類型

值類型(基本類型):String,Number,Boolean,Null,Undefined。
引用類型:Array、Object、Function、Date等有多個值構成的可變長度的複雜類型。javascript

基本類型與引用類型有什麼區別?

(1)基本類型的變量保存的是變量值,引用類型的變量保存的是內存地址;
(2)基本類型長度固定,在內存中佔據固定大小的空間,數據存放在棧內存中;引用類型能夠給對象添加屬性和方法,長度不固定,數據存放在堆內存中。引用類型的存儲須要棧區和堆區(堆區是指內存裏的堆內存)共同完成,棧區內存保存變量標識符和指向堆內存中該對象的指針,也能夠說是該對象在堆內存的地址;
(3)基本類型在賦值的時候拷貝值,引用類型在賦值的時候只拷貝地址,不拷貝值。html


基本類型與引用類型的複製

const num1 = 5;
const num2 = num1;

clipboard.png

const obj1 = {};
const obj2 = obj1;

clipboard.png

基本類型複製與引用類型複製,看不懂直接上代碼!!
// 測試引用類型傳值和數組類型傳值
const obj = {
  success: false,
  result: {
    name: '222'
  }
};
let name = obj && obj.result && obj.result.name; // name爲一個str,具體的值爲基礎類型,name這裏保存的是變量值,而不是引用地址
console.log(name); // 222
name = "333";
console.log(obj.result.name); // 222, name爲變量值,name的改變並不會影響到obj.result.name
obj.result.name = "44444";
console.log(obj.result.name); // 44444
console.log(name); // 333,name爲變量值,而非引用地址,與obj.result.name相互不影響,所以obj.result.name的改變也不會引發name的變化
const obj = {
  success: false,
  result: {
    name: '222'
  }
};
let result = obj && obj.result;
console.log(result);  // { name: '222' },obj.result是一個Object類型,這裏result存的是obj.result的引用地址,result和obj.result指向堆中的同一個地址,相互影響
obj.result.name = "44444";
console.log(obj.result.name); // '44444'
console.log(result); // { name: '44444' }
result.name = "xxxxx"; // 屬性修改,相互影響
console.log(obj.result); // { name: 'xxxxx' }
// result從新賦值,指向一個新的引用地址,此時result與obj.result指向不一樣地址,再也不相互影響
result = {
  name: 'ooooo'
};
console.log(result); // { name: 'ooooo' }
console.log(obj.result); // { name: 'xxxxx' }
const obj = {
  success: false,
  result: [0, 1]
};
let result = obj && obj.result;
console.log(result); //[0, 1],obj.result爲Array類型,result和obj.result指向堆中的同一個地址,相互影響
console.log(obj.result); // [0, 1]
result.push('aa'); // 數組的push操做是在原數組基礎上操做,並不生成一個新的數組,result和obj.result依然指向同一個地址,相互影響
console.log(result); // [0, 1, 'aa']
console.log(obj.result); // [0, 1, 'aa']
result = [0, 1, 2]; // result從新賦值,此時result指向堆中一個新的地址,result與obj.result指向不一樣地址,再也不相互影響
console.log(obj.result); // [0, 1, 'aa']
console.log(result); // [0, 1, 2]

函數參數傳遞按值類型仍是引用類型?

基本類型參數的傳遞與基本類型的複製同樣,傳遞的是變量值。java

function addTen(num) {
   num = num + 10;
   return num;
}
var count = 20;
var result = addTen(count);
console.log(count); // 20
console.log(result); // 30

引用類型參數的傳遞與引用類型的複製同樣,傳遞的是內存地址。數組

function setName(obj){
   obj.name = 'xxx';
   obj = {name: 'ppp'}; // obj指向一個新的地址,與person再也不指向同一個地址
   console.log(obj.name); // 'ppp'
}
const person = {name : 'oo'};
setName(person);
console.log(person.name); // ‘xxx’
官方解釋來一發:

ECMAScript中全部函數的參數都是按值傳遞的。函數

也就是說,把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。基本類型的傳遞如同基本類型的複製同樣,而引用類型值的傳遞,如同引用類型變量的複製同樣。

總結工具

很簡單,javascript函數參數都是按值傳遞(都是棧內數據的拷貝)。
基本類型傳的是值自己(由於直接把值存在棧內),引用類型傳的是對象在內存裏面的地址 (由於複雜對象存在堆內,因此在棧裏存對象所在的堆地址)。

基本類型與引用類型的檢測

typeof是檢測基本數據類型的最佳工具,可是對檢測引用類型,返回的都是object,並不能肯定是哪一種類型的對象,沒有意義。測試

基本類型:基本類型中的null,返回爲object,其餘的都能正常檢測出準確的類型。
typeof('aa'); // 'string'
typeof(123); // 'number'
typeof(NaN); // 'number'
typeof(cc); // 'undefined' 未定義變量undefined
typeof(undefined); // 'undefined'
typeof(true); // 'boolean'
typeof(null); // 'object'

引用類型:function是特殊類型,能夠直接用typeof來判斷是不是function。
typeof([]); // 'object'
typeof({}); // 'object'
typeof(function(){}); // 'function'

typeof總結:

clipboard.png

instanceof操做符能夠專門用來檢測引用類型,判斷當前對象是什麼類型的對象。
alert({name: 'aa'} instanceof Object); // true
alert([1, 2] instanceof Array); // true
alert(function(){} instanceof Function); // true
alert([1, 2] instanceof Object); // true 全部引用類型的值都是Object的實例,所以單獨的判斷instanceof Object並不能區分是數組,仍是函數等,instanceof應該用來檢測真正的對象實例。
alert(13 instanceof Number); // false 使用instanceof檢測基本類型的值,始終返回false,由於基本類型不是對象。
new Number(12) instanceof Number; // true
javascript最準確且簡便的方法:

clipboard.png


參考文獻

https://www.zhihu.com/questio...
https://www.cnblogs.com/focus...
https://www.cnblogs.com/telne...
https://www.jianshu.com/p/585...spa

相關文章
相關標籤/搜索