Hướng dẫn class javascript info - thông tin javascript của lớp

Trong lập trình hướng đối tượng, một lớp là một mẫu mã chương trình mở rộng để tạo các đối tượng, cung cấp các giá trị ban đầu cho các biến trạng thái (biến thành viên) và triển khai hành vi (hàm thành viên hoặc phương thức).

Trong thực tế, chúng ta thường cần tạo ra nhiều đối tượng cùng loại, như người dùng hoặc hàng hóa hoặc bất cứ thứ gì.

Như chúng ta đã biết từ Trình xây dựng chương, nhà điều hành "mới",

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
8 có thể giúp với điều đó.

Nhưng trong JavaScript hiện đại, có một cấu trúc lớp học nâng cao hơn, giới thiệu các tính năng mới tuyệt vời hữu ích cho lập trình hướng đối tượng.

Cú pháp của lớp ”

Cú pháp cơ bản là:

class MyClass {
  // class methods
  constructor() { ... }
  method1() { ... }
  method2() { ... }
  method3() { ... }
  ...
}

Sau đó sử dụng

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
9 để tạo một đối tượng mới với tất cả các phương thức được liệt kê.

Phương thức

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
0 được gọi tự động bởi
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
1, vì vậy chúng ta có thể khởi tạo đối tượng ở đó.

Ví dụ:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();

Khi

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
2 được gọi:

  1. Một đối tượng mới được tạo ra.
  2. class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    3 chạy với đối số đã cho và gán nó cho
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    4.

Sau đó, chúng ta có thể gọi các phương thức đối tượng, chẳng hạn như

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
5.

Không có dấu phẩy giữa các phương pháp lớp

Một cạm bẫy phổ biến cho các nhà phát triển người mới là đặt dấu phẩy giữa các phương pháp lớp, điều này sẽ dẫn đến lỗi cú pháp.

Ký hiệu ở đây là không bị nhầm lẫn với các chữ cái đối tượng. Trong lớp, không cần dấu phẩy.

Lớp học là gì?

Vì vậy, chính xác thì

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
6 là gì? Đó không phải là một thực thể cấp ngôn ngữ hoàn toàn mới, như người ta có thể nghĩ.

Hãy để tiết lộ bất kỳ phép thuật nào và xem một lớp học thực sự là gì. Điều đó sẽ giúp tìm hiểu nhiều khía cạnh phức tạp.

Trong JavaScript, một lớp là một loại chức năng.

Ở đây, hãy xem:

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function

Những gì

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
7 Cấu trúc thực sự làm là:

  1. Tạo một hàm có tên
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    8, điều đó trở thành kết quả của khai báo lớp. Mã chức năng được lấy từ phương thức
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    3 (giả sử trống nếu chúng ta không viết phương thức đó).
  2. Lưu trữ các phương thức lớp, chẳng hạn như
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // class is a function
    alert(typeof User); // function
    
    // ...or, more precisely, the constructor method
    alert(User === User.prototype.constructor); // true
    
    // The methods are in User.prototype, e.g:
    alert(User.prototype.sayHi); // the code of the sayHi method
    
    // there are exactly two methods in the prototype
    alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
    0, trong
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // class is a function
    alert(typeof User); // function
    
    // ...or, more precisely, the constructor method
    alert(User === User.prototype.constructor); // true
    
    // The methods are in User.prototype, e.g:
    alert(User.prototype.sayHi); // the code of the sayHi method
    
    // there are exactly two methods in the prototype
    alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
    1.

Sau khi đối tượng

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
2 được tạo, khi chúng ta gọi phương thức của nó, nó được lấy từ nguyên mẫu, giống như được mô tả trong chương F.Prototype. Vì vậy, đối tượng có quyền truy cập vào các phương thức lớp.

Chúng ta có thể minh họa kết quả của tuyên bố

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
3 như:

Đây là mã để hướng nội:

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi

Không chỉ là một đường cú pháp

Đôi khi, mọi người nói rằng

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
6 là một đường cú pháp của người Hồi giáo (cú pháp được thiết kế để làm cho mọi thứ dễ đọc hơn, nhưng không giới thiệu bất cứ điều gì mới), bởi vì chúng tôi thực sự có thể khai báo điều tương tự mà không cần sử dụng từ khóa
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
6: tất cả:

// rewriting class User in pure functions

// 1. Create constructor function
function User(name) {
  this.name = name;
}
// a function prototype has "constructor" property by default,
// so we don't need to create it

// 2. Add the method to prototype
User.prototype.sayHi = function() {
  alert(this.name);
};

// Usage:
let user = new User("John");
user.sayHi();

Kết quả của định nghĩa này là về cùng. Vì vậy, thực sự có những lý do tại sao

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
6 có thể được coi là một đường cú pháp để xác định một hàm tạo cùng với các phương pháp nguyên mẫu của nó.

Tuy nhiên, có những khác biệt quan trọng.

  1. Đầu tiên, một hàm được tạo bởi

    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    6 được dán nhãn bởi một thuộc tính nội bộ đặc biệt
    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // class is a function
    alert(typeof User); // function
    
    // ...or, more precisely, the constructor method
    alert(User === User.prototype.constructor); // true
    
    // The methods are in User.prototype, e.g:
    alert(User.prototype.sayHi); // the code of the sayHi method
    
    // there are exactly two methods in the prototype
    alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
    8. Vì vậy, nó không hoàn toàn giống như tạo ra nó bằng tay.

    Ngôn ngữ kiểm tra tài sản đó ở nhiều nơi. Ví dụ: không giống như một chức năng thông thường, nó phải được gọi bằng

    class User {
      constructor(name) { this.name = name; }
      sayHi() { alert(this.name); }
    }
    
    // proof: User is a function
    alert(typeof User); // function
    1:

    class User {
      constructor() {}
    }
    
    alert(typeof User); // function
    User(); // Error: Class constructor User cannot be invoked without 'new'

    Ngoài ra, một biểu diễn chuỗi của một hàm tạo lớp trong hầu hết các công cụ JavaScript bắt đầu với lớp lớp

    class User {
      constructor() {}
    }
    
    alert(User); // class User { ... }

    Có những khác biệt khác, chúng tôi sẽ gặp họ sớm.

  2. Phương pháp lớp là không thể kích động. Một định nghĩa lớp đặt cờ

    // rewriting class User in pure functions
    
    // 1. Create constructor function
    function User(name) {
      this.name = name;
    }
    // a function prototype has "constructor" property by default,
    // so we don't need to create it
    
    // 2. Add the method to prototype
    User.prototype.sayHi = function() {
      alert(this.name);
    };
    
    // Usage:
    let user = new User("John");
    user.sayHi();
    0 thành
    // rewriting class User in pure functions
    
    // 1. Create constructor function
    function User(name) {
      this.name = name;
    }
    // a function prototype has "constructor" property by default,
    // so we don't need to create it
    
    // 2. Add the method to prototype
    User.prototype.sayHi = function() {
      alert(this.name);
    };
    
    // Usage:
    let user = new User("John");
    user.sayHi();
    1 cho tất cả các phương thức trong
    // rewriting class User in pure functions
    
    // 1. Create constructor function
    function User(name) {
      this.name = name;
    }
    // a function prototype has "constructor" property by default,
    // so we don't need to create it
    
    // 2. Add the method to prototype
    User.prototype.sayHi = function() {
      alert(this.name);
    };
    
    // Usage:
    let user = new User("John");
    user.sayHi();
    2.

    Điều đó tốt, bởi vì nếu chúng ta

    // rewriting class User in pure functions
    
    // 1. Create constructor function
    function User(name) {
      this.name = name;
    }
    // a function prototype has "constructor" property by default,
    // so we don't need to create it
    
    // 2. Add the method to prototype
    User.prototype.sayHi = function() {
      alert(this.name);
    };
    
    // Usage:
    let user = new User("John");
    user.sayHi();
    3 trên một đối tượng, chúng ta thường không muốn các phương pháp lớp của nó.

  3. Các lớp luôn luôn

    // rewriting class User in pure functions
    
    // 1. Create constructor function
    function User(name) {
      this.name = name;
    }
    // a function prototype has "constructor" property by default,
    // so we don't need to create it
    
    // 2. Add the method to prototype
    User.prototype.sayHi = function() {
      alert(this.name);
    };
    
    // Usage:
    let user = new User("John");
    user.sayHi();
    4. Tất cả mã bên trong cấu trúc lớp tự động ở chế độ nghiêm ngặt.

Bên cạnh đó, cú pháp

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
6 mang đến nhiều tính năng khác mà chúng tôi sẽ khám phá sau.

Biểu thức lớp

Giống như các chức năng, các lớp có thể được xác định bên trong một biểu thức khác, được truyền xung quanh, trả về, được chỉ định, v.v.

Ở đây, một ví dụ về biểu thức lớp:

let User = class {
  sayHi() {
    alert("Hello");
  }
};

Tương tự như các biểu thức chức năng được đặt tên, các biểu thức lớp có thể có tên.

Nếu một biểu thức lớp có tên, nó chỉ hiển thị bên trong lớp:

// "Named Class Expression"
// (no such term in the spec, but that's similar to Named Function Expression)
let User = class MyClass {
  sayHi() {
    alert(MyClass); // MyClass name is visible only inside the class
  }
};

new User().sayHi(); // works, shows MyClass definition

alert(MyClass); // error, MyClass name isn't visible outside of the class

Chúng ta thậm chí có thể làm cho các lớp động tự động theo yêu cầu, như thế này:

function makeClass(phrase) {
  // declare a class and return it
  return class {
    sayHi() {
      alert(phrase);
    }
  };
}

// Create a new class
let User = makeClass("Hello");

new User().sayHi(); // Hello

Getters/setters

Giống như các đối tượng theo nghĩa đen, các lớp có thể bao gồm getters/setters, thuộc tính được tính toán, v.v.

Ở đây, một ví dụ cho

// rewriting class User in pure functions

// 1. Create constructor function
function User(name) {
  this.name = name;
}
// a function prototype has "constructor" property by default,
// so we don't need to create it

// 2. Add the method to prototype
User.prototype.sayHi = function() {
  alert(this.name);
};

// Usage:
let user = new User("John");
user.sayHi();
6 được triển khai bằng cách sử dụng
// rewriting class User in pure functions

// 1. Create constructor function
function User(name) {
  this.name = name;
}
// a function prototype has "constructor" property by default,
// so we don't need to create it

// 2. Add the method to prototype
User.prototype.sayHi = function() {
  alert(this.name);
};

// Usage:
let user = new User("John");
user.sayHi();
7:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
0

Về mặt kỹ thuật, khai báo lớp như vậy hoạt động bằng cách tạo getters và setters trong

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
1.

Tên được tính toán […]

Ở đây, một ví dụ với tên phương thức được tính toán bằng dấu ngoặc

// rewriting class User in pure functions

// 1. Create constructor function
function User(name) {
  this.name = name;
}
// a function prototype has "constructor" property by default,
// so we don't need to create it

// 2. Add the method to prototype
User.prototype.sayHi = function() {
  alert(this.name);
};

// Usage:
let user = new User("John");
user.sayHi();
9:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
1

Các tính năng như vậy rất dễ nhớ, vì chúng giống với các đối tượng theo nghĩa đen.

Trường lớp

Các trình duyệt cũ có thể cần một polyfill

Các trường lớp là một bổ sung gần đây cho ngôn ngữ.

Trước đây, các lớp của chúng tôi chỉ có phương pháp.

Các trường lớp học trực tuyến là một cú pháp cho phép thêm bất kỳ thuộc tính nào.

Chẳng hạn, hãy để thêm thuộc tính

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
0 vào
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
3:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
2

Vì vậy, chúng tôi chỉ viết "=" trong tuyên bố, và đó là nó.

Sự khác biệt quan trọng của các trường lớp là chúng được đặt trên các đối tượng riêng lẻ chứ không phải

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // the code of the sayHi method

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
1:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
3

Chúng ta cũng có thể gán các giá trị bằng cách sử dụng các biểu thức và các lệnh gọi chức năng phức tạp hơn:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
4

Tạo các phương thức ràng buộc với các trường lớp

Như đã được chứng minh trong chức năng chức năng liên kết chức năng trong JavaScript có

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
3 động. Nó phụ thuộc vào bối cảnh của cuộc gọi.

Vì vậy, nếu một phương thức đối tượng được truyền xung quanh và được gọi trong một bối cảnh khác,

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
3 won sẽ là một tham chiếu đến đối tượng của nó nữa.

Chẳng hạn, mã này sẽ hiển thị

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
5:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
5

Vấn đề được gọi là "Mất

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
3".

Có hai cách tiếp cận để sửa nó, như đã thảo luận trong chức năng liên kết chức năng chương:

  1. Vượt qua chức năng bao bọc, chẳng hạn như
    class User {
      constructor() {}
    }
    
    alert(typeof User); // function
    User(); // Error: Class constructor User cannot be invoked without 'new'
    7.
  2. Liên kết phương thức với đối tượng, ví dụ: trong hàm tạo.

Các trường lớp cung cấp một cú pháp khác, khá thanh lịch:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
6

Trường lớp

class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
8 được tạo trên cơ sở trên mỗi đối tượng, có một hàm riêng cho mỗi đối tượng
class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
9, với
class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
3 bên trong nó tham chiếu đối tượng đó. Chúng ta có thể vượt qua
class User {
  constructor() {}
}

alert(User); // class User { ... }
1 xung quanh bất cứ nơi nào và giá trị của
class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'
3 sẽ luôn đúng.

Điều đó đặc biệt hữu ích trong môi trường trình duyệt, cho người nghe sự kiện.

Bản tóm tắt

Cú pháp lớp cơ bản trông như thế này:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// Usage:
let user = new User("John");
user.sayHi();
7

class User {
  constructor() {}
}

alert(User); // class User { ... }
3 về mặt kỹ thuật là một hàm (một hàm mà chúng tôi cung cấp dưới dạng
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
3), trong khi các phương thức, getters và setters được viết thành
class User {
  constructor() {}
}

alert(User); // class User { ... }
5.

Trong các chương tiếp theo, chúng tôi sẽ tìm hiểu thêm về các lớp học, bao gồm cả kế thừa và các tính năng khác.