Số – Number

Không như nhiều ngôn ngữ lập trình khác, kiểu số thường chia ra làm nhiều loại như integer, short, long. float… Riêng Javascript chỉ có kiểu number

Số nguyên trong Javascript có độ chính xác đến 15 chữ số

var x = 999999999999999;   // x sẽ là 999999999999999
var y = 9999999999999999;  // y sẽ là 10000000000000000

Giới hạn của số thập phân là 17 chữ số, nhưng không phải việc tính toán số thập phân lúc nào cũng chính xác 100%. Tìm hiểu floating-point

var x = 0.2 + 0.1;         // x sẽ bằng 0.30000000000000004

Để giải quyết điều này, chúng ta nên nhân nó thành số nguyên rồi thực hiện

var x = (0.2 * 10 + 0.1 * 10) / 10;       // x sẽ bằng 0.3

Nếu cộng 2 số thì kết quả sẽ là số. Nhưng nếu chuỗi cộng với số thì kết quả là chuỗi. Vậy nên khi tính toán thì nên chuyển hết về dạng số

var x = "10";
var y = 20;
var z = x + y;           // z sẽ là 1020 (một string)

NaN – Not a Number

NaN là một giá trị trong Javascript dùng để xác định một số không phải là một số hợp lệ

var x = 100 / 'Apple' // x sẽ là NaN (Not a Number)
typeof NaN // returns "number"

// chúng ta có thể dùng function isNaN() để kiểm tra giá trị có phải là NaN hay không
isNaN(x) // return true

Infinity – Dương vô cực

Infinity nghĩ là dương vô cực, -Infinity nghĩa là âm vô cực

var x = 2 / 0 // x sẽ là Infinity
var y = -2 / 0 // y sẽ là -Infinity
typeof Infinity // returns "number"

Hexadecimal – Hệ thập lục phân

Nếu bạn biểu diễn bắt đầu bằng 0x thì JS sẽ hiểu đây là hệ thập lục phân

var x = 0xff // x sẽ là 255

Một số phương thức hay dùng

toString(): Ép kiểu số về chuỗi

var x = 123
x.toString() // '123'
(123).toString() // '123'

toFixed(): Làm tròn

var x = 9.656;
x.toFixed(0);           // returns 10
x.toFixed(2);           // returns 9.66
x.toFixed(4);           // returns 9.6560
x.toFixed(6);           // returns 9.656000

Ép kiểu về số

Chúng ta có 3 cách

  • Number() chuyển đổi giá trị về kiểu số
  • parseInt() chuyển đổi giá trị về kiểu số nguyên
  • parseFloat() chuyển đổi giá trị về kiểu số thập phân
Number(true);          // returns 1
Number(false);         // returns 0
Number("10");          // returns 10
Number("  10");        // returns 10
Number("10  ");        // returns 10
Number(" 10  ");       // returns 10
Number("10.33");       // returns 10.33
Number("10,33");       // returns NaN
Number("10 33");       // returns NaN
Number("John");        // returns NaN
parseInt("10");         // returns 10
parseInt("10.33");      // returns 10
parseInt("10 20 30");   // returns 10
parseInt("10 years");   // returns 10
parseInt("years 10");   // returns NaN
parseFloat("10");        // returns 10
parseFloat("10.33");     // returns 10.33
parseFloat("10 20 30");  // returns 10
parseFloat("10 years");  // returns 10
parseFloat("years 10");  // returns NaN

Chuỗi – String

Chuỗi có thể được chứa trong nháy đơn hoặc nháy kép. Vị trí đầu tiên của chuỗi là 0.

var carName1 = "Volvo XC60";  // Double quotes
var carName2 = 'Volvo XC60';  // Single quotes

Một số phương thức hay dùng

length trả về độ dài của chuỗi

var txt = 'Duoc'
var sln = txt.length // 4

indexOf() trả về vị trí đầu tiên của từ khóa trong một chuỗi. Nếu không có sẽ trả về -1

var str = "Please locate where 'locate' occurs!"
var pos = str.indexOf('locate') // 7

Tách chuỗi

Có 3 phương thức tách chuỗi

slice(start, end): Tách từ vị trí start đến vị trí end – 1

var str = 'Apple, Banana, Kiwi'
var res = str.slice(7, 13) // Banana

//Nếu tham số là giá trị âm thì vị trí sẽ được đếm từ phía sau
str.slice(-12, -6) // Banana

//Nếu không có tham số thứ 2 thì coi như đếm đến cuối
str.slice(7) // Banana, Kiwi
str.slice(-12) // Banana, Kiwi

substring(start, end): Tương tự với slice nhưng không thể nhận giá trị âm

var str = 'Apple, Banana, Kiwi'
var res = str.substring(7, 13) // Banana

substr() tương tự slice() nhưng tham số thứ 2 là độ dài chuỗi

var str = 'Apple, Banana, Kiwi'
var res = str.substr(7, 6) // Banana
str.substr(7) // Banana, Kiwi
str.substr(-4) // Kiwi

replace(): Thay thế chuỗi

var str = 'Please visit Microsoft and Microsoft!'
var n1 = str.replace('Microsoft', 'W3Schools') 
var n2 = str.replace(/Microsoft/g, "W3Schools");
console.log(n1) // Please visit W3Schools and Microsoft!
console.log(n2) // Please visit W3Schools and W3Schools!

Chuyển đổi sang chữ hoa hoặc chữ thường (upper and lower case)

var text1 = 'Hello World!'
var text2 = text1.toUpperCase() // HELLO WORLD!
var text3 = text1.toLowerCase() // hello world!

concat(): Nối chuỗi

var text1 = 'Hello'
var text2 = 'World'
var text3 = text1.concat(' ', text2) // Hello World

trim(): Xóa khoảng trắng 2 bên chuỗi

var str = '       Hello World!        '
var newStr = str.trim() // Hello World!

charAt() hoặc []: Lấy ký tự từ một chuỗi

var str = 'HELLO WORLD'
str.charAt(0) // returns H
str[0] // returns H
str[0] = 'A' // Không bị lỗi nhưng đoạn code này không hoạt động

charCodeAt(): Lấy UTF-16 code tại vị trí bất kì trong chuỗi

var str = 'HELLO WORLD'
str.charCodeAt(0) // returns 72

split(): Chuyển chuỗi sang mảng. Tham số là chuỗi ngăn cách

const txt1 = 'a,b,c,d,e'
const array1 = txt1.split(',') // [ 'a', 'b', 'c', 'd', 'e' ]

// Nếu tham số là rỗng thì sẽ return về mảng từng ký tự
const txt2 = 'Hello'
const array2 = txt2.split('')  // [ 'H', 'e', 'l', 'l', 'o' ]

Mảng – Array

// Mảng có thể chứa nhiều kiểu dữ liệu bên trong
const cars = [{ name: 'BMW', location: 'germany' }, 'Toyota', 24]
console.log(cars[1]) // Toyota
cars[0].name = 'Mercedes'
console.log(cars) // [ { name: 'Mercedes', location: 'germany' }, 'Toyota', 24 ]

Một số phương thức và thuộc tính hay dùng

length: return độ dài mảng

const num = [1, 2, 3, 4]
num.length // 4

Array.isArray() hoặc instanceof để nhận biết một biến có phải là mảng hay không

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
Array.isArray(fruits) // true
fruits instanceof Array // true

toString() hoặc join() để chuyển mảng sang chuỗi

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
const str1 = fruits.toString() // Banana,Orange,Apple,Mango
const str2 = fruits.join('-') // Banana-Orange-Apple-Mango

push(): thêm 1 phần từ vào cuối mảng, return lại chiều dài mảng mới

const fruits = ['Banana', 'Orange', 'Apple']
const x = fruits.push('Mango') // giá trị của x là 4

pop(): xóa phần tử cuối cùng của mảng, return lại phần tử vừa xóa

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
const x = fruits.pop() // giá trị của x là Mango

shift(): xóa phần tử đầu tiên của mảng, return lại phần tử vừa xóa

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
const x = fruits.shift() // giá trị của x là Banana

unshift(): thêm 1 phần tử vào đầu mảng, return lại chiều dài mảng mới

const fruits = ['Orange', 'Apple', 'Mango']
const x = fruits.unshift('Banana') // giá trị của x là 4

Lưu ý khi dùng delete, phần tử sẽ bị mất khỏi mảng nhưng để lại 1 khoảng trống. Khi truy cập đến khoảng trống này thì giá trị của nó là undefined

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
delete fruits[0]
console.log(fruits) // [ <1 empty item>, 'Orange', 'Apple', 'Mango' ]
console.log(fruits.length) // 4

splice(vị trí thêm, số lượng cần xóa, … phần tử thêm): Hàm splice dùng để thêm hoặc xóa nhiều phần tử trong 1 mảng. Return về mảng với những phần tử vừa được xóa

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
// Thêm vào vị trí số 2
const x = fruits.splice(2, 0, 'Lemon', 'Kiwi')
console.log(x) // [] vì không xóa phần tử nào mà chỉ thêm
console.log(fruits) // [ 'Banana', 'Orange', 'Lemon', 'Kiwi', 'Apple', 'Mango' ]
const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
// Xóa 1 phần tử tại vị trí số 0
const x = fruits.splice(0, 1)
console.log(x) // [ 'Banana' ]
console.log(fruits) // [ 'Orange', 'Apple', 'Mango' ]

slice(vị trí bắt đầu, vị trí kết thúc): tách ra một mảng mới từ mảng cũ

const fruits = ['Banana', 'Orange', 'Apple', 'Mango']
// tách ra 1 mảng mới bắt đầu tại vị trí đầu tiên đến vị trí cuối
const newFruits = fruits.slice(1)
console.log(newFruits) // [ 'Orange', 'Apple', 'Mango' ]
console.log(fruits) // [ 'Banana', 'Orange', 'Apple', 'Mango' ]

// tách ra 1 mảng mới bắt đầu tại vị trí 1 đến 2 (3-1)
const newFruits2 = fruits.slice(1, 3)
console.log(newFruits2) //[ 'Orange', 'Apple' ]

concat(): Tạo mới một mảng bằng cách nối các mảng cũ

const myGirls = ['Cecilie', 'Lone']
const myBoys = ['Emil', 'Tobias', 'Linus']
const myChildren = myGirls.concat(myBoys) // [ 'Cecilie', 'Lone', 'Emil', 'Tobias', 'Linus' ]

spread operator : Phân rã mảng (object) thành từng phần tử nhỏ ( tưởng tượng [1,2,3] => 1,2,3)

const cars1 = [1, 2, 3]
const cars2 = [3, 4, 5]

// Nối mảng
const newCars = [...cars1, ...cars2] // [ 1, 2, 3, 3, 4, 5 ]

// Tạo thành 1 mảng mới
const cars3 = [...cars1] // [1, 2, 3]
console.log(cars1 !== cars3) // true

forEach(): Lặp qua từng phần tử trong mảng

tham số là một callback function với 3 đối số:

  • giá trị phần tử
  • index phần tử
  • mảng đang thực hiện
const numbers = [1, 2, 3, 4, 5, 6, 7]
const newNumbers = []
numbers.forEach((value, index, array) => {
    newNumbers.push(value)
})
console.log(newNumbers) // [1, 2, 3, 4, 5, 6, 7]

map(): Tạo một mảng mới bằng cách thực hiện tính toán trên mỗi phần tử. map() không thay đổi mảng cũ

const numbers = [1, 2, 3]
const newNumbers = numbers.map((value, index, array) => {
  return value * 2
})
console.log(newNumbers) // [2, 4, 6]

filter(): Tạo một mảng mới với những phần tử thỏa điều kiện

const numbers = [1, 2, 3]
const newNumbers = numbers.filter((value, index, array) => {
  return value >=2
})
console.log(newNumbers) // [2, 3]

find(): trả về phần tử thỏa điều kiện đầu tiên. Nếu không có sẽ return undefined

const numbers = [1, 2, 3]
const result = numbers.find((value, index, array) => {
  return value >= 2
})
console.log(result) // 2

findIndex(): trả về index của phần tử thỏa điều kiện đầu tiên. Nếu không có sẽ return -1

const cars = ['BMW', 'Toyota', 'Hyundai']
const result = cars.findIndex((value, index, array) => {
  return value === 'Toyota'
})
console.log(result) // 1

indexOf(): trả về index của phần tử trong mảng. Nếu không có sẽ return -1

const cars = ['BMW', 'Toyota', 'Hyundai']
const index = cars.indexOf('Toyota')
console.log(index) // 1

every(): Nếu mọi phần tử thỏa điều kiện sẽ return true, còn không sẽ return false

const numbers = [1, 2, 3]
const check = numbers.every((value, index, array) => {
  return value > 2
})
console.log(check) // false

some(): Nếu có một phần tử thỏa điều kiện sẽ return true, còn không sẽ return false

const numbers = [1, 2, 3]
const check = numbers.some((value, index, array) => {
  return value > 2
})
console.log(check) // true

includes(): Kiểm tra một phần tử có trong mảng hay không. return true/false

const numbers = [1, 2, 3, 4, 5]
const check = numbers.includes(5) // true

Thường thì các method với tring, array không thay đổi giá trị gốc. Ngoại trừ: pop, push, shift, unshift, delete

Object

  • entry của object là cặp key, value tương ứng. entry còn được coi như là property (thuộc tính) của object
  • key thì luôn luôn là một string hoặc number
  • value có thể là bất cứ giá trị nào của Javascript, kể cả function
  • method (phương thức) là những thuộc tính mà value của nó là function
const user = {
  name: 'Duoc',
  age: 24,
  greet() {
    console.log('Hello, Toi ten la ' + this.name)
  },
}
user.greet() // Hello, Toi ten la Duoc

prototype object

Prototype là cơ chế mà giúp các Javascript object thừa kế các tính năng từ các object khác.

Theo như các bài trước ta biết rằng JS có 2 kiểu data là kiểu nguyên thủy (numer, string, boolean…) và object. Nhưng nếu hiểu kĩ hơn thì ẩn sâu bên trong Javascript, ngoại trừ undefined thì toàn bộ các kiểu dữ liệu còn lại đều là object. Các kiểu string, number, boolean lần lượt là object dạng String, Number, Boolean. Mảng là object dạng Array, hàm là object dạng Function.

var str = 'abc'; // str là string, cha nó là String.prototype

// nhân đôi chuỗi đưa vào
String.prototype.duplicate = function() { return this + this; }

console.log(str.duplicate()); // Tìm thấy hàm duplicate trong prototype
// object literal
var person = {
  firstName: 'Du',
  lastName: 'Duoc',
  showName: function() {
    console.log(this.firstName + ' ' + this.lastName)
  },
} // object này có prototype là Object.prototype

// Constructor Function
function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
  this.showName = function() {
    console.log(this.firstName + ' ' + this.lastName)
  }
}

var otherPerson = new Person('Du', 'Duoc') // object này có prototype là Person.prototype
// Prototype mới: Person.prototype được tạo ra
// Person.prototype kế thừa Object.prototype

Thêm một phương thức vào object được tạo từ một constructor function

// STEP 0: tạo ra 1 hàm
function Student(name, age) {
  this.name = name
  this.age = age
}
// STEP 1: tạo 1 đối tượng s1 bằng toán tử new
const s1 = new Student('Du Thanh Duoc', 20)
// STEP 2: thêm một hàm sayHello() cho Student như sau:
Student.sayHello = function() {
  console.log('Hello')
}
// STEP 3: thêm 1 hàm showName() cho prototype của Student như sau:
Student.prototype.showName = function() {
  console.log('My name: ', this.name)
}
// STEP 4: Gọi lần lượt hai hàm trên từ s1:
s1.sayHello() // Lỗi, vì s1 ko có hàm sayHello, hàm này chỉ thuộc Student thôi.
s1.showName() // In ra: 'My name: Du Thanh Duoc'
// Cuối cùng, thử câu sau:
Student.sayHello() // In ra 'Hello'

Có thể sửa prototype của một function thông qua object (đối tượng) được tạo từ function đó

s1.__proto__.study = function() {
  console.log(`Tôi là ${this.name}, Tôi đang học bài.`)
}
// Thử tạo s2 và gọi s2.study()
const s2 = new Student('Badder Cuder', 30)
s2.study() // In ra: 'Tôi là Badder Cuder, Tôi đang học bài.'

Một số điều thú vị về __proto__.

  • Có thể coi prototype là đối tượng tạo ra __proto__
const user = {
  name: 'Duoc',
  age: 24,
  greet() {
    console.log('Hello, Toi ten la ' + this.name)
  },
  __proto__: {
    describe() {
      console.log('Toi ' + this.age + ' tuoi')
    },
  },
}
user.greet() // Hello, Toi ten la Duoc
user.describe() // Toi 24 tuoi

Một số phương thức thường thao tác với object

Đọc – thêm – sửa – xóa thuộc tính object

const person = {
  name: 'Duoc',
}
// đọc thuộc tính name
person.name
// thêm thuộc tính vào person
person.ability = ['dance', 'sing']
// sửa thuộc tính name
person.name = 'Alan'
// xóa thuộc tính name
delete person.name

Object.assign(): dùng để merge object

const person = {
  name: 'Duoc',
  ability: ['programing'],
}

const person2 = Object.assign(person, { ability: ['dance', 'sing'] })
console.log(person2) // { name: 'Duoc', ability: [ 'dance', 'sing' ] }

spread operator: dùng để shallow copy hoặc merge object

const person = {
  name: 'Duoc',
  ability: ['programing'],
}

const person2 = { ...person, ability: ['dance', 'sing'] }
console.log(person2) // { name: 'Duoc', ability: [ 'dance', 'sing' ] }

Object.keys(): trả về mảng các key của object

const person = {
  name: { firstName: 'Du', lastName: 'Duoc' },
  age: 24,
}
console.log(Object.keys(person)) // [ 'name', 'age' ]

Object.values(): trả về mảng các value của object

const person = {
  name: { firstName: 'Du', lastName: 'Duoc' },
  age: 24,
}
console.log(Object.values(person)) // [ { firstName: 'Du', lastName: 'Duoc' }, 24 ]

Lớp – Class

Class là tính năng của ES6 sinh ra để giải quyết cú pháp kế thừa prototype phức tạp bằng cách dùng classextends. Ẩn dưới class vẫn là prototype, lâp trình với class giống như lập trình bậc cao, còn prototype là bậc thấp vậy :mrgreen:

class Human {
  constructor(name) {
    this.name = name
  }
  sing() {
    console.log(`${this.name} đang hát...`)
  }
}

class Student extends Human {
  constructor(name, grade) {
    // Khởi tạo Human bên trong Student
    // truyền name vào constuctor của Human
    super(name)
    this.grade = grade
  }
  study() {
    console.log(`${this.name} có ${this.grade} điểm`)
  }
}
const duoc = new Student('Dư Thanh Được', 100)
// Student kế thừa hàm sing() từ Human, nên duoc có thể gọi
duoc.sing()
// duoc gọi hàm study(), bên trong study sử dụng "this.name",
duoc.study()

Khi bạn dùng extends thì nên khai báo super() ngay dưới constructor(), nếu không thì khi tạo đối tượng mới từ class sẽ bị lỗi!

Khai báo thuộc tính tĩnh (static property chưa phổ biến trên nhiều trình duyệt nên mình không đề cập) hoặc phương thức tĩnh (static method) với static

  • Lưu ý static method chỉ được gọi ở class, không thể gọi được ở đối tượng được tạo từ class
class Human {
  constructor(name) {
    this.name = name
  }
  static sing() {
    console.log(`${this.name} đang hát...`)
  }
}

Human.sing() // Human đang hát...
(new Human('Duoc')).sing() // Lỗi Human.sing(...) is not a function

get và set

class Human {
  constructor(name) {
    this._name = name
  }

  get name() {
    return this._name.toUpperCase()
  }

  set name(newName) {
    this._name = newName
  }
}

const duoc = new Human('Duoc')
duoc.name = 'Alan'
console.log(duoc.name) // ALAN

Tham khảo:

SERIES JAVASCRIPT SIDA – PỜ RỒ TÔ TAI (PROTOTYPE) LÀ CÁI GÌ

Class và Prototype trong JavaScript

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

https://www.w3schools.com/

https://developer.mozilla.org/