From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- .../reference/classes/constructor/index.html | 127 +++++++ .../reference/classes/extends/index.html | 108 ++++++ .../vi/web/javascript/reference/classes/index.html | 410 +++++++++++++++++++++ 3 files changed, 645 insertions(+) create mode 100644 files/vi/web/javascript/reference/classes/constructor/index.html create mode 100644 files/vi/web/javascript/reference/classes/extends/index.html create mode 100644 files/vi/web/javascript/reference/classes/index.html (limited to 'files/vi/web/javascript/reference/classes') diff --git a/files/vi/web/javascript/reference/classes/constructor/index.html b/files/vi/web/javascript/reference/classes/constructor/index.html new file mode 100644 index 0000000000..dddb2555f3 --- /dev/null +++ b/files/vi/web/javascript/reference/classes/constructor/index.html @@ -0,0 +1,127 @@ +--- +title: constructor +slug: Web/JavaScript/Reference/Classes/constructor +translation_of: Web/JavaScript/Reference/Classes/constructor +--- +
{{jsSidebar("Classes")}}
+ +

Phương thức constructor là một phương thức đặc biệt dùng để khởi tạo 1 object và được tạo ở trong class.

+ +
{{EmbedInteractiveExample("pages/js/classes-constructor.html")}}
+ + + +

Cú pháp

+ +
constructor([arguments]) { ... }
+ +

Mô tả

+ +

Chỉ có duy nhất 1 phương thức đặc biệt tên là "constructor" ở trong class. Có nhiều hơn 1 phương thức constructor ở trong class thì sẽ gây ra lỗi{{jsxref("SyntaxError")}}.

+ +

Một constructor có thể sử dụng từ khóa {{jsxref("Operators/super", "super")}} để gọi đến constructor của class cha.

+ +

Nếu bạn không chỉ định 1 phương thức constructor thì constructor mặc định sẽ được sử dụng

+ +

Ví dụ

+ +

Sử dụng phương thức constructor 

+ +

Đoạn code này được lấy từ classes sample (live demo).

+ +
class Square extends Polygon {
+  constructor(length) {
+    // Here, it calls the parent class' constructor with lengths
+    // provided for the Polygon's width and height
+    super(length, length);
+    // Note: In derived classes, super() must be called before you
+    // can use 'this'. Leaving this out will cause a reference error.
+    this.name = 'Square';
+  }
+
+  get area() {
+    return this.height * this.width;
+  }
+
+  set area(value) {
+    this.area = value;
+  }
+}
+ +

Ví dụ khác

+ +

Hãy xem đoạn code sau

+ +
class Polygon {
+    constructor() {
+        this.name = "Polygon";
+    }
+}
+
+class Square extends Polygon {
+    constructor() {
+        super();
+    }
+}
+
+class Rectangle {}
+
+Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
+
+console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
+console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
+
+let newInstance = new Square();
+console.log(newInstance.name); //Polygon
+ +

Ở đây prototype của class Square đã bị thay đổi nhưng constructor kế thừa từ class Polygon vẫn được gọi khi tạo ra 1 thực thể mới.

+ +

Default constructors

+ +

Như đã nói ởi trước, nếu bạn không chỉ đỉnh 1 phương thức constructor thì default constructor sẽ được sử dụng. Với những class cơ bản thì default contructor sẽ là:

+ +
constructor() {}
+
+ +

Với những class dẫn xuất, default constructor sẽ là:

+ +
constructor(...args) {
+  super(...args);
+}
+ +

Thông số kĩ thuật

+ + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('ES2015', '#sec-static-semantics-constructormethod', 'Constructor Method')}}{{Spec2('ES2015')}}Initial definition.
{{SpecName('ESDraft', '#sec-static-semantics-constructormethod', 'Constructor Method')}}{{Spec2('ESDraft')}} 
+ +

Browser compatibility

+ + + +

{{Compat("javascript.classes.constructor")}}

+ +

Bài viết liên quan

+ + diff --git a/files/vi/web/javascript/reference/classes/extends/index.html b/files/vi/web/javascript/reference/classes/extends/index.html new file mode 100644 index 0000000000..a7a2438965 --- /dev/null +++ b/files/vi/web/javascript/reference/classes/extends/index.html @@ -0,0 +1,108 @@ +--- +title: extends(Thừa kế) +slug: Web/JavaScript/Reference/Classes/extends +translation_of: Web/JavaScript/Reference/Classes/extends +--- +
{{jsSidebar("Classes")}}
+ +

Từ khóa extends được sử dụng trong khai báo class hoặc trong class expressions để tạo ra 1 class con là con của class khác

+ +
{{EmbedInteractiveExample("pages/js/classes-extends.html", "taller")}}
+ + + +

Cú pháp

+ +
class ChildClass extends ParentClass { ... }
+ +

Mô tả

+ +

Từ khó extends có thể được sử dụng để tạo ra class con từ những class mà chúng ta tạo ra hoặc những class sẵn có

+ +

Thuộc tính .prototype của lớp được kế thừa phải trả về giá trị là  {{jsxref("Object")}} hoặc {{jsxref("null")}}.

+ +

Ví dụ

+ +

Sử dụng extends

+ +

Ở ví dụ đầu tiên tạo ra 1 class Square từ class Polygon. Ví dụ này được lấy từ  đây (source).

+ +
class Square extends Polygon {
+  constructor(length) {
+    // Ở đây, gọi 1 constructor từ class cha với tham số truyền vào là length
+    // cung cấp chiều rộng vào chiều cao của class Polygon
+    super(length, length);
+    // Chú ý: trong những class con, super()  phải được gọi trước khi
+    // bạn có thể sử dụng từ khóa 'this'. Nếu không sẽ gây ra lỗi tham chiếu
+    this.name = 'Square';
+  }
+
+  get area() {
+    return this.height * this.width;
+  }
+}
+ +

Sử dụng extends với những object có sẵn

+ +

Trong ví dụ này chúng ta thừa kế từ object có sẵn là {{jsxref("Date")}} . Ví dụ này được lấy từ đây(source).

+ +
class myDate extends Date {
+  constructor() {
+    super();
+  }
+
+  getFormattedDate() {
+    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+    return this.getDate() + '-' + months[this.getMonth()] + '-' + this.getFullYear();
+  }
+}
+ +

Thừa kế từ null

+ +

Thừa kế từ {{jsxref("null")}} cũng giống như class thông thường, ngoại trừ rằng các prototype của object sẽ không được thừa kế từ {{jsxref("Object.prototype")}}.

+ +
class nullExtends extends null {
+  constructor() {}
+}
+
+Object.getPrototypeOf(nullExtends); // Function.prototype
+Object.getPrototypeOf(nullExtends.prototype) // null
+
+new nullExtends(); //ReferenceError: this is not defined
+
+ +

Thông số kĩ thuật

+ + + + + + + + + + + + + + + + + + + +
Thông sốTrạng tháiBình luận
{{SpecName('ES2015', '#sec-class-definitions', 'extends')}}{{Spec2('ES2015')}}Initial definition.
{{SpecName('ESDraft', '#sec-class-definitions', 'extends')}}{{Spec2('ESDraft')}} 
+ +

Trình duyệt tương thích

+ + + +

{{Compat("javascript.classes.extends")}}

+ +

Bài viết liên quan

+ + diff --git a/files/vi/web/javascript/reference/classes/index.html b/files/vi/web/javascript/reference/classes/index.html new file mode 100644 index 0000000000..02a693e6fc --- /dev/null +++ b/files/vi/web/javascript/reference/classes/index.html @@ -0,0 +1,410 @@ +--- +title: Classes +slug: Web/JavaScript/Reference/Classes +tags: + - Class trong ES6 + - JavaScript + - biểu thức class + - class declarations + - class expressions + - class trong javasript + - khai báo class + - thừa kế +translation_of: Web/JavaScript/Reference/Classes +--- +
{{JsSidebar("Classes")}}
+ +
Lớp (class) trong JavaScript được giới thiệu trong ECMAScript 2015 chủ yếu là cú pháp cải tiến (syntactical sugar) dựa trên nền tảng thừa kế nguyên mẫu (prototypal inheritance) sẵn có trong JavaScript. Cú pháp class không giới thiệu mô hình thừa kế hướng đối tượng mới cho JavaScript.
+ +

Định nghĩa class

+ +

Thực tế các class giống như các "function đặc biệt", và cũng giống như bạn có thể định nghĩa hàm biểu thức (function expressions)  và khai báo hàm (function declarations), cú pháp class có hai thành phần: biểu thức class (class expressions) và khai báo class (class declarations).

+ +

Khai báo class

+ +

Một cách để định nghĩa class là sử dụng khai báo lớp class declaration. Để khai báo một class, bạn sử dụng từ khóa class  với tên của class đằng sau (ví dụ "Rectangle" như dưới đây).

+ +
class Rectangle {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+}
+ +

Hoisting (sự kéo lên)

+ +

Một sự khác biệt quan trọng giữa khai báo hàmkhai báo class mà các bạn cần chú ý đó là khai báo hàm được kéo lên đầu ({{Glossary("Hoisting", "hoisted")}}), và khai báo class thì không. Bạn cần khai báo class của bạn trước tiên sau đó mới có thể gọi và sử dụng nó, ngược lại nếu viết code giống như phía dưới đây thì sẽ xảy ra lỗi {{jsxref("ReferenceError")}}:

+ +
var p = new Rectangle(); // ReferenceError
+
+class Rectangle {}
+
+ +

Biểu thức class

+ +

Một biểu thức class là một cách khác để khai báo một class. Biểu thức class có thể có tên hoặc không tên. Biểu thức class nếu có tên, thì tên đó chỉ được nhìn thấy bên trong thân class. (Tuy nhiên từ bên ngoài nó có thể được lấy ra thông qua thuộc tính {{jsxref("Function.name", "name")}} của class (không phải instance)).

+ +
// biểu thức class không tên
+var Rectangle = class {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+};
+
+console.log(Rectangle.name);
+// output: "Rectangle" (tên của biến được gán)
+
+// biểu thức class có tên
+var Rectangle = class Rectangle2 {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+};
+
+console.log(Rectangle.name);
+// output: "Rectangle2" (tên phía sau từ khóa class)
+
+ +
+

Lưu ý: Các biểu thức class cũng theo quy luật hoisting như của {{anch("Class declarations")}} đề cập ở trên.

+
+ +

Thân class và định nghĩa phương thức

+ +

Phần thân của một class là phần nằm trong dấu ngoặc nhọn {}. Tại đó bạn có thể định nghĩa các thành phần của class như phương thức (method) hoặc hàm khởi tạo (constructor).

+ +

Strict mode

+ +

Các phần tử khai báo trong class declarations và class expressions đã được thực hiện ở chế độ strict mode như constructor, static tương tự đối với prototype methods, setter, getter functions. (Nếu bạn chưa hiểu chế độ strict mode thì hãy tìm hiểu thêm tại đây).

+ +

Constructor (hàm khởi tạo)

+ +

Hàm khởi tạo (constructor) là một hàm đặc biệt, nhiệm vụ của nó là khởi tạo một đối tượng cho một class. Trong một class chỉ có thể tồn tại duy nhất một hàm khởi tạo, nghĩa là bạn chỉ có thể khai báo duy nhất một hàm với tên "constructor". Nếu bạn cố gắng làm ngược lại (khai báo nhiều hơn một hàm constructor) thì sẽ xuất hiện lỗi {{jsxref("SyntaxError")}}.

+ +

Một constructor có thể sử dụng từ khóa super để gọi tới hàm constructor của class cha.

+ +

Phương thức Prototype

+ +

Xem thêm định nghĩa hàm.

+ +
class Rectangle {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+
+  get area() {
+    return this.calcArea();
+  }
+
+  calcArea() {
+    return this.height * this.width;
+  }
+}
+
+const square = new Rectangle(10, 10);
+
+console.log(square.area);
+ +

Phương thức Static (phương thức tĩnh)

+ +

Từ khóa static định nghĩa một hàm static (hàm tĩnh) trong một class. Nếu muốn gọi hàm static này thì bạn không cần gọi chúng thông qua các instantiating của class đó và bạn cũng không thể gọi chúng thông qua cách khởi tạo class. Hàm static thường được sử dụng vào mục đích tạo ra một hàm tiện ích (có thể gọi là hàm dùng chung) cho cả một ứng dụng.

+ +
class Point {
+  constructor(x, y) {
+    this.x = x;
+    this.y = y;
+  }
+
+  static distance(a, b) {
+    const dx = a.x - b.x;
+    const dy = a.y - b.y;
+
+    return Math.hypot(dx, dy);
+  }
+}
+
+const p1 = new Point(5, 5);
+const p2 = new Point(10, 10);
+
+console.log(Point.distance(p1, p2));
+ +

Boxing với phương thức prototype và static

+ +

Khi hai hàm static và prototype được gọi trực tiếp (không cần tạo đối tượng có giá trị "this") thì bây giờ bên trong hàm gọi, giá trị this sẽ là undefine. Autoboxing sẽ không xảy ra. Hành vi này sẽ giống nhau ngay cả khi chúng ta viết code ở strict mode bởi vì tất cả các hàm, phương thức, hàm khởi tạo, setter và getter đều thực thi mặc định ở strict mode. Chính vì vậy nếu chúng ta không chỉ định giá trị "this" thì giá trị của "this" sẽ là undefined.

+ +
class Animal {
+  speak() {
+    return this;
+  }
+  static eat() {
+    return this;
+  }
+}
+
+let obj = new Animal();
+obj.speak(); // Animal {}
+let speak = obj.speak;
+speak(); // undefined
+
+Animal.eat() // class Animal
+let eat = Animal.eat;
+eat(); // undefined
+
+ +

Nếu chúng ta chỉnh sửa code như trên bằng cách sửa dụng prototype thì autoboxing sẽ tự động hiểu rằng giá trị this bấy giờ là dựa trên cái hàm được gọi. Tham khảo code bên dưới.

+ +
function Animal() { }
+
+Animal.prototype.speak = function() {
+  return this;
+}
+
+Animal.eat = function() {
+  return this;
+}
+
+let obj = new Animal();
+let speak = obj.speak;
+speak(); // global object
+
+let eat = Animal.eat;
+eat(); // global object
+
+ +

Tạo lớp con với extends

+ +

Từ khóa extends được sử dụng trong class declarations hoặc class expressions để tạo ra một class con kế thừa từ một class sẵn có (class cha).

+ +
class Animal {
+  constructor(name) {
+    this.name = name;
+  }
+
+  speak() {
+    console.log(this.name + ' makes a noise.');
+  }
+}
+
+class Dog extends Animal {
+  speak() {
+    console.log(this.name + ' barks.');
+  }
+}
+
+var d = new Dog('Mitzie');
+d.speak(); // Mitzie barks.
+
+ +

Nếu có một constructor trong lớp con (sub-class), nó cần gọi hàm super() trước khi có thể sử dụng "this".

+ +

Một cách khác cũng có thể gọi và mở rộng hàm có sẵn là dùng prototype:

+ +
function Animal (name) {
+  this.name = name;
+}
+
+Animal.prototype.speak = function () {
+  console.log(this.name + ' makes a noise.');
+}
+
+class Dog extends Animal {
+  speak() {
+    console.log(this.name + ' barks.');
+  }
+}
+
+var d = new Dog('Mitzie');
+d.speak(); // Mitzie barks.
+
+ +

Cần lưu ý rằng các class không thể extend một object bình thường trong javascript (regular object). Do đó nếu bạn muốn kế thừa một hàm từ object bình thường này, bạn cần thay thế và sử dụng {{jsxref("Object.setPrototypeOf()")}}:

+ +
var Animal = { // regular object
+  speak() {
+    console.log(this.name + ' makes a noise.');
+  }
+};
+
+class Dog { //
+  constructor(name) {
+    this.name = name;
+  }
+}
+
+Object.setPrototypeOf(Dog.prototype, Animal);// Nếu bạn không làm điều này khi gọi hàm speak thì sẽ sinh ra lỗi
+
+var d = new Dog('Mitzie'); // đối tượng của class Dog
+d.speak(); // Mitzie makes a noise.
+
+ +

Species

+ +

Bạn có thể muốn trả về các đối tượng {{jsxref("Array")}} trong mảng của class MyArray. Mô hình species sẽ cho phép bạn ghi đè lên các hàm khởi tạo mặc định.

+ +

Ví dụ, khi sử dụng những phương thức như là {{jsxref("Array.map", "map()")}} điều đó sẽ trả về giá trị khởi tạo mặc định, bạn muốn những phương thức đó trả về một mảng đối tượng của Array, thay vì đối tượng của MyArray. {{jsxref("Symbol.species")}}  sẽ cho phép bạn thực hiện điều này:

+ +
class MyArray extends Array {
+  // Overwrite species to the parent Array constructor
+  static get [Symbol.species]() { return Array; }
+}
+
+var a = new MyArray(1,2,3);
+var mapped = a.map(x => x * x);
+
+console.log(mapped instanceof MyArray); // false
+console.log(mapped instanceof Array);   // true
+
+ +

Gọi class cha sử dụng super

+ +

Từ khóa super dùng để gọi một hàm có sẵn ở đối tượng cha.

+ +
class Cat {
+  constructor(name) {
+    this.name = name;
+  }
+
+  speak() {
+    console.log(this.name + ' makes a noise.');
+  }
+}
+
+class Lion extends Cat {
+  speak() {
+    super.speak();
+    console.log(this.name + ' roars.');
+  }
+}
+
+var l = new Lion('Fuzzy');
+l.speak();
+// Fuzzy makes a noise.
+// Fuzzy roars.
+
+
+ +

Mix-ins

+ +

Abstract subclasses or mix-ins are templates for classes. An ECMAScript class can only have a single superclass, so multiple inheritance from tooling classes, for example, is not possible. The functionality must be provided by the superclass.

+ +

A function with a superclass as input and a subclass extending that superclass as output can be used to implement mix-ins in ECMAScript:

+ +

Tập hợp các class con hoặc mix-ins được gọi là khuôn mẫu cho các class. Trong ECMAScript một class chỉ có thể có một lớp cha, vì vậy để thừa kế từ tập hợp các class (kế thừa nhiều class) là điều không thể. Các chức năng phải được cung cấp bởi lớp mà nó kế thừa (cung cấp bởi lớp cha).

+ +

Một hàm mà đã được định nghĩa ở lớp cha và lớp con muốn kế thừa và mở rộng hàm đó ra thì có thể sự dụng các lệnh mix-ins trong  ECMAScript như sau:

+ +
var calculatorMixin = Base => class extends Base {
+  calc() { }
+};
+
+var randomizerMixin = Base => class extends Base {
+  randomize() { }
+};
+
+ +

Một class để sử dụng mix-ins này có thể viết code như thế này:

+ +
class Foo { }
+class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
+ +

Đặc điểm kỹ thuật

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('ES2015', '#sec-class-definitions', 'Class definitions')}}{{Spec2('ES2015')}}Initial definition.
{{SpecName('ES2016', '#sec-class-definitions', 'Class definitions')}}{{Spec2('ES2016')}}
{{SpecName('ES2017', '#sec-class-definitions', 'Class definitions')}}{{Spec2('ES2017')}}
{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}{{Spec2('ESDraft')}}
+ +

Tính tương thích với các trình duyệt

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)EdgeInternet ExplorerOperaSafari
Basic support{{CompatChrome(42.0)}}[1]
+ {{CompatChrome(49.0)}}
{{CompatGeckoDesktop(45)}}13{{CompatNo}}{{CompatOpera(43.0)}}{{CompatSafari(9.0)}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari MobileChrome for Android
Basic support{{CompatVersionUnknown}}{{CompatGeckoMobile(45)}}{{CompatUnknown}}{{CompatUnknown}}9{{CompatChrome(56.0)}}
+
+ +

[1] Yêu cầu chế độ strict (luôn chạy javascript ở chế độ này). Tắt strict mode trong flag "Enable Experimental JavaScript", mặc định flag này bị vô hiệu hóa.

+ +

Xem thêm

+ + -- cgit v1.2.3-54-g00ecf