Kiểu dữ liệu (Data type)

Có 2 kiểu chính: Kiểu nguyên thủy và object.

Kiểu nguyên thủy (Primitive)

  • Number: 1, 6, 10.2, …
  • String: ‘du thanh duoc’, …
  • Boolean: true/false
  • Null
  • Undefined
  • Symbol (ES6)

Sự khác nhau giữa nullundefined

nullundefined bằng nhau về mặt giá trị nhưng  khác nhau về kiểu

typeof undefined           // undefined
typeof null                // object. Dù là object nhưng nó vẫn được xếp vào kiểu nguyên thủy nhé

null === undefined         // false
null == undefined          // true

undefined nghĩa là không có giá trị. undefined xuất hiện ở

// Biến chưa khởi tạo giá trị
let a
console.log(a) // undefined

// Thuộc tính không tồn tại trong object
let people = { name: 'Duoc' }
console.log(people.age) // undefined

// Thiếu param
function sum(a, b) {
  console.log(b)
}
sum(1) // log ra b là undefined

// function không return hoặc return undefined
function handle() {
  alert('XdevClass')
}
console.log(handle()) // undefined

null nghĩa là rỗng (khác với '' nghĩa là chuỗi rỗng), giá trị của nó là rỗng. null thường được dùng cho object mà không có giá trị như mong đợi.

Không thể truy cập thuộc tính của nullundefined

function getName(value) {
  return value.name
}
// Lỗi
getName(undefined) // TypeError
getName(null) // TypeError

Kiểu Object

Tất cả những kiểu không thuộc kiểu dữ liệu nguyên thủy được coi là kiểu Object

// Plain Object
var people = { name: 'Du Thanh Duoc', age: 24 }

// Array
var products = ['Iphone', 'Samsung', 'Xiaomi']

// Regular Expression
var regex = /ab+c/

// Function cũng được coi là 1 object
function sum(a, b) {
  return a + b
}

// Nhưng
typeof sum === 'function' // true

// null không được coi là object mặc dù
typeof null === 'object' // true

Với cách khai báo kiểu dữ liệu nguyên thủy như trên thì ta đang khai báo kiểu constructor. Ngoài ra ta có thể tạo một object cho boolean, number, string bằng các wrapper object như String, Number, Boolean.

var str = new String('Duoc')
console.log(typeof str) // object
console.log(str) // String {"Duoc"}
str === 'Duoc' // false
var num = new Number(1996)
var b = new Boolean(true)

Để lấy giá trị nguyên thủy từ các object trên thì ta dùng hàm valueOf()

var str = new String('Duoc') 
str.valueOf() // 'Duoc'

Chúng có thể đóng vai như một function để chuyển đổi về giá trị nguyên thủy

String(1996) // '1996'
Number('2020') // 2020
Boolean(0) // false

Tham trị và tham chiếu

Mình đã có một bài đầy đủ và chi tiết tại tại đây: Bạn đã thực sự hiểu về tham trị và tham chiếu Javascript?

Tham trị

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 đó.

// So sánh bằng giá trị
'abc' === 'abc' //true
24 === 24 // true

// Luôn luôn bất biến (immutable)
var num = 1
// Thêm thuộc tính name
num.name = 'XdevClass'
// Không hiệu nghiệm
console.log(num.name) // undefined

Tham chiếu

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.

// So sánh bằng tham chiếu
{} === {} // false

var names1 = ['Duoc']
var names2 = ['Duoc']
names1 === names2 // false

// Có thể thay đổi (mutate)
var people1 = {name: 'Jack'}
var people2 = people1
people2.name = 'Huge'
console.log(people1) // {name: 'Huge'}

Truthy và Falsy

Truthy và falsy là những giá trị mà Javascript khi ép về kiểu boolean sẽ cho ra true hoặc false. Giống như dùng Boolean(value) để ép kiểu vậy.

Các giá trị được cho là truthy: Chuỗi khác rỗng, số khác 0 và tất cả các object.

Vì thế: [] hay {} vẫn được cho là truthy

Boolean({}) // true
Boolean([]) // true

Các giá trị được cho là falsy: undefined, null, false, 0, NaN, ''

Khai báo biến, scope, hosting

Mình đã viết một bài siêu chi tiết về khai báo biến, scope và hoisting: Hiểu sâu về Hoisting, Scope trong Javascript

var

var khi khai báo trong function sẽ có funtion scope, còn lại là global scope

// function scope
function click() {
  var name = 'Duoc'
}
click()
console.log(name) // ReferenceError: name is not defined

// global scope
if (true) {
  var age = 24
}
console.log(age) // 24

var còn có tính chất hoisting, nghĩa là khai báo ở đâu đi nữa thì cũng được đưa lên đầu tiên

console.log(name)
var name = 'Duoc'

sẽ được biên dịch thành

var name
console.log(name) // undefined
name = 'Duoc'

ngoài ra còn có thể khai báo lại

var name = 'Duoc'
var name = 'Beck'

let

let sẽ có block scope

// Block scope
if (true) {
  let name = 'Duoc'
}
console.log(name) // ReferenceError

// Không thể khai báo lại
let age = 24
let age = 25 // SyntaxError: Identifier 'age' has already been declared

const

const cũng như let đều có block scope. Khi khai báo biến bằng const với kiểu dữ liệu nguyên thủy, thì biến đó sẽ không thể cập nhật giá trị mới.

// Không thể gán lại giá trị mới với giá trị nguên thủy
const name = 'Duoc'
name = 'Alex' //TypeError: Assignment to constant variable.

// Lưu ý với object
const person = { name: 'Duoc' }
person.name = 'Will'
console.log(person) // {name: 'Will'}

Lưu ý: Nếu bạn hỏi let và const có được Hoist hay không thì câu trả lời là có. let và const được Hoist nhưng bạn sẽ không thể truy cập chúng trước khi chúng thực sự được khai báo.

scope

Như đã tìm hiểu ở trên, có 3 loại scope

  • Global Scope
  • Function Scope
  • Block Scope.

hoisting

Ngoài các trường hợp trên thì hoisting còn xuất hiện với khai báo hàm (Function Declaration)

Với cách này thì function được Hoisting. Và Javascript cho phép chúng ta gọi một hàm trước khi hàm đó được khai báo.

hoisted() // Output: "This function has been hoisted."
function hoisted() {
  console.log('This function has been hoisted.')
}

Tham khảo

https://www.facebook.com/groups/AngularVietnam

https://www.w3schools.com/

https://developer.mozilla.org/