Nội dung bài viết
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 null
và undefined
null
và undefined
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 null
và undefined
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.') }