Tìm hiểu về ES6 trong Javascript

ES6 đề cập đến phiên bản 6 của ngôn ngữ lập trình ECMA Script. ECMA Script là tên chuẩn cho JavaScript và phiên bản 6 là phiên bản tiếp theo sau phiên bản 5 được phát hành vào năm 2011. Đây là một cải tiến lớn cho ngôn ngữ JavaScript và thêm nhiều tính năng để giúp việc phát triển phần mềm quy mô lớn dễ dàng hơn.

ECMAScript, hay ES6, đã được xuất bản vào tháng 6 năm 2015. Sau đó nó được đổi tên thành ECMAScript 2015. Hỗ trợ trình duyệt web đầy đủ cho ngôn ngữ vẫn chưa hoàn thành, mặc dù việc hỗ trợ cho các phần chính đã được tiến hành. Các trình duyệt web chính hỗ trợ một số tính năng của ES6. Tuy nhiên, có thể sử dụng phần mềm được gọi là trình chuyển đổi để chuyển đổi code ES6 thành ES5, vì ES5 được hỗ trợ tốt hơn trên hầu hết các trình duyệt.

ES6

Bây giờ, hãy xem xét một số thay đổi lớn mà ES6 mang lại cho JavaScript.

1. Hằng số

Cuối cùng khái niệm về các hằng số đã được đưa vào JavaScript! Hằng số là các giá trị chỉ có thể được xác định một lần (trong mỗi phạm vi được giải thích bên dưới). Hai giá trị cho một hằng số trong cùng phạm vi sẽ tạo ra lỗi.

const JOE = 4.0
JOE= 3.5
// results in: Uncaught TypeError: Assignment to constant variable.

Bạn có thể dùng hằng số ở bất cứ đâu bạn sử dụng một biến (var).

console.log("Value is: " + joe * 2)
// prints: 8

2. Các biến và các hàm có phạm vi khối

Các biến

Với ES6, các biến được khai báo sử dụng let (và các hằng số mô tả ở trên), tuân theo các quy tắc phạm vi khối giống như trong Java, C++, v.v...

Trước bản cập nhật này, các biến trong JavaScript là hàm scoped. Tức là, khi bạn cần một phạm vi mới cho một biến, bạn phải khai báo nó trong một hàm.

Các biến giữ nguyên giá trị cho đến cuối khối. Sau đó, giá trị trong khối ngoài (nếu có) được khôi phục.

{
let x = "hello";
{
let x = "world";
console.log("inner block, x = " + x);
}
console.log("outer block, x = " + x);
}
// prints
inner block, x = world
outer block, x = hello

Bạn cũng có thể xác định lại các hằng số trong các khối như vậy.

{
let x = "hello";
{
const x = 4.0;
console.log("inner block, x = " + x);
try {
x = 3.5
} catch(err) {
console.error("inner block: " + err);
}
}
x = "world";
console.log("outer block, x = " + x);
}
// prints
inner block, x = 4
inner block: TypeError: Assignment to constant variable.
outer block, x = world

3. Arrow Function (Hàm mũi tên)

Arrow function

ES6 đưa ra một cú pháp mới để xác định các hàm bằng cách sử dụng một mũi tên. Trong ví dụ sau, x là một hàm chấp nhận một tham số được gọi là a và trả về giá trị của nó:

var x = a => a + 1;
x(4) // returns 5

Sử dụng cú pháp này, bạn có thể xác định và chuyển các đối số trong các hàm một cách dễ dàng. Hãy sử dụng forEach():

[1, 2, 3, 4].forEach(a => console.log(a + " => " + a*a))
// prints
1 => 1
2 => 4
3 => 9
4 => 16

Xác định các hàm chấp nhận nhiều đối số bằng cách đặt chúng trong dấu ngoặc đơn:

[22, 98, 3, 44, 67].sort((a, b) => a - b)
// returns
[3, 22, 44, 67, 98]

4. Các tham số hàm mặc định

Các tham số hàm có thể được khai báo với các giá trị mặc định. Trong ví dụ sau, x là một hàm có hai tham số ab. Tham số thứ hai - b được gán một giá trị mặc định là 1.

var x = (a, b = 1) => a * b
x(2)
// returns 2
x(2, 2)
// returns 4

Không giống như các ngôn ngữ khác như C++ hoặc Python, các tham số có giá trị mặc định có thể xuất hiện trước những tham số không có giá trị mặc định. Lưu ý rằng hàm này được định nghĩa là một khối có giá trị return như sau:

var x = (a = 2, b) => { return a * b }

Tuy nhiên, đối số được kết hợp từ trái sang phải. Sau khi được gọi lần đầu như ví dụ bên dưới, b có một giá trị không xác định, mặc dù đã được khai báo với một giá trị mặc định. Đối số được truyền vào sẽ khớp với a thay vì b. Hàm trả về NaN.

x(2)
// returns NaN
x(1, 3)
// returns 3

Khi bạn chuyển undefined làm đối số, giá trị mặc định được sử dụng nếu có.

x(undefined, 3)
// returns 6

5. Các tham số hàm còn lại

Khi gọi một hàm, đôi khi có một nhu cầu phát sinh, nhằm truyền vào một số lượng đối số tùy ý và xử lý các đối số này trong hàm. Nhu cầu này được xử lý bằng các tham số hàm còn lại. Đây là cách để nắm bắt phần còn lại của các đối số, theo sau các đối số khác được xác định bằng cách sử dụng cú pháp hiển thị bên dưới. Các đối số này được ghi lại trong một mảng.

var x = function(a, b, ...args) { console.log("a = " + a + ", b = " + b + ", " + args.length + " args left"); }
x(2, 3)
// prints
a = 2, b = 3, 0 args left
x(2, 3, 4, 5)
// prints
a = 2, b = 3, 2 args left

6. String templating

String templating đề cập đến việc nội suy các biến và biểu thức thành chuỗi, bằng cách sử dụng một cú pháp như perl hoặc shell. Một template chuỗi được đính kèm trong các ký tự dấu kiểm ngược (`). Ngược lại, dấu nháy đơn (') hoặc dấu ngoặc kép (“) cho biết các chuỗi bình thường. Biểu thức bên trong mẫu được đánh dấu từ ${}. Đây là một ví dụ:

var name = "joe";
var x = `hello ${name}`
// returns "hello joe"

Tất nhiên, bạn có thể sử dụng một biểu thức tùy ý để đánh giá.

// define an arrow function
var f = a => a * 4

// set a parameter value
var v = 5

// and evaluate the function within the string template
var x = `hello ${f(v)}`
// returns "hello 20"

Cú pháp để xác định chuỗi này cũng có thể được sử dụng để xác định các chuỗi nhiều dòng.

var x = `hello world
next line`
// returns
hello world
next line

7. Thuộc tính đối tượng

ES6 đưa ra một cú pháp tạo đối tượng đơn giản. Hãy xem ví dụ dưới đây:

var x = "hello world", y = 25
var a = { x, y }
// is equivalent to the ES5:
{x: x, y: y}

Tên thuộc tính computed khá tiện lợi. Với ES5 và các phiên bản trước đó, để đặt cho thuộc tính đối tượng một cái tên mang tính computed, bạn phải thực hiện điều này:

var x = "hello world", y = 25
var a = {x: x, y: y}
a["joe" + y] = 4
// a is now:
{x: "hello world", y: 25, joe25: 4}

Bây giờ bạn có thể làm tất cả trong một bước xác định duy nhất:

var a = {x, y, ["joe" + y]: 4}
// returns
{x: "hello world", y: 25, joe25: 4}

Và tất nhiên, để xác định các phương thức, bạn chỉ có thể xác định nó bằng tên:

var a = {x, y, ["joe" + y]: 4, foo(v) { return v + 4 }}
a.foo(2)
// returns
6

8. Cú pháp xác định lớp chính thức

Xác định lớp

Và cuối cùng, JavaScript đưa ra một cú pháp xác định lớp chính thức. Trong khi nó chỉ đơn thuần là cú pháp tạo từ các lớp dựa trên prototype (nguyên mẫu) sẵn có, nó có vai trò tăng cường sự rõ ràng cho code. Điều đó có nghĩa là nó không thêm một đối tượng mới hoặc bất kỳ thứ gì như thế.

class Circle {
constructor(radius) {
this.radius = radius
}
}
// use it
var c = new Circle(4)
// returns: Circle {radius: 4}

Phương thức khai báo

Xác định một phương thức cũng khá đơn giản.

class Circle {
constructor(radius) {
this.radius = radius
}
computeArea() { return Math.PI * this.radius * this.radius }
}
var c = new Circle(4)
c.computeArea()
// returns: 50.26548245743669

Getter và Setter

Bây giờ, ta có gettersetter, với một cập nhật đơn giản cho cú pháp. Hãy xác định lại lớp Circle với thuộc tính area.

class Circle {
constructor(radius) {
this.radius = radius
}
get area() { return Math.PI * this.radius * this.radius }
}
var c = new Circle(4)
// returns: Circle {radius: 4}
c.area
// returns: 50.26548245743669

Bây giờ, hãy thêm một setter. Để có thể xác định radius dưới dạng thuộc tính có thể đặt trước, ta sẽ xác định lại trường thực tế thành _radius hoặc một thứ sẽ không xung đột với setter. Nếu không, ta sẽ gặp “stack overflow error” (lỗi tràn ngăn xếp).

Đây là lớp được xác định lại:

class Circle {
constructor(radius) {
this._radius = radius
}
get area() { return Math.PI * this._radius * this._radius }
set radius(r) { this._radius = r }
}
var c = new Circle(4)
// returns: Circle {_radius: 4}
c.area
// returns: 50.26548245743669
c.radius = 6
c.area
// returns: 113.09733552923255

Nhìn chung, đây là một điểm bổ sung khá tốt cho JavaScript hướng đối tượng.

Sự thừa hưởng

Ngoài việc xác định các lớp bằng cách sử dụng từ khóa class, bạn cũng có thể sử dụng từ khóa extends để thừa hưởng từ các siêu lớp (super class). Hãy xem cách làm việc này bằng một ví dụ.

class Ellipse {
constructor(width, height) {
this._width = width;
this._height = height;
}
get area() { return Math.PI * this._width * this._height; }
set width(w) { this._width = w; }
set height(h) { this._height = h; }
}

class Circle extends Ellipse {
constructor(radius) {
super(radius, radius);
}
set radius(r) { super.width = r; super.height = r; }
}

// create a circle
var c = new Circle(4)
// returns: Circle {_width: 4, _height: 4}
c.radius = 2
// c is now: Circle {_width: 2, _height: 2}
c.area
// returns: 12.566370614359172
c.radius = 5
c.area
// returns: 78.53981633974483

Trên đây là một giới thiệu ngắn về một số tính năng của JavaScript ES6.

Bạn có đang sử dụng ES6 trong các dự án của bạn không? Trải nghiệm của bạn như thế nào? Vui lòng cho chúng tôi biết trong phần bình luận bên dưới nhé!

Xem thêm:

Thứ Năm, 04/10/2018 19:27
3,73 👨 496