Primitive trong JavaScript

In JavaScript, a primitive (primitive value, primitive data type) is data that is not an object and has no methods or properties. There are 7 primitive data types:

  • string
  • number
  • bigint
  • boolean
  • undefined
  • symbol
  • null

Most of the time, a primitive value is represented directly at the lowest level of the language implementation.

All primitives are immutable; that is, they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned to a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered. The language does not offer utilities to mutate primitive values.

Primitives have no methods but still behave as if they do. When properties are accessed on primitives, JavaScript auto-boxes the value into a wrapper object and accesses the property on that object instead. For example, "foo".includes("f") implicitly creates a String wrapper object and calls String.prototype.includes() on that object. This auto-boxing behavior is not observable in JavaScript code but is a good mental model of various behaviors — for example, why "mutating" primitives does not work (because str.foo = 1 is not assigning to the property foo of str itself, but to an ephemeral wrapper object).

Trong tất cả các ngôn ngữ lập trình đều có một khái niệm đó là kiểu dữ liệu. Đối với Javascript, về cơ bản có những kiểu dữ liệu như string, number, boolean, … 

Mục tiêu trong bài này là phân loại các kiểu dữ liệu và sự khác nhau giữa chúng. Cho nên mình sẽ không đi chi tiết hoặc liệt kê hết các kiểu dữ liệu trong Javascript đâu nhé.

Kiểu dữ liệu nguyên thủy (Primitive Type)

Là các kiểu dữ liệu như String, Number, Booeal, Null, Undefined, …

let str = "hello 'world' ";  // Dùng nháy kép, vì bên trong có nháy đơn
console.log(str) // hello 'world'

xem ra không có gì đặc biệt lắm, thử qua kiểu dữ liệu khác trong JS xem sao

Kiểu dữ liệu dạng Object (Reference Type)

là các kiểu dữ liệu như Array, Object, Function, …

Khác với kiểu nguyên thủy, khi mà khai báo biến A nào đó bằng với biến B (kiểu Reference) thì thực tế biến A trỏ địa chỉ vào biến B, nên khi A thay đổi thì B cũng thay đổi theo và ngược lại.

let obj = { a : 1 };
let second_obj = obj;
second_obj.a = 2;

console.log(obj) // { a : 2 }

Dễ và cơ bản đúng không nào, hi vọng các bạn hiểu được 2 loại dữ liệu này trong js, dù cơ bản nhưng nó giúp đỡ rất nhiều trong tương lai của bạn đấy.

Có 6 kiểu dữ liệu nguyên thủy (primitive data type): undefined, boolean, number, string, bigint, symbol. Khi ta sao chép giá trị biến này cho biến khác thì giá trị của 2 biến này độc lập và không liên quan với nhau. Ví dụ :

let a = 1
let b = a
b = 2
console.log(a) // 1
console.log(b) // 2

Dù gán b = a, nhưng khi b thay đổi thì a vẫn không thay đổi!

Khi giá trị thuộc kiểu dữ liệu nguyên thủy, biến sẽ chứa giá trị của biến đó.

Hình ảnh minh hoạ :

Reference type

Các bạn lưu ý là trong Javascript: object, array, function thì đều được coi là object cả nhé.

Khi gán hoặc sao chép dữ liệu thuộc kiểu object thì biến đó chỉ lưu địa chỉ của giá trị đó trên vùng nhớ. Nó không lưu giá trị được gán.

Gán object

ví dụ với array :

let arr1 = ['a', 'b']
let arr2 = cars1
arr2 = ['c', 'd']
console.log(arr1) // ['a', 'b']
console.log(arr2) // ['c', 'd']

Hình ảnh minh hoạ :

location1 đại diện cho địa chỉ vùng nhớ của array ['a','b']

location2 đại diện cho địa chỉ vùng nhớ của array ['c', 'd']

location1 khác location2

Nhìn vào sơ đồ trên ta thấy được ban đầu thì arr1 và arr2 đều lưu giá trị ô nhớ giống nhau (đều là location1) và chia sẻ cho nhau các thuộc tính bên trong array. arr1 và arr2 đều có giá trị ô nhớ giống nhau nhưng nó lại ở 2 mắt xích khác nhau, vì thế khi thay đổi arr2 bằng 1 giá trị khác (array khác) thì sẽ không ảnh hưởng đến arr2. Nếu như bạn thay đổi arr2[0] thì arr1[0] cũng sẽ thay đổi theo vì 2 vị trí này chia sẽ với nhau.

Thêm một ví dụ nữa để hiểu rõ hơn :

Thay đổi thuộc tính Object

const person1 = { name: 'Do Tuan', age: 23 }
const person2 = person1
person2.age = 20
console.log(person1) // { name: 'Do Tuan', age: 20 }
console.log(person2) // { name: 'Do Tuan', age: 20 }

Bạn đang thắc mắc tại sao khai báo bằng const rồi nhưng lại có thể thay đổi giá trị bên trong object được phải không? Thực ra thì khi bạn khai báo const kết hợp với object thì bạn sẽ không thể thay đổi object nhưng lại có thể thay đổi thuộc tính của nó.

Như ví dụ thì bạn không thể thay đổi person2 bằng một object mới được, mà chỉ có thể thay đổi person2.age hoặc person2.name. Điều này liên quan đến vùng nhớ như mình đã nói ở bên trên, nếu bạn thay đổi nguyên 1 object thì vùng nhớ của person2 sẽ thay đổi và const không cho phép nên sẽ gây lỗi. Nhưng nếu bạn thay đổi thuộc tính bên trong thì vùng nhớ object bên ngoài vẫn giữ nguyên.