Photo by Mohammad Rahmani on Unsplash
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);
参考资料
- Primitive types vs objects in JavaScript
- JavaScript 的资料型别与资料结构 - JavaScript | MDN
- JS基础:Primitive type v.s Object types | by LeeBoy | Medium
- 标准内建物件 - JavaScript | MDN
- [第十七週] JavaScript 进阶: Primitive & Object 原始类型与物件的差异 | Yakim shu
- What’s an Object in JavaScript? - YouTube
Donate KJ 贊助作者喝咖啡
如果這篇文章對你有幫助的話,可以透過下面支付方式贊助作者喝咖啡,如果有什麼建議或想說的話可以贊助並留言給我
If this article has been helpful to you, you can support the author by treating them to a coffee through the payment options below. If you have any suggestions or comments, feel free to sponsor and leave a message for me!
方式 Method | 贊助 Donate |
PayPal | https://paypal.me/kejyun |
綠界 ECPay | https://p.ecpay.com.tw/AC218F1 |
歐付寶 OPay | https://payment.opay.tw/Broadcaster/Donate/BD2BD896029F2155041C8C8FAED3A6F8 |