thumb
2022-09-12 14:39:48.000

Phần 3: Thao tác với number, string, array, object và class trong Javascript

1. 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)
  

2. 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
  

3. 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"
  

4. 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
  

5. 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
  

6. 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
  

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

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


  var txt = 'Ben'
  var sln = txt.length // 3
  

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' ]
  

8. 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

9. 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: 'Ben',
    age: 28,
    greet() {
      console.log('Hello, My name is ' + this.name)
    },
  }
  user.greet() // Hello, My name is Ben
  

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: 'Anh',
    lastName: 'Ben',
    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('Anh', 'Ben') // 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('Nguyen Vu Hoang', 28)
  // 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: Nguyen Vu Hoang'
  // 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: 'Ben',
    age: 28,
    greet() {
      console.log('Hello, My name is ' + this.name)
    },
    __proto__: {
      describe() {
        console.log('I am' + this.age + ' years old')
      },
    },
  }
  user.greet() // Hello, My name is Ben
  user.describe() // I am 28 years old
  

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: 'Ben',
  }
  // đọ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/p>


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

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


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

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


  const person = {
    name: { firstName: 'Anh', lastName: 'Ben' },
    age: 28,
  }
  console.log(Object.keys(person)) // [ 'name', 'age' ]
  

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


  const person = {
    name: { firstName: 'Anh', lastName: 'Ben' },
    age: 28,
  }
  console.log(Object.values(person)) // [ { firstName: 'Anh', lastName: 'Ben' }, 28 ]
  

10. 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('Nguyen Vu Hoang', 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('Ben')).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
  
Share: