Try   HackMD

JS 物件傳值?傳參考?|筆記 by Jiang

tags: Jiang Vue新手夏令營

JS 物件傳值?傳參考?

20210609 影片連結 source code

重新認識 JavaScript: Day 05 JavaScript 是「傳值」或「傳址」?
五分鐘快速了解 [傳址,傳參考,傳址]

內容大綱

  • 物件與純值
  • 物件傳參考的特性
  • 陣列、函式也是傳參考嗎?
  • 傳參考的運用情境
  • 如何避免傳參考
  • 各種運用技巧
  • 奇怪的題目
console.log('真相只有一個');

var person = '小明';
var person2 = person;
console.log(person, person2); // 一樣喔

var person = '小明';
var person2 = person;
person2 = '杰倫';
console.log(person === person2) // 不一樣喔
console.log(person, person2); 

var person = {
  name: '小明'
}
var person1 = person;
person1.name = '杰倫';
console.log(person === person1)
console.log(person) // 杰倫 
console.log(person.name); // 杰倫 

var member = ['爸', '媽'];
var member2 = member;
member2.push('小三');
console.log(member); // 有小三 

function fn(name) {
  return `${name}被抓到了`
}
var fn2 = fn;
fn2.magicName = '奇怪的東西';
// 不會出錯,正確的
console.log(fn2) // 從fn拷貝過來
console.log(fn===fn2) // true
console.log(fn2.magicName); //奇怪的東西
console.dir(fn2.magicName); 

function 函式(name) {
  return `${name}被抓到了`
}
console.log(函式('漂亮阿姨'));  // 中文化可以動  

var 名偵探 = console;
名偵探.柯南 = console.log;

// 名偵探.柯南(函式('漂亮阿姨'))

// ## let 5, const 6
// 沒有改變過指向,只有改變屬性值,建議用const
const person = {
  name: '小明'
}

// person.name = '杰倫';
名偵探.柯南(person)

// 1 const, 2 let
// 改變裡面的值而已,指向都沒變,可以用 const
const family = ['爸', '媽', '小三'];
family.forEach((item, key) => {
  if(item === '小三') {
    family.splice(key, 1)
  }
});
console.log(family);

function fn(item) {
  item.name = '杰倫';
}
const person = {
  name: '小明',
}
fn(person);
console.log(person); // 杰倫

function fn(item) {
  const newItem={
    name : '杰倫',
  }
  // item = newItem;
  // item.name = newItem;
  Object.keys(item).forEach(key => { // 把屬性取出來
    console.log(key) // key 對應到 name 屬性
    item[key] = newItem [key]; // 直接覆蓋取代
  })
  console.log('item', item);
}
const person = {
  name: '小明',
}
fn(person);
console.log(person); // 小明

#1 淺層複製

尚未用淺層複製
const person = {
  name: '小明'
}
const person2 =person;
person2.name = '杰倫';
console.log(person2.name, person.name);
console.log(person === person2); //這裡結果一樣喔

使用淺層複製 
const person = {
  name: '小明'
}
const person2 = { ...person }; // 用...展開來淺層複製
person2.name = '杰倫';
console.log(person2.name, person.name); // 兩個分開了
console.log(person === person2); // 用淺層複製就不一樣了

#2 深層複製

只用淺層拷貝
var person = {
  name: '小明',
  family: {
    name: '小明家',
    members: ['爸', '媽']
  }
}
const person2 = {...person};
person2.name = '杰倫';
person2.family.name = '杰倫家'
console.log(person, person2);
console.log(person.family === person2.family);  // 第一層結果不一樣,但第二層就同時改變了 因為指向同一個參考位置

使用深層拷貝
var person = {
  name: '小明',
  family: {
    name: '小明家',
    members: ['爸', '媽']
  }
}
const person2 = JSON.parse( JSON.stringify(person)); // JSON.stringify轉字串 JSON.parse再轉物件
person2.name = '杰倫';
person2.family.name = '杰倫家'
console.log(person, person2);
console.log(person.family === person2.family); // 兩者沒有關聯性了不相等

擴展:把原本的東西複製一份,再增加一些東西
const person = {
  name: '小明',
  fn: function() {
    console.log(`我叫作 ${this.name}`);
  }
};

const person2 = {
  ...person, // 直接記住 person
  name: '杰倫', // name 直接替換掉
};
person.fn();//小明
person2.fn();//杰倫

const family = [{name: '爸'}, { name: '媽' }];
family.forEach((item, key) => {
  const newItem = {
    name: '杰倫'
  };
  
  family[key] = newItem; 
  console.log('family[key]', family[key]);
  console.log('item', item);
});
console.log(family); // 有加上杰倫喔,蓋過去了

// 真地獄
var person = {
  name: '小明'
}
person.person = person;
console.log(person.person === person.person.person); //true 無限迴圈哈哈哈

// 真真真真真地獄 面試題目
var a = {
  x: '小明'
}
var b = a;
a.y = a = {
  x: '杰倫'
};

console.log(b === a); // false
console.log('a:', a ); 
console.log('b:', b );

// 1. a 結果
// 2. { x: '杰倫'}
// 3. 其它

console.log(b.y === a);
// 1一樣