Primitive types vs objects 原生型態與 object 比較
Node.js Primitive types vs objects 原生型態與 object 比較
JavaScript 有 2 種資料類型
- Primitive: 原始 / 基本 ( 非物件 )
- Object: 物件
Primitive types 原生型態
- strings
- numbers (Number and BigInt)
- booleans (true or false)
- undefined
- Symbol values (ES6)
- null
null
是個特別的原生型態,透過 typeof null
你會得到 Object
,但其實他是原生型態
所有東西如果不是 Primitive type 原生型態
的話,都會是 object
let obj = {};
let str = 'KJ'
let und = undefined;
let num = 3;
let nul = null;
let bool = true;
let func = () => {}
// number
console.log(typeof num)
// undefined
console.log(typeof und)
// string
console.log(typeof str)
// boolean
console.log(typeof bool)
// function
console.log(typeof func)
// object
console.log(typeof obj)
// object
console.log(typeof nul)
Object type
- Object
- Function
- Array
- Set
primitive types 與 Object type 比較
屬性 | primitive types | Object type |
---|---|---|
immutable 不可改變 | 不可改變 | 可改變 |
變數傳遞方式 | passed by value 傳值 | passed by reference 傳址 |
變數複製方式 | copied by value 複製值 | copied by reference 複製參照位址 |
比較方式 | compared by value 比較數值 | compared by reference 比較位址 |
變數傳遞方式
Primitive
let name = 'Kay';
let secondName = name;
name = 'Jay';
// Jay
console.log(name);
// Kay
console.log(secondName);
非 Primitive
let employee = {
name: 'Kay'
};
let secondEmployee = employee;
employee.name = 'Jay';
// { name: 'Jay' }
console.log(employee);
// { name: 'Jay' }
console.log(secondEmployee);
// true
console.log(employee === secondEmployee);
let employee = {
name: 'Kay'
};
let secondEmployee = {
name: 'Kay'
};
// false
console.log(employee === secondEmployee);
宣告兩個 objective type 讓 key-value 值完全相同
,但是兩者比較後,回傳是 false
,因為 by reference 在比較時,真正比的是兩者的位置
,所以 個別的 Array 、Object 永遠不會相同。
比較變數
// false
console.log([] === []);
// false
console.log({} === {});
// false
console.log([1, 2, 3] === [1, 2, 3]);
// false,NaN 永遠不會等於自己,要比對可以用 isNaN()
console.log(NaN === NaN);
變數類型
String 字串
字串比較特別,還有一個特色叫 immutable
,當使用String.prototype methods做任何操作都不會影響到原字串
let s = 'javascript';
s.toUpperCase();
s.slice(-4);
s.concat('es6');
s[3] = 'x';
// javascript
console.log(s)
// a
console.log(s[3])
let newString = s.concat(' es6');
// javascript es6
console.log(newString);
在改變字串後,必須要用變數去接收這個改變的值
Array 陣列
let arr = [
'Kay',
'Jay'
];
// 複製陣列
let copyArr = arr;
copyArr[1] = 'KK';
// [ 'Kay', 'KK' ]
console.log(arr);
// [ 'Kay', 'KK' ]
console.log(copyArr);
Object Type 複製
Array 複製
1. 使用 for 迴圈輪詢所有元素
const Employee = ['Kay', 'Jay']
const copyEmployee = []
for (let i = 0; i < Employee.length; i++) {
copyEmployee[i] = Employee[i]
}
copyEmployee[0] = 'KJ';
// [ 'Kay', 'Jay' ]
console.log(Employee);
// [ 'KJ', 'Jay' ]
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
2. 使用 Array.slice() 切割複製元素
const Employee = ['Kay', 'Jay']
// 用 Slice 切割不指定切割位置
const copyEmployee = Employee.slice()
copyEmployee[0] = 'KJ';
// [ 'Kay', 'Jay' ]
console.log(Employee);
// [ 'KJ', 'Jay' ]
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
3. 用 Array.concat() 重新連接陣列資料
const Employee = ['Kay', 'Jay']
// 用 concat 重新連接陣列資料
const copyEmployee = [].concat(Employee)
copyEmployee[0] = 'KJ';
// [ 'Kay', 'Jay' ]
console.log(Employee);
// [ 'KJ', 'Jay' ]
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
4. 用 …array 重新賦值到新的變數
const Employee = ['Kay', 'Jay']
// 用 ...array 重新賦值到新的變數
const copyEmployee = [...Employee];
copyEmployee[0] = 'KJ';
// [ 'Kay', 'Jay' ]
console.log(Employee);
// [ 'KJ', 'Jay' ]
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
5. 用 Array.from() 重新賦值到新陣列資料
const Employee = ['Kay', 'Jay']
// 用 from 重新賦值到新陣列資料
const copyEmployee = Array.from(Employee)
copyEmployee[0] = 'KJ';
// [ 'Kay', 'Jay' ]
console.log(Employee);
// [ 'KJ', 'Jay' ]
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
Object 複製
1. 使用 Object.assign() 重新賦值
const Employee = {
name: 'Kay',
age: 17
}
// 使用 Object.assign 重新賦值
const copyEmployee = Object.assign({}, Employee, {
name: 'KJ',
job: 'engineer'
});
// { name: 'Kay', age: 17 }
console.log(Employee);
// { name: 'KJ', age: 17, job: 'engineer' }
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
使用 …objedt 重新賦值到新的變數
const Employee = {
name: 'Kay',
age: 17
}
const copyEmployee = {...Employee, name: 'KJ', job: 'engineer' };
// { name: 'Kay', age: 17 }
console.log(Employee);
// { name: 'KJ', age: 17, job: 'engineer' }
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
3. 使用 JSON.stringify 及 JSON.parse 複製物件
若物件有多層巢狀結構的話,可以用這個方式複製,但效能較差
const Employee = {
name: 'Kay',
age: 17
}
// 使用 JSON.stringify 及 JSON.parse 複製物件
const copyEmployee = JSON.parse(JSON.stringify(Employee))
copyEmployee.name = 'KJ';
copyEmployee.job = 'engineer';
// { name: 'Kay', age: 17 }
console.log(Employee);
// { name: 'KJ', age: 17, job: 'engineer' }
console.log(copyEmployee);
// false
console.log(Employee === copyEmployee);
判斷變數實際類型
1. typeof
用 typeof 可以檢查資料型態,但在判斷 typeof null
的時候會回傳 object
let EmployeeArray = ['Kay', 'Jay'];
let EmployeeObject = {
name: 'Kay',
age: 17
}
let EmployeeFunc = () => {};
let EmployeeString = 'Kay';
let EmployeeUndefined = undefined;
let EmployeeNumber = 3;
let EmployeeBoolean = true;
let EmployeeNull = null;
// object
console.log(typeof EmployeeArray);
// object
console.log(typeof EmployeeObject);
// function
console.log(typeof EmployeeFunc);
// string
console.log(typeof EmployeeString);
// undefined
console.log(typeof EmployeeUndefined);
// number
console.log(typeof EmployeeNumber);
// boolean
console.log(typeof EmployeeBoolean);
// object
console.log(typeof EmployeeNull);
如果對一個未宣告或未賦值的變數做 typeof,會回傳 undefined
所以有些時候可以拿 typeof 來檢查變數是否存在。
2. Object.toString()
使用 Object.prototype.toString.call()
,回傳的字串後面就是這個變數的類型
let EmployeeArray = ['Kay', 'Jay'];
let EmployeeObject = {
name: 'Kay',
age: 17
}
let EmployeeFunc = () => {};
let EmployeeString = 'Kay';
let EmployeeUndefined = undefined;
let EmployeeNumber = 3;
let EmployeeBoolean = true;
let EmployeeNull = null;
let variableTypeArray = Object.prototype.toString.call(EmployeeArray);
let variableTypeObject = Object.prototype.toString.call(EmployeeObject);
let variableTypeFunc = Object.prototype.toString.call(EmployeeFunc);
let variableTypeString = Object.prototype.toString.call(EmployeeString);
let variableTypeUndefined = Object.prototype.toString.call(EmployeeUndefined);
let variableTypeNumber = Object.prototype.toString.call(EmployeeNumber);
let variableTypeBoolean = Object.prototype.toString.call(EmployeeBoolean);
let variableTypeNull = Object.prototype.toString.call(EmployeeNull);
// [object Array]
console.log(variableTypeArray);
// [object Object]
console.log(variableTypeObject);
// [object Function]
console.log(variableTypeFunc);
// [object String]
console.log(variableTypeString);
// [object Undefined]
console.log(variableTypeUndefined);
// [object Number]
console.log(variableTypeNumber);
// [object Boolean]
console.log(variableTypeBoolean);
// [object Null]
console.log(variableTypeNull);