Các đối tượng và lớp có giống nhau trong JavaScript không?

JavaScript là một ngôn ngữ lập dị với nhiều cách tiếp cận hầu hết mọi vấn đề. Khi ES6 thêm từ khóa “class”, nó đã tiết kiệm thời gian hay chỉ làm vẩn đục nước?

Qua

chỉ Robertson

Justen có một thập kỷ kinh nghiệm về JavaScript full-stack khi làm việc với những người như Taylor Swift và Red Hot Chili Peppers

CHIA SẺ

CHIA SẺ

JavaScript là một ngôn ngữ lập dị. Mặc dù lấy cảm hứng từ Smalltalk, nhưng nó sử dụng cú pháp giống như C. Nó kết hợp các khía cạnh của mô hình lập trình thủ tục, chức năng và hướng đối tượng [OOP]. Nó có nhiều cách tiếp cận, thường là dư thừa, để giải quyết hầu hết mọi vấn đề lập trình có thể tưởng tượng được và không có ý kiến ​​​​mạnh mẽ về việc cái nào được ưa thích hơn. Nó được gõ một cách yếu ớt và linh hoạt, với cách tiếp cận giống như mê cung để cưỡng chế kiểu chữ khiến ngay cả những nhà phát triển có kinh nghiệm cũng vấp ngã

JavaScript cũng có mụn cóc, bẫy và các tính năng đáng ngờ. Các lập trình viên mới phải vật lộn với một số khái niệm khó hơn của nó—nghĩ về tính không đồng bộ, bao đóng và cẩu. Các lập trình viên có kinh nghiệm về các ngôn ngữ khác giả định một cách hợp lý những thứ có tên và hình thức tương tự sẽ hoạt động theo cách tương tự trong JavaScript và thường sai. Mảng không thực sự là mảng;

Rắc rối với các lớp ES6

Kẻ phạm tội tồi tệ nhất cho đến nay là phiên bản mới nhất của JavaScript, ECMAScript 6 [ES6]. các lớp học. Một số cuộc nói chuyện xung quanh các lớp học thực sự đáng báo động và cho thấy một sự hiểu lầm sâu xa về cách ngôn ngữ thực sự hoạt động

“JavaScript cuối cùng cũng là một ngôn ngữ hướng đối tượng thực sự khi nó có các lớp. ”

Hoặc

“Các lớp giải phóng chúng ta khỏi suy nghĩ về mô hình kế thừa bị hỏng của JavaScript. ”

Hoặc thậm chí

“Các lớp là cách tiếp cận an toàn hơn, dễ dàng hơn để tạo các loại trong JavaScript. ”

Những tuyên bố này không làm tôi bận tâm vì chúng ngụ ý rằng có điều gì đó không ổn với sự kế thừa nguyên mẫu; . Những tuyên bố này làm tôi khó chịu vì không có tuyên bố nào là đúng và chúng cho thấy hậu quả của cách tiếp cận “mọi thứ cho mọi người” của JavaScript đối với thiết kế ngôn ngữ. Nó làm tê liệt khả năng hiểu ngôn ngữ của lập trình viên thường xuyên hơn mức cho phép. Trước khi tôi đi xa hơn, hãy minh họa

JavaScript Pop Quiz #1. Sự khác biệt cơ bản giữa các khối mã này là gì?

function PrototypicalGreeting[greeting = "Hello", name = "World"] {
  this.greeting = greeting
  this.name = name
}

PrototypicalGreeting.prototype.greet = function[] {
  return `${this.greeting}, ${this.name}!`
}

const greetProto = new PrototypicalGreeting["Hey", "folks"]
console.log[greetProto.greet[]]
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]

Câu trả lời ở đây là không có một. Những điều này thực hiện giống nhau một cách hiệu quả, vấn đề chỉ là liệu cú pháp lớp ES6 có được sử dụng hay không

Đúng, ví dụ thứ hai diễn cảm hơn. Chỉ vì lý do đó, bạn có thể lập luận rằng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 là một bổ sung hay cho ngôn ngữ. Thật không may, vấn đề phức tạp hơn một chút

JavaScript Pop Quiz #2. Đoạn mã sau làm gì?

function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]

Câu trả lời đúng là nó in ra bàn điều khiển

> MyClass
> Overridden in Proto
> Overridden in MyClass
> Overridden in instance

Nếu bạn trả lời sai, bạn không hiểu thực chất

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 là gì. Đây không phải là lỗi của bạn. Giống như
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
0,
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 không phải là một tính năng ngôn ngữ, đó là sự tối nghĩa về cú pháp. Nó cố gắng che giấu mô hình thừa kế nguyên mẫu và những thành ngữ vụng về đi kèm với nó, đồng thời ngụ ý rằng JavaScript đang làm điều gì đó mà nó không làm.

Bạn có thể đã được cho biết rằng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 đã được giới thiệu với JavaScript để giúp các nhà phát triển OOP cổ điển đến từ các ngôn ngữ như Java cảm thấy thoải mái hơn với mô hình kế thừa lớp ES6. Nếu bạn là một trong những nhà phát triển đó, ví dụ đó có thể khiến bạn kinh hoàng. nó nên. Nó cho thấy rằng từ khóa
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 của JavaScript không đi kèm với bất kỳ đảm bảo nào mà một lớp có nghĩa là cung cấp. Nó cũng thể hiện một trong những điểm khác biệt chính trong mô hình kế thừa nguyên mẫu. Nguyên mẫu là thể hiện đối tượng, không phải loại

Nguyên mẫu so với. Các lớp học

Sự khác biệt quan trọng nhất giữa kế thừa dựa trên lớp và nguyên mẫu là một lớp định nghĩa một kiểu có thể được khởi tạo trong thời gian chạy, trong khi nguyên mẫu tự nó là một thể hiện đối tượng

Con của một lớp ES6 là một định nghĩa kiểu khác mở rộng lớp cha với các thuộc tính và phương thức mới, do đó có thể được khởi tạo trong thời gian chạy. Con của nguyên mẫu là một thể hiện đối tượng khác ủy quyền cho cha bất kỳ thuộc tính nào không được triển khai trên con

lưu ý bên lề. Bạn có thể thắc mắc tại sao tôi lại đề cập đến các phương thức lớp mà không đề cập đến các phương thức nguyên mẫu. Đó là vì JavaScript không có khái niệm về phương thức. Các hàm là hạng nhất trong JavaScript và chúng có thể có thuộc tính hoặc là thuộc tính của các đối tượng khác

Một hàm tạo của lớp tạo một thể hiện của lớp. Hàm tạo trong JavaScript chỉ là một hàm cũ đơn giản trả về một đối tượng. Điều đặc biệt duy nhất về hàm tạo JavaScript là khi được gọi bằng từ khóa

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
7, nó gán nguyên mẫu của nó làm nguyên mẫu của đối tượng được trả về. Nếu điều đó nghe có vẻ hơi khó hiểu với bạn, thì bạn không đơn độc đâu—đúng vậy, và đó là một phần lý do tại sao các nguyên mẫu vẫn chưa được hiểu rõ

Nói một cách thực sự hay, một đứa trẻ của nguyên mẫu không phải là bản sao của nguyên mẫu của nó, cũng không phải là một vật thể có hình dạng giống như nguyên mẫu của nó. Đứa trẻ có một tham chiếu sống đến nguyên mẫu và bất kỳ thuộc tính nguyên mẫu nào không tồn tại trên đứa trẻ là tham chiếu một chiều đến thuộc tính cùng tên trên nguyên mẫu

Hãy xem xét những điều sau đây

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
3

Ghi chú. Bạn hầu như sẽ không bao giờ viết mã như thế này trong đời thực—đó là một cách làm tệ hại—nhưng nó thể hiện nguyên tắc một cách ngắn gọn

Trong ví dụ trước, trong khi

function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
5 là
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
6, nó tham chiếu đến
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
7. Ngay sau khi chúng tôi xác định
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
8 trên
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
9,
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
5 có giá trị
> MyClass
> Overridden in Proto
> Overridden in MyClass
> Overridden in instance
1, nhưng
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
7 vẫn giữ nguyên giá trị ban đầu của nó. Khi chúng tôi
> MyClass
> Overridden in Proto
> Overridden in MyClass
> Overridden in instance
3, nó lại đề cập đến
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
7, có nghĩa là khi chúng tôi thay đổi giá trị của cha mẹ, thì
function Proto[] {
  this.name = 'Proto'
  return this;
}

Proto.prototype.getName = function[] {
  return this.name
}

class MyClass extends Proto {
  constructor[] {
    super[]
    this.name = 'MyClass'
  }
}

const instance = new MyClass[]

console.log[instance.getName[]]

Proto.prototype.getName = function[] { return 'Overridden in Proto' }

console.log[instance.getName[]]

MyClass.prototype.getName = function[] { return 'Overridden in MyClass' }

console.log[instance.getName[]]

instance.getName = function[] { return 'Overridden in instance' }


console.log[instance.getName[]]
5 đề cập đến giá trị mới

Hãy xem điều gì vừa xảy ra [với mục đích minh họa rõ ràng hơn, chúng ta sẽ giả sử đây là

> MyClass
> Overridden in Proto
> Overridden in MyClass
> Overridden in instance
6 chứ không phải chuỗi ký tự, sự khác biệt không quan trọng ở đây]

Cách thức hoạt động bí mật của nó, và đặc biệt là các đặc thù của

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
7 và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
6, là một chủ đề cho một ngày khác, nhưng Mozilla có một bài viết kỹ lưỡng về chuỗi kế thừa nguyên mẫu của JavaScript nếu bạn muốn đọc thêm

Điều quan trọng cần rút ra là các nguyên mẫu không xác định một

> MyClass
> Overridden in Proto
> Overridden in MyClass
> Overridden in instance
9;

Vẫn còn với tôi?

JavaScript Pop Quiz #3. Làm thế nào để bạn thực hiện quyền riêng tư trong các lớp học?

Các thuộc tính nguyên mẫu và lớp của chúng tôi ở trên không được “đóng gói” nhiều như “treo bấp bênh ngoài cửa sổ. “Chúng ta nên khắc phục điều đó, nhưng bằng cách nào?

Không có mã ví dụ ở đây. Câu trả lời là bạn không thể

JavaScript không có bất kỳ khái niệm nào về quyền riêng tư, nhưng nó có bao đóng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
0

Bạn có hiểu chuyện gì vừa xảy ra không? . Không sao đâu, thực sự đấy—chúng không đáng sợ như người ta tưởng, chúng cực kỳ hữu ích và bạn nên dành chút thời gian để tìm hiểu về chúng

JavaScript Pop Quiz #4. Điều gì tương đương với điều trên bằng cách sử dụng từ khóa
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8?

Xin lỗi, đây là một câu hỏi mẹo khác. Về cơ bản, bạn có thể làm điều tương tự, nhưng có vẻ như thế này

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
2

Hãy cho tôi biết nếu điều đó có vẻ dễ dàng hoặc rõ ràng hơn trong

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
32. Theo quan điểm cá nhân của tôi, nó còn tệ hơn một chút—nó phá vỡ cách sử dụng thành ngữ của các khai báo
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 trong JavaScript và nó không hoạt động giống như bạn mong đợi từ Java chẳng hạn. Điều này sẽ được làm rõ sau đây

JavaScript Pop Quiz #5.
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
34 làm gì?

Hãy cùng tìm hiểu

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
6

À, điều đó thật ngượng

JavaScript Pop Quiz #6. Các nhà phát triển JavaScript có kinh nghiệm thích cái nào—Nguyên mẫu hay Lớp?

Bạn đoán xem, đó là một câu hỏi mẹo khác—các nhà phát triển JavaScript có kinh nghiệm có xu hướng tránh cả hai khi họ có thể. Đây là một cách hay để làm điều trên với JavaScript thành ngữ

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
7

Đây không chỉ là việc tránh sự xấu xí cố hữu của thừa kế, hoặc thực thi đóng gói. Hãy nghĩ xem bạn có thể làm gì khác với

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
35 và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
36 mà bạn không thể dễ dàng làm với nguyên mẫu hoặc lớp

Có điều, bạn có thể hủy cấu trúc nó vì bạn không phải lo lắng về ngữ cảnh của

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
6

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
1

Điều đó thật tuyệt. Bên cạnh việc tránh

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
7 và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
6 tomfoolery, nó cho phép chúng ta sử dụng các đối tượng của mình thay thế cho nhau với các mô-đun CommonJS và ES6. Nó cũng làm cho bố cục dễ dàng hơn một chút

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
0

Khách hàng của

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
00 không phải lo lắng về việc
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
01 đến từ đâu và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
02 không phải loay hoay với việc tung hứng ngữ cảnh của
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
03 hoặc các thuộc tính được lồng sâu. Xin lưu ý bạn, chúng tôi không phải lo lắng nhiều về
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
6 trong mã thủ tục đồng bộ đơn giản, nhưng nó gây ra tất cả các loại sự cố trong mã không đồng bộ mà tốt hơn hết là nên tránh

Chỉ cần suy nghĩ một chút,

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
02 có thể được phát triển thành một công cụ gián điệp cực kỳ tinh vi có thể xử lý tất cả các loại mục tiêu xâm nhập—hay nói cách khác, một mặt tiền

Tất nhiên bạn cũng có thể làm điều đó với một lớp, hay đúng hơn là một tập hợp các lớp, tất cả đều kế thừa từ một

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
06 hoặc
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
07… ngoại trừ việc JavaScript không có bất kỳ khái niệm nào về tóm tắt hoặc giao diện

Hãy quay lại ví dụ về lời chào để xem cách chúng tôi triển khai nó với một nhà máy

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
1

Bạn có thể nhận thấy những nhà máy này đang trở nên ngắn gọn hơn khi chúng ta đi cùng nhau, nhưng đừng lo lắng—họ cũng làm như vậy. Các bánh xe đào tạo sắp ra mắt, mọi người

Đó đã là bản soạn sẵn ít hơn so với nguyên mẫu hoặc phiên bản lớp của cùng một mã. Thứ hai, nó đạt được sự đóng gói các thuộc tính của nó một cách hiệu quả hơn. Ngoài ra, nó có dung lượng bộ nhớ và hiệu năng thấp hơn trong một số trường hợp [thoạt nhìn có vẻ không giống như vậy, nhưng trình biên dịch JIT đang âm thầm hoạt động đằng sau hậu trường để giảm bớt các kiểu trùng lặp và suy luận]

Vì vậy, nó an toàn hơn, thường nhanh hơn và viết mã như thế này dễ dàng hơn. Tại sao chúng ta cần các lớp học một lần nữa? . Điều gì xảy ra nếu chúng ta muốn các biến thể của lời chào không vui và nhiệt tình? . Chúng tôi biết rằng chúng tôi sẽ cần tham số hóa dấu câu, vì vậy chúng tôi sẽ tái cấu trúc một chút và thêm một số phần tử con

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
2

Đó là một cách tiếp cận tốt, cho đến khi ai đó xuất hiện và yêu cầu một tính năng không phù hợp rõ ràng với hệ thống phân cấp và toàn bộ mọi thứ không còn ý nghĩa gì nữa. Hãy ghim vào suy nghĩ đó trong khi chúng tôi cố gắng viết chức năng tương tự với các nhà máy

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
3

Không rõ ràng là mã này tốt hơn, mặc dù nó ngắn hơn một chút. Trên thực tế, bạn có thể lập luận rằng nó khó đọc hơn và có thể đây là một cách tiếp cận khó hiểu. Chúng ta không thể có một

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
09 và một
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
20 sao?

Sau đó, khách hàng của bạn đến và nói: “Tôi cần một người chào đón mới không hài lòng và muốn cả phòng biết về điều đó. ”

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
4

Nếu chúng ta cần sử dụng cách chào hỏi không hài lòng một cách nhiệt tình này nhiều lần, chúng ta có thể tự làm điều đó dễ dàng hơn

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
5

Có những cách tiếp cận phong cách sáng tác này hoạt động với các nguyên mẫu hoặc lớp. Ví dụ: bạn có thể suy nghĩ lại về

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
21 và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
22 với tư cách là người trang trí. Nó vẫn sẽ cần nhiều bản tóm tắt hơn so với cách tiếp cận kiểu chức năng được sử dụng ở trên, nhưng đó là cái giá bạn phải trả cho sự an toàn và đóng gói của các lớp thực

Vấn đề là, trong JavaScript, bạn không nhận được sự an toàn tự động đó. Các khung JavaScript nhấn mạnh việc sử dụng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 thực hiện rất nhiều "phép thuật" để giải quyết các loại vấn đề này và buộc các lớp phải tự hành xử. Thỉnh thoảng hãy xem mã nguồn
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
24 của Polymer, tôi thách bạn. Đó là cấp độ thuật sĩ cổ điển của JavaScript arcana, và ý tôi là không có sự mỉa mai hay mỉa mai

Tất nhiên, chúng tôi có thể khắc phục một số vấn đề đã thảo luận ở trên với

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
25 hoặc
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
26 để có tác động lớn hơn hoặc ít hơn. Nhưng tại sao lại bắt chước biểu mẫu mà không có chức năng, trong khi bỏ qua các công cụ mà JavaScript vốn cung cấp cho chúng ta mà chúng ta có thể không tìm thấy trong các ngôn ngữ như Java?

Tìm những phần tốt

Các nhà phát triển JavaScript thường nhấn mạnh những điểm hay của ngôn ngữ này, cả về mặt thông tục và liên quan đến cuốn sách cùng tên. Chúng tôi cố gắng tránh những cái bẫy được đặt ra bởi các lựa chọn thiết kế ngôn ngữ đáng ngờ hơn của nó và bám vào các phần cho phép chúng tôi viết mã rõ ràng, dễ đọc, giảm thiểu lỗi, có thể tái sử dụng

Có những lập luận hợp lý về phần nào của JavaScript đủ điều kiện, nhưng tôi hy vọng tôi đã thuyết phục bạn rằng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 không phải là một trong số đó. Nếu không làm được điều đó, hy vọng bạn hiểu rằng tính kế thừa trong JavaScript có thể là một mớ hỗn độn khó hiểu và rằng
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 sẽ không sửa lỗi đó cũng như không giúp bạn hiểu về các nguyên mẫu. Tín dụng bổ sung nếu bạn chọn các gợi ý rằng các mẫu thiết kế hướng đối tượng hoạt động tốt mà không cần các lớp hoặc kế thừa ES6

Tôi không bảo bạn tránh hoàn toàn

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8. Đôi khi bạn cần kế thừa và
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8 cung cấp cú pháp rõ ràng hơn để thực hiện điều đó. Đặc biệt,
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
61 đẹp hơn nhiều so với cách tiếp cận nguyên mẫu cũ. Bên cạnh đó, nhiều khuôn khổ giao diện người dùng phổ biến khuyến khích sử dụng nó và có lẽ bạn nên tránh viết mã phi tiêu chuẩn kỳ lạ trên nguyên tắc một mình. Tôi chỉ không thích nơi này sẽ đi

Trong những cơn ác mộng của tôi, cả một thế hệ thư viện JavaScript được viết bằng

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8, với kỳ vọng rằng nó sẽ hoạt động tương tự như các ngôn ngữ phổ biến khác. Toàn bộ lớp lỗi mới [ý định chơi chữ] được phát hiện. Những cái cũ được hồi sinh mà có thể dễ dàng bị bỏ lại trong Nghĩa địa của JavaScript không đúng định dạng nếu chúng ta không bất cẩn rơi vào cái bẫy
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
8. Các nhà phát triển JavaScript có kinh nghiệm bị những con quái vật này cản trở, bởi vì những gì phổ biến không phải lúc nào cũng tốt

Cuối cùng, tất cả chúng ta đều thất vọng bỏ cuộc và bắt đầu phát minh lại các bánh xe trong Rust, Go, Haskell hoặc ai biết được cái gì khác, sau đó biên dịch thành Wasm cho web, và các khung và thư viện web mới sinh sôi nảy nở thành vô số ngôn ngữ

Nó thực sự làm tôi mất ngủ vào ban đêm

Hiểu những điều cơ bản

ECMAScript 6 là gì?

ES6 là triển khai ổn định mới nhất của ECMAScript, tiêu chuẩn mở dựa trên JavaScript. Nó bổ sung một số tính năng mới cho ngôn ngữ bao gồm hệ thống mô-đun chính thức, các biến và hằng trong phạm vi khối, hàm mũi tên và nhiều từ khóa, cú pháp và đối tượng tích hợp mới khác.

ES6 có phải là phiên bản ECMAScript mới nhất không?

ES6 [ES2015] là tiêu chuẩn mới nhất ổn định và được triển khai đầy đủ [ngoại trừ các lệnh gọi đuôi thích hợp và một số sắc thái] trong các phiên bản mới nhất của các trình duyệt chính và các môi trường JS khác. ES7 [ES2016] và ES8 [ES2017] cũng có thông số kỹ thuật ổn định, nhưng việc triển khai khá hỗn hợp

ES6 có hướng đối tượng không?

JavaScript hỗ trợ mạnh mẽ cho lập trình hướng đối tượng, nhưng nó sử dụng mô hình kế thừa khác [nguyên mẫu] so với hầu hết các ngôn ngữ OO phổ biến [sử dụng kế thừa cổ điển]. Nó cũng hỗ trợ các phong cách lập trình thủ tục và chức năng

Các lớp ES6 là gì?

Trong ES6, từ khóa "class" và các tính năng liên quan là một cách tiếp cận mới để tạo các hàm tạo nguyên mẫu. Chúng không phải là các lớp thực sự theo cách quen thuộc với người dùng của hầu hết các ngôn ngữ hướng đối tượng khác

Những từ khóa nào có thể được sử dụng để triển khai kế thừa trong ES6?

Người ta có thể triển khai tính kế thừa trong JavaScript ES6 thông qua từ khóa "class" và "extends". Một cách tiếp cận khác là thông qua thành ngữ chức năng "hàm tạo" cộng với việc gán các hàm và thuộc tính tĩnh cho nguyên mẫu của hàm tạo

Kế thừa nguyên mẫu trong JavaScript là gì?

Trong kế thừa nguyên mẫu, các nguyên mẫu là các thể hiện đối tượng mà các thể hiện con ủy quyền các thuộc tính không xác định. Ngược lại, các lớp trong kế thừa cổ điển là các định nghĩa kiểu, từ đó các lớp con kế thừa các phương thức và thuộc tính trong quá trình khởi tạo

Thẻ

JavaScriptOOP

Người làm việc tự do? Tìm công việc tiếp theo của bạn.

Công việc lập trình viên JavaScript

Xem thông tin đầy đủ

chỉ Robertson

Nhà phát triển JavaScript tự do

Giới thiệu về tác giả

Justen là nhà phát triển JavaScript full-stack với hơn một thập kỷ kinh nghiệm. Anh ấy đã làm việc trong các dự án cho một số thương hiệu lớn nhất trong ngành xuất bản và ghi âm, đồng thời làm việc trực tiếp với các doanh nghiệp nhỏ và tổ chức phi lợi nhuận trong nhiều lĩnh vực. Bộ kỹ năng rộng của anh ấy cho phép anh ấy đáp ứng tất cả các nhu cầu về công nghệ web của các doanh nghiệp nhỏ và công ty mới thành lập hoặc lấp đầy khoảng trống trong các nhóm lớn hơn

Thuê Justen

Bình luận

Julian G

Xin chào. Tôi không phải là nhà phát triển JS, thậm chí không phải là nhà phát triển JS "xấu", tuy nhiên tôi thỉnh thoảng sử dụng nó vì tôi là nhà phát triển Qt/QML. Về tuyên bố. ``` const dụ = bảng điều khiển MyClass[] mới. nhật ký [ví dụ. getName[]] nguyên mẫu. nguyên mẫu. getName = function[] { return 'Ghi đè trong Proto' } bảng điều khiển. nhật ký [ví dụ. getName[]] MyClass. nguyên mẫu. getName = function[] { return 'Ghi đè trong MyClass' } bảng điều khiển. nhật ký [ví dụ. getName[]] ``` Tôi không cảm thấy kinh hoàng, thực tế là tôi thấy điều này rất giống với các con trỏ C tới các hàm [là cơ chế đa hình mà C có], tôi phải nói rằng tôi thích cơ chế này. tôi không thích. nguyên mẫu. cú pháp [đối với tôi nó có vẻ khá phức tạp]. bài viết hay, cảm ơn

Julian G

Xin chào. Tôi không phải là nhà phát triển JS, thậm chí không phải là nhà phát triển JS "xấu", tuy nhiên tôi thỉnh thoảng sử dụng nó vì tôi là nhà phát triển Qt/QML. Về tuyên bố. ``` const dụ = bảng điều khiển MyClass[] mới. nhật ký [ví dụ. getName[]] nguyên mẫu. nguyên mẫu. getName = function[] { return 'Ghi đè trong Proto' } bảng điều khiển. nhật ký [ví dụ. getName[]] MyClass. nguyên mẫu. getName = function[] { return 'Ghi đè trong MyClass' } bảng điều khiển. nhật ký [ví dụ. getName[]] ``` Tôi không cảm thấy kinh hoàng, thực tế là tôi thấy điều này rất giống với các con trỏ C tới các hàm [là cơ chế đa hình mà C có], tôi phải nói rằng tôi thích cơ chế này. tôi không thích. nguyên mẫu. cú pháp [đối với tôi nó có vẻ khá phức tạp]. bài viết hay, cảm ơn

chỉ Robertson

Chắc chắn rồi, và đó cũng là một điểm tương đồng gần hơn với những gì đang xảy ra trong Javascript. Tôi đồng ý rằng toàn bộ. nguyên mẫu. cú pháp vụng về. Tương tự như vậy, cảm ơn vì những suy nghĩ của bạn. ]

chỉ Robertson

Chắc chắn rồi, và đó cũng là một điểm tương đồng gần hơn với những gì đang xảy ra trong Javascript. Tôi đồng ý rằng toàn bộ. nguyên mẫu. cú pháp vụng về. Tương tự như vậy, cảm ơn vì những suy nghĩ của bạn. ]

Arsenii Fomin

cảm ơn vì bài viết tuyệt vời. Dành 10 phút để hiểu thế nào là "nhiệt tình[không vui[helloerFactory]][]. lời chào []" hoạt động. ] Theo kinh nghiệm của tôi, tôi bắt đầu phát triển web từ vững chắc [hay nói đúng hơn là S. O. L. I. D. ] Nền tảng C++ 3 năm trước với rất nhiều gói gọn trong đầu tôi. Tôi đã nghe rất nhiều điều không hay về javascript và quyết định tìm một cuốn sách hay để hiểu những điều cần tránh, đọc "Những phần hay của javascript", bắt đầu sử dụng javascript trong các dự án và trở thành một người hâm mộ ngôn ngữ này. Khi bạn hiểu rằng để giải quyết bất kỳ vấn đề nào, về cơ bản bạn chỉ cần một công cụ - hàm [đồng thời là con trỏ hàm/đối tượng/đóng/"cấu trúc có hàm"], điều đó thực sự ấn tượng so với C++, nơi bạn cần kết hợp các lớp . Và trong hầu hết các trường hợp, bạn không bao giờ cần các lớp, mới, cái này và tất cả những thứ đó trong javascript. Btw tại sao bạn không đề cập đến khả năng có các trường riêng tư khi tạo đối tượng mới thông qua thành phần?

Arsenii Fomin

cảm ơn vì bài viết tuyệt vời. Dành 10 phút để hiểu thế nào là "nhiệt tình[không vui[helloerFactory]][]. lời chào []" hoạt động. ] Theo kinh nghiệm của tôi, tôi bắt đầu phát triển web từ vững chắc [hay nói đúng hơn là S. O. L. I. D. ] Nền tảng C++ 3 năm trước với rất nhiều gói gọn trong đầu tôi. Tôi đã nghe rất nhiều điều không hay về javascript và quyết định tìm một cuốn sách hay để hiểu những điều cần tránh, đọc "Những phần hay của javascript", bắt đầu sử dụng javascript trong các dự án và trở thành một người hâm mộ ngôn ngữ này. Khi bạn hiểu rằng để giải quyết bất kỳ vấn đề nào, về cơ bản bạn chỉ cần một công cụ - hàm [đồng thời là con trỏ hàm/đối tượng/đóng/"cấu trúc có hàm"], điều đó thực sự ấn tượng so với C++, nơi bạn cần kết hợp các lớp . Và trong hầu hết các trường hợp, bạn không bao giờ cần các lớp, mới, cái này và tất cả những thứ đó trong javascript. Btw tại sao bạn không đề cập đến khả năng có các trường riêng tư khi tạo đối tượng mới thông qua thành phần?

chỉ Robertson

Cảm ơn. ] JavaScript sẽ bớt quái vật hơn nhiều khi bạn sử dụng một tập hợp con hẹp các tính năng bổ sung cho nhau. Vâng, tôi muốn tìm hiểu sâu hơn về cách đạt được giá trị tương đương với các trường riêng tư. Có một số cách tiếp cận tuyệt vời liên quan đến việc đóng cửa với Object. defineProperties để kiểm soát các bộ mô tả đối tượng mà tôi thường sử dụng, nhưng tôi không muốn đi quá sâu vào vấn đề đó. Có lẽ trong một bài báo trong tương lai

chỉ Robertson

Cảm ơn. ] JavaScript sẽ bớt quái vật hơn nhiều khi bạn sử dụng một tập hợp con hẹp các tính năng bổ sung cho nhau. Vâng, tôi muốn tìm hiểu sâu hơn về cách đạt được giá trị tương đương với các trường riêng tư. Có một số cách tiếp cận tuyệt vời liên quan đến việc đóng cửa với Object. defineProperties để kiểm soát các bộ mô tả đối tượng mà tôi thường sử dụng, nhưng tôi không muốn đi quá sâu vào vấn đề đó. Có lẽ trong một bài báo trong tương lai

cây đu đủ

Cảm ơn vì bài viết hay. Cũng gặp khó khăn trong việc hiểu `nhiệt tình [không vui [chào mừngFactory]][]. chào[]`

cây đu đủ

Cảm ơn vì bài viết hay. Cũng gặp khó khăn trong việc hiểu `nhiệt tình [không vui [chào mừngFactory]][]. chào[]`

schollii

Bài báo rất thú vị. Đối với tôi, các ví dụ nguyên mẫu và lớp rất dễ dàng và không có gì ngạc nhiên [có lẽ việc lập trình trong 30 năm bằng nhiều ngôn ngữ sẽ giúp ích]. Tôi cũng thấy việc kết thúc dễ dàng, nhưng thành phần của những người chào đón thì không như vậy và dựa trên nhận xét của những người khác, tôi không phải là người duy nhất. Vì vậy, tôi không muốn sử dụng loại bố cục đó mặc dù tôi thực sự thích ví dụ của bạn về cách bao đóng có thể tăng khả năng đóng gói bằng cách không để lộ các thuộc tính phải là riêng tư nhưng trong js thì không thể nếu không có kỹ thuật đó. Đối với tôi, ví dụ về người chào hỏi không bao giờ nên được sử dụng trong thực tế nhưng chắc chắn là có ý nghĩa nghiêm túc để suy nghĩ ở đó, vì vậy tôi chắc chắn sẽ để mắt đến các biến thể về cùng một chủ đề. Cảm ơn cho một đọc thú vị

schollii

Bài báo rất thú vị. Đối với tôi, các ví dụ nguyên mẫu và lớp rất dễ dàng và không có gì ngạc nhiên [có lẽ việc lập trình trong 30 năm bằng nhiều ngôn ngữ sẽ giúp ích]. Tôi cũng thấy việc kết thúc dễ dàng, nhưng thành phần của những người chào đón thì không như vậy và dựa trên nhận xét của những người khác, tôi không phải là người duy nhất. Vì vậy, tôi không muốn sử dụng loại bố cục đó mặc dù tôi thực sự thích ví dụ của bạn về cách bao đóng có thể tăng khả năng đóng gói bằng cách không để lộ các thuộc tính phải là riêng tư nhưng trong js thì không thể nếu không có kỹ thuật đó. Đối với tôi, ví dụ về người chào hỏi không bao giờ nên được sử dụng trong thực tế nhưng chắc chắn là có ý nghĩa nghiêm túc để suy nghĩ ở đó, vì vậy tôi chắc chắn sẽ để mắt đến các biến thể về cùng một chủ đề. Cảm ơn cho một đọc thú vị

chỉ Robertson

Cảm ơn. ] Đó là sự thật, trong cuộc sống thực, có lẽ bạn sẽ không làm điều gì phức tạp để giải quyết một vấn đề đơn giản như vậy. Tất nhiên, bạn cũng có thể sẽ không tạo một hệ thống phân cấp lớp để giải quyết vấn đề. Tuy nhiên, có những lúc cách tiếp cận này hữu ích, trong trường hợp không thể thực hiện được điều gì đó đơn giản hơn.

chỉ Robertson

Cảm ơn. ] Đó là sự thật, trong cuộc sống thực, có lẽ bạn sẽ không làm điều gì phức tạp để giải quyết một vấn đề đơn giản như vậy. Tất nhiên, bạn cũng có thể sẽ không tạo một hệ thống phân cấp lớp để giải quyết vấn đề. Tuy nhiên, có những lúc cách tiếp cận này hữu ích, trong trường hợp không thể thực hiện được điều gì đó đơn giản hơn.

monserAR

really very interesting and informative article, by reading this we can add to our insight perusahaan virtual reality indonesia

monserAR

really very interesting and informative article, by reading this we can add to our insight perusahaan virtual reality indonesia

Nihar Shah

This article is very much in deep. So it is useful for those who wants to develop their site in java. Our dedicated nodejs developers on hiring works on java at affordable cost.

Nihar Shah

This article is very much in deep. So it is useful for those who wants to develop their site in java. Our dedicated nodejs developers on hiring works on java at affordable cost.

Michael Stely

I agree. There is definitely a lot of room for improvement with JS. However, I do not agree with your scary-monster-under-the-bed mischaracterization of it. I've built mobile apps with JS for over 10 years, most recently in the React Native framework. It's been both challenging and rewarding. I learn something new every day. Let me ask you this [because I really don't understand the crux of the post]: - Do other languages handle strongly-typed data better? Yep. - Do they coerce more consistent design and/or development through a more consistent set of tools? Sure do. - Conversely, do they provide a broader scope of utility or application than JS? You tell me. I sat no. - Do they have a higher developer adoption rate than JS? No. - Do more businesses around the world bet their company on it than JS? No. - Are all the developers who bet their careers on it and companies who bet their businesses on it simply that stupid and would be better served chucking the whole mess for one of your chosen ones? - Why, then, all the salty hate? That's how it reads to me, at any rate. The undercurrent of disparagement has me wondering, "If you dislike it that much, why not pick any one of dozens of alternatives." I realize this article is dated. Your opinion may have softened. But as I scrolled through the comments, I found no one willing to disagree with your opinion. I thought it incumbent on me to at least provide a differing view.

Mirko

bài viết rất hay. Tôi chỉ còn một câu hỏi, có lẽ vì tôi không biết về nội bộ của JavaScript. Nếu tôi sử dụng các nhà máy này, liệu chúng có tạo ra các phương thức mới cho các đối tượng được sản xuất mỗi khi tôi gọi chúng không?

Matthijs Wensveen

Tôi cảm thấy rằng bạn đã nhầm lẫn những lời chỉ trích hợp lệ với sự ghét cay đắng. Lời chỉ trích là về tính năng lớp [ish] mới trong ES6 [và ở mức độ thấp hơn là các tính năng dựa trên nguyên mẫu cơ bản bị che giấu bởi tính năng này], chứ không phải về chính ngôn ngữ đó. Tôi coi việc các chuyên gia trong lĩnh vực này làm nổi bật những phần chuyên môn mà họ cho là dở là một điều tốt, thay vì truyền giáo một cách mù quáng. Những cuốn sách như “JavaScript. The Good Parts" và "Better, Faster, Lighter Java" là những ví dụ tuyệt vời về những cuốn sách quan trọng nhưng rất hữu ích về chủ đề chuyên môn tương ứng của chúng

Adelchi Pelizzo

Seems to me the more I seek clarification, the more I get confused. Would the first example be still valid this way: function PrototypicalGreeting[greeting = "Hello", name = "World"] { this.greeting = greeting this.name = name greet = function[] { return `${this.greeting}, ${this.name}! } }

David Mauas

Hấp dẫn. Tuy nhiên - về cơ bản không có sự khác biệt trong C++ & C giữa lớp và cấu trúc. struct chỉ là { } một cấu trúc dữ liệu. Các lớp nói riêng và OOP nói chung, IMO, rất tuyệt vì chúng tạo điều kiện cho SUY NGHĨ về mọi thứ như thể chúng là đối tượng. Chúng giúp *con người* chúng ta nhìn mọi thứ rõ ràng hơn. Sắp xếp. Chắc chắn rồi - chúng ta cũng có thể viết *mọi thứ* trong tập hợp. không có sự khác biệt. Các ngôn ngữ cấp cao hơn về cơ bản trừu tượng hóa mọi thứ thành một ngữ nghĩa khác - đó là TẤT CẢ mục đích của chúng. Vì vậy - có - các lớp trong JS không phải là các lớp "thực sự". Nhưng nếu chúng giúp một con người sắp xếp mọi thứ - dù chỉ một chút - bằng thứ ngôn ngữ lộn xộn, lộn xộn này - thì chúng thật tuyệt vời. Và nói chung - ngay cả khi không có sự kế thừa, giao diện, v.v. - các lớp * thực sự * tuyệt vời. Không có ứng dụng quy mô lớn nào [thực sự, rất lớn] - có thể tồn tại mà không có OOP. [và các loại mạnh nữa] Nó đã được kiểm chứng qua thời gian. Giống như các loại mạnh ngăn chặn các vấn đề - mặc dù không thực sự khác biệt - tất cả đều là ngữ nghĩa. Vì vậy, mặc dù "lớp" là "chức năng" được ngụy trang - tôi sẽ chọn nó vì nó có lợi thế. Cũng như lịch sự và nói chuyện tử tế với người khác. Cũng giống như một triệu thứ ngữ nghĩa làm cho cuộc sống của chúng ta tốt hơn rất nhiều. làm ơn, cảm ơn bạn, chúc một ngày tốt lành. ] Ngữ nghĩa tạo nên sự khác biệt *thế giới*. Đó là quan điểm của tôi

Cihan Deniz

AFAIK below factory creates a new function for every time it is called. function greeterFactory[greeting = "Hello", name = "World"] { return { greet: [] => `${greeting}, ${name}!` } } I remember making this mistake and creating the slowest component. And then I switched to prototypes, so number of function instances decreased to one per prototype. Let me give a quick example; const a = { greet: [] => 'hello world' }; const b = { greet: [] => 'hello world' }; Above code has two functions declared, but below has only one. function greet[] { return 'hello world'; } const a = { greet: greet }; const b = { greet: greet }; But that was like 15 years ago, so I'm not sure if my point is still valid or not, I'm just asking if it is...

ytkimirti

bài báo tuyệt vời. Điều này đã giải quyết rất nhiều vấn đề mà tôi gặp phải với các nguyên mẫu ngay cả khi mục tiêu của bạn là làm chúng tôi bối rối. D Tôi đã học được quá nhiều từ bài viết này cảm ơn bạn rất nhiều. ]

Charles Robertson

If you are one of those developers, that example probably horrified you This is assuming you think that a JS Class should follow the way classes in other languages work? Why is it not possible for JavaScript to follow its own set of rules, which it does? Every language has its own idiosyncrasies. As long as one is clear about the rules of a language, everything is fine. Personally, I find the class keyword in JavaScript makes code look cleaner. I think most people understand that is it is just syntactic sugar, like the async/await keyword.

hhvdblom

Tôi là nhà phát triển C/C#/C++ VÀ là nhà phát triển Javascript rất có kinh nghiệm. Tôi rất hoan nghênh lớp học về Javascript. Việc đóng gói lớp rất phù hợp với các dự án của tôi

hhvdblom

C được phát triển vào năm 1972. Nó vẫn còn sống và đá. Javascript đã tệ nhưng đang trở nên tốt hơn. Nó đang đi theo hướng X và điều đó tốt. Những người phủ định phát minh ra "đường cú pháp" nhưng các lớp học chỉ tốt hơn một cách đầy đủ để đi. Tại sao những tiêu cực chống lại các lớp học? . Tôi đã đọc rất nhiều mã javascript cũ và điều đó thật tệ

hhvdblom

Vâng, bạn nói đúng và chính xác. Nguyên mẫu cần được ẩn, nội bộ và không được sử dụng trực tiếp

hhvdblom

Vâng, bạn đúng. Bài viết này quay trở lại phong cách Javascript cũ nhưng các lớp học là con đường tiếp theo nếu anh ấy thích hay không

chỉ Robertson

Xin lỗi vì trả lời rất muộn. Tôi nghĩ rằng bạn đã hiểu sai ý tôi ở đây - và không có gì ngạc nhiên, với mức độ ghét mà một số ngôn ngữ trực tuyến. Có thể dễ dàng coi đây là một bài viết khác về "10 lý do tôi ghét javascript". Nhưng đây là về một tính năng ngôn ngữ cụ thể - các lớp học. Và một số lời chỉ trích về nguyên mẫu. Không phải ngôn ngữ nói chung. Ngược lại, quan điểm của tôi không thay đổi chút nào. Nếu bất cứ điều gì nó đã cứng lại, và ngày nay tôi dựa nhiều vào mã kiểu chức năng và các nhà máy hơn là khi tôi viết bài này. Thật không may, "nỗi sợ" của tôi ở đây đã bò ra khỏi gầm giường. Tôi thấy nhiều thư viện và mô-đun được tích hợp trong WASM hơn mỗi ngày, thường là để tránh javascript và những điều kỳ quặc của nó. Có thể một trang web đa ngôn ngữ không phải là điều tồi tệ nhất trên thế giới, nhưng đó là một sự khác biệt đáng kể so với giấc mơ về một trang web minh bạch và cởi mở

chỉ Robertson

That's sort of the problem I have with classes - unfortunately they don't do encapsulation any different than javascript already did with prototypes. And prototypes were already a pretty inferior way of achieving encapsulation. Prototypes give us inheritance, which is arguably the least useful concept in the OOP paradigm - a rant for another day! So class didn't actually give us anything new, other than the false impression that javascript had classes. What it did give us us was a cleaner way to write prototypes - something that already existed - albeit with a confusing keyword.

chỉ Robertson

In general, yes - I think well-understood keywords should go out of their way to behave as they are commonly understood to behave in other languages. At a minimum, they certainly shouldn't disguise a feature as another unrelated feature in order to make the language feel more familiar. Async/await is actually a perfect counter-example. It behaves analogously to its peers in other languages, while being sugar for something that already existed and worked well in javascript [promises]. In fact you can use promises and async/await completely interchangeably, which is very useful. I am a big fan of that approach.

chỉ Robertson

Vâng, bạn hoàn toàn đúng. Ví dụ đó sẽ tạo một thể hiện mới của hàm mỗi khi nó được gọi. Tôi bỏ qua sự thật này cho ngắn gọn [bài viết đã quá dài. ] Nói chung khi bạn đang xử lý số lượng đối tượng rất lớn hoặc nhiều đối tượng được tạo và hủy liên tiếp nhanh chóng, bạn sẽ gặp vấn đề về hiệu suất. Các nguyên mẫu có thể hữu ích ở đây và đôi khi chúng là câu trả lời đúng, nhưng thường thì những gì bạn đang giải quyết có liên quan đến thu gom rác, trong trường hợp đó, các nguyên mẫu sẽ chỉ giảm bớt một phần vấn đề chứ không loại bỏ được nó. Câu trả lời tốt nhất thường là tránh làm điều này ngay từ đầu. Tìm cách để không phải tạo và phá hủy hàng tấn đồ vật. Nếu bạn không thể làm điều đó, các nhóm đối tượng thường là viên đạn bạc của bạn

chỉ Robertson

Classes specifically, and OOP in general, IMO, are great because they facilitate THINKING about things as IF they were objects..
I am not so convinced this is true. Modularity and encapsulation are important, but thinking of your code as if it was a physical object [say a machine or a tool] is often a false analogy. I escaped the "OOP Cult" a long time ago and found there many different ways to think of code that are often much more useful. This is a rant for another day, and one already made better by other people, but in reply to your whole premise: the notion that large-scale applications cannot exist without OOP is an article of faith unsupported by facts. For example most of our internet infrastructure today runs atop the linux kernel, which is very large, very important, has innumerable contributors and a nearly 30 year history of development, and has never been and could not be object-oriented. Although it does embrace modularity and encapsulation, concerns which are orthogonal to inheritance, message-oriented interfaces and other things that come with the OOP package. Similarly OOP is almost completely unused in scientific simulation, data analysis, commercial video games, and in many other fields that OOP evangelism conveniently ignores. These all certainly qualify as "truly, really large" scale. A typical high-end video game will employ hundreds of people, take half a decade to complete, have millions of customers, and require on-going support and online services for another half-decade after release. And yet you don't see OOP being applied very often in game programming because it's a bad fit [the Unity game engine is a notable exception]. You'd think it was the perfect fit of course, if you came up in the OOP school [isn't a video game chock full of virtual objects, and don't they have many hierarchical relationships?] but it turns out that the way a game engine must manipulate its data in order to achieve acceptable performance is incompatible with that paradigm. I'll end up writing another article here if I keep going, so instead I recommend searching for good criticisms of OOP and what other paradigms have to offer.

chỉ Robertson

Xem câu trả lời của tôi cho OP để biết lý do tại sao tôi không đồng ý. ]

chỉ Robertson

Vâng, bạn đúng. Hầu hết thời gian đây không phải là vấn đề, nhưng như trong bài đăng StackOverflow của bạn, nó có thể trở thành vấn đề khi bạn tạo hàng tấn đối tượng. Để thêm vào các câu trả lời, hiệu suất gặp trở ngại với số lượng lớn các đối tượng thường đến từ việc khởi tạo hoặc thu gom rác các đối tượng đó. Nhóm đối tượng là một cách tuyệt vời để giải quyết vấn đề này và đáng để xem xét nếu bạn cần xử lý một đống lớn các đối tượng đồng nhất

david moore

I figured out a very annoying thing here: I found that in node, there's the following situation: console.log[Object.getPrototypeOf[greetProto]] //PrototypicalGreeting { greet: [Function] } console.log[Object.getPrototypeOf[classyGreeting]] //ClassicalGreeting {} This is solved in this stackoverflow question: //stackoverflow.com/a/44186329/17616747 , where it's stated "Methods/properties created through the class syntax are non-enumerable and it seems that the environment you log the value in doesn't show non-enumerable properties. console.log is not standardized, so different outputs in different environments have to be expected." So there's a difference in whether the prototype properties are enumerable. Yeesh. Hopefully this helps someone else out!

chỉ Robertson

Ah, yes that's a good catch. You can make properties of a class instance enumerable through the Object.defineProperty method if you'd like them to be. One key thing to remember is that non-enumerable properties are still exposed on the object; they just won't appear in enumerations like for .. in. So making a property enumerable or non-enumerable does not relate to concepts like privacy or encapsulation. This is another of those weird gotchas that makes me think the whole notion of introducing class into JS was a mistake. JS just fundamentally does not work like Java and other classical OOP languages, despite superficial similarities. The list of edge cases and broken expectations class introduced is innumerable, pun intended.

xpdx

Có vẻ như vấn đề lớn nhất là sử dụng từ khóa "class" vì nó chứa quá nhiều hành lý từ các ngôn ngữ khác. Chỉ cần sử dụng một gợi ý từ khóa ngắn gọn súc tích khác ở gốc nguyên mẫu sẽ dễ chịu hơn. Tôi thích cú pháp lớp JS hơn cú pháp nguyên mẫu ban đầu, nhưng nó có vẻ khiến nhiều người nhầm lẫn

chỉ Robertson

Tôi đồng ý rằng sử dụng một từ khóa phù hợp hơn phản ánh những gì đang thực sự xảy ra sẽ tốt hơn. Một số tốc ký được giới thiệu để hỗ trợ "lớp" cũng hoạt động theo nghĩa đen đối tượng trong ES6 nếu bạn thích nó.

class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
4 Và tất nhiên, bạn cũng có thể mô phỏng các thành viên riêng tư bằng cách sử dụng bao đóng theo cách này.
class ClassicalGreeting {
  constructor[greeting = "Hello", name = "World"] {
    this.greeting = greeting
    this.name = name
  }

  greet[] {
    return `${this.greeting}, ${this.name}!`
  }
}

const classyGreeting = new ClassicalGreeting["Hey", "folks"]

console.log[classyGreeting.greet[]]
5 Bạn sẽ không nhận được tài sản thừa kế thông qua "extends", nhưng tất nhiên tôi sẽ nói "bạn có chắc là bạn muốn điều đó không?"

Lớp có phải là một đối tượng trong JavaScript không?

Một lớp JavaScript không phải là một đối tượng . Nó là một khuôn mẫu cho các đối tượng JavaScript.

Tôi có nên sử dụng lớp hoặc đối tượng JavaScript không?

Tuy nhiên, điểm quan trọng nhất là không có lớp nào trong JavaScript vì JavaScript là ngôn ngữ hướng đối tượng nguyên mẫu. Điều này có nghĩa là các đối tượng trong JavaScript kế thừa trực tiếp từ các đối tượng khác. Do đó chúng ta không cần các lớp học . Tất cả những gì chúng ta cần là một cách để tạo và mở rộng các đối tượng.

Chủ Đề