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);

参考资料