Javascript prototype chuyên sâu

Công Nghệ
Javascript prototype chuyên sâu
Bài này chỉ phù hợp với các bạn đã có kiến thức trung bình khá javascript trở lên, mình không chỉ đơn giản giải thích cách xài mà còn sâu hơn, bạn sẽ nắm rất rất rõ prototype trong javascript thực chất là gì Object trong javascript rất là vi diệu. Nó là nền tảng của rất nhiều thứ hay ho trong javascript. Object là một cặp giá trị key/value. Cách đơn giản nhất tạo một object là obj = {} , thêm các property và phương thức sử dụng dấu chấm let animal = {} animal.name = 'Leo' animal.energy = 10 animal.eat = function (amount) { console.log(`${this.name} is eating.`) this.energy += amount } animal.sleep = function (length) { console.log(`${this.name} is sleeping.`) this.energy += length } animal.play = function (length) { console.log(`${this.name} is playing.`) this.energy -= length } Quá đơn giản. Giờ chúng ta muốn có thêm một animal khác, chúng ta đưa toàn bộ logic này vào bên trong 1 function, cách này gọi là Functional Instantiation hay constructor function function Animal (name, energy) { let animal = {} animal.name = name animal.energy = energy animal.eat = function (amount) { console.log(`${this.name} is eating.`) this.energy += amount } animal.sleep = function (length) { console.log(`${this.name} is sleeping.`) this.energy += length } animal.play = function (length) { console.log(`${this.name} is playing.`) this.energy -= length } return animal } const leo = Animal('Leo', 7) const snoop = Animal('Snoop', 10) Khi chúng ta muốn tạo một instance mới của Animal , tất cả những gì chúng ta cần làm là gọi lại hàm Animal . Cách làm này có một điểm hạn chế, các phương thức eat , sleep , play là hoàn toàn giống nhau cho các instance, đồng thời khi tạo một instance mới chúng ta cũng đã vô tình lãng phí bộ...
Bài này chỉ phù hợp với các bạn đã có kiến thức trung bình khá javascript trở lên, mình không chỉ đơn giản giải thích cách xài mà còn sâu hơn, bạn sẽ nắm rất rất rõ prototype trong javascript thực chất là gì
Object trong javascript rất là vi diệu. Nó là nền tảng của rất nhiều thứ hay ho trong javascript.

Object là một cặp giá trị key/value. Cách đơn giản nhất tạo một object là obj = {}, thêm các property và phương thức sử dụng dấu chấm

let animal = {}
animal.name = 'Leo'
animal.energy = 10

animal.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

animal.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

animal.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

Quá đơn giản. Giờ chúng ta muốn có thêm một animal khác, chúng ta đưa toàn bộ logic này vào bên trong 1 function, cách này gọi là Functional Instantiation hay constructor function

function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy

  animal.eat = function (amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  }

  animal.sleep = function (length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  }

  animal.play = function (length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }

  return animal
}

const leo = Animal('Leo', 7)
const snoop = Animal('Snoop', 10)

Khi chúng ta muốn tạo một instance mới của Animal, tất cả những gì chúng ta cần làm là gọi lại hàm Animal.

Cách làm này có một điểm hạn chế, các phương thức eatsleepplay là hoàn toàn giống nhau cho các instance, đồng thời khi tạo một instance mới chúng ta cũng đã vô tình lãng phí bộ nhớ bằng việc khai báo thêm những object mà đôi khi không cần thiết.

Tuyển dụng lập trình Javascript lương cao

Chúng ta sẽ tách các phương thức này ra. Từ ngữ chuyên môn cho vấn đề này là Functional Instantiation với các phương thức dùng chung.

const animalMethods = {
  eat(amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  },
  sleep(length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  },
  play(length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
}

function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy
  animal.eat = animalMethods.eat
  animal.sleep = animalMethods.sleep
  animal.play = animalMethods.play

  return animal
}

Các phương thức dùng chung giờ đây nằm ở từng object và refer đến object bên trong của Animal.

Object.create

Nâng cấp thêm chút nữa bằng Object.createObject.create cho phép bạn tạo một object, nếu không tìm thấy nó sẽ đưa về một object khác để xem có thể tìm thấy property đó không.

const parent = {
  name: 'Stacey',
  age: 35,
  heritage: 'Irish'
}

const child = Object.create(parent)
child.name = 'Ryan'
child.age = 7

console.log(child.name) // Ryan
console.log(child.age) // 7
console.log(child.heritage) // Irish

Trong ví dụ trên, bởi vì children được tạo bởi Object.create(parent), khi nó không tìm thấy property trong children, javascript tự nó biết tìm đến parent object. Trong ví dụ này, child không có property là heritage, mà parent có, nên nó sẽ lấy của parent là Irish

Giờ làm sao chúng ta đơn giản hoá code của Animal? Thay vì thêm tất cả các phương thức dùng chung vào Animal từng thằng một, có thể dùng Object.create để truyền object animalMethods

const animalMethods = {
  eat(amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  },
  sleep(length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  },
  play(length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
}

function Animal (name, energy) {
  let animal = Object.create(animalMethods)
  animal.name = name
  animal.energy = energy

  return animal
}

const leo = Animal('Leo', 7)
const snoop = Animal('Snoop', 10)

leo.eat(10)
snoop.play(5)

Bây giờ khi gọi leo.eat, javascript sẽ tìm phương thức eat trên object leo. Nếu fail, nó đưa đến animalMethods trong đó có hàm eat

Làm như vậy có thể bị xem là hơi tricky khi quản lý một object độc lập cho các phương thức dùng chung.

Javascript chúng ta có prototype đảm nhiệm việc này mà bạn không cần viết thêm gì cả.

Tất cả function trong Javascript có một property là prototype, nó reference đến một object.

Holy grab? Không tin có thể test

function doThing () {}
console.log(doThing.prototype) // {}

Thay vì viết Object.create(animalMethods), chúng ta cứ dùng luôn object có sẵn là prototype

function Animal (name, energy) {
  let animal = Object.create(Animal.prototype)
  animal.name = name
  animal.energy = energy

  return animal
}

Animal.prototype.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

Animal.prototype.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

Animal.prototype.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

const leo = Animal('Leo', 7)
const snoop = Animal('Snoop', 10)

leo.eat(10)
snoop.play(5)

Hy vọng là bạn có giây phút ERECA khi đọc tới đây, như mình đã có. prototype chỉ là một property mà tất cả function trong javascript đều có.

Sâu hơn xa hơn

Tới thời điểm này, chúng ta đã biết

  1. Tạo một function constructor
  2. Thêm phương thức cho function constructor bằng prototype
  3. Sử dụng Object.create để khi fail trỏ đến prototype

Cái này là quá căn bản với các ngôn ngữ lập trình khác, không lẽ javascript lại tệ đến vậy sao, không có một cách chính thống để làm? Có chứ, sử dụng new

Tại sao chúng ta phải đi cả ngàn dặm tới bước này, sao mình không nói toạc luôn ngay từ đầu? Với cách này bạn sẽ nắm rất sâu, hiểu rất rõ new sẽ làm gì bên dưới

Xem lại constructor Animal, 2 phần quan trọng nhất là tạo object và return nó.

function Animal (name, energy) {
  let animal = Object.create(Animal.prototype)
  animal.name = name
  animal.energy = energy

  return animal
}

new thì có gì hót – khi gọi một function sử dụng new, 2 dòng code này sẽ được chạy luôn cho mình và object được tạo ra gọi là this

Cách viết dùng new

function Animal (name, energy) {
  // const this = Object.create(Animal.prototype)

  this.name = name
  this.energy = energy

  // return this
}

Animal.prototype.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

Animal.prototype.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

Animal.prototype.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

const leo = new Animal('Leo', 7)
const snoop = new Animal('Snoop', 10)

Không dùng new, lỗi

function Animal (name, energy) {
  this.name = name
  this.energy = energy
}

const leo = Animal('Leo', 7)
console.log(leo) // undefined

WTF? Cả đống này chỉ là để làm cái class trong các ngôn ngữ khác thôi ư?

Đúng. Trước thời ES6, javascript không có vụ class này, chúng ta dùng như vậy đấy.

Vậy nếu bạn đang đọc bài này, thì bạn đã qua thời ES6, ES7, chúng ta có cách chính thống để làm. Bên dưới ES6 thì nó cũng làm i chang như vậy thôi, chẳng qua là bạn được viết bằng cách có “gu” hơn, chứ bên dưới nó vẫn implement như thế.

class Animal {
constructor(name, energy) {
this.name = name
this.energy = energy
}
eat(amount) {
console.log(`${this.name} is eating.`)
this.energy += amount
}
sleep(length) {
console.log(`${this.name} is sleeping.`)
this.energy += length
}
play(length) {
console.log(`${this.name} is playing.`)
this.energy -= length
}
} const leo = new Animal('Leo', 7) const snoop = new Animal('Snoop', 10)

Một số phương thức với prototype nên biết

Lấy tất cả prototype của function

Object.getPrototypeOf()

function Animal (name, energy) {
  this.name = name
  this.energy = energy
}

Animal.prototype.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

Animal.prototype.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

Animal.prototype.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

const leo = new Animal('Leo', 7)
const prototype = Object.getPrototypeOf(leo)

console.log(prototype)
// {constructor: ƒ, eat: ƒ, sleep: ƒ, play: ƒ}

prototype === Animal.prototype // true

Có 2 điểm quan trọng trong đoạn code trên

  • 1 là chỗ constructor cũng được liệt kê ra như một hàm, như vậy bất kỳ instance nào cũng có thể gọi đến constructor bằng instance.constructor
  • 2 là nếu so sánh Object.getPrototypeOf(leo) === Animal.prototype là đúng.

Xác định một property có tồn tại trong prototype không

.hasOwnProperty()

const leo = new Animal('Leo', 7)

for(let key in leo) {
  if (leo.hasOwnProperty(key)) {
    console.log(`Key: ${key}. Value: ${leo[key]}`)
  }
}

kiểm tra một object có phải là một instance của Class

object instanceof Class

function Animal (name, energy) {
  this.name = name
  this.energy = energy
}

function User () {}

const leo = new Animal('Leo', 7)

leo instanceof Animal // true
leo instanceof User // false

Lưu ý về arrow function

Do arrow function không có this bên trong nó, không thể dùng nó như một constructor function

const Animal = () => {}

const leo = new Animal() // Error: Animal is not a constructor

Đồng thời arrow function cũng sẽ không có prototype

const Animal = () => {}

console.log(Animal.prototype) // undefined
Bài viết gốc được đăng tải tại Vuilaptrinh
Tham khảo thêm các vị trí tuyển IT đa ngành tại đây

Bài viết liên quan

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bài viết được sự cho phép của tác giả Chung Nguyễn Hôm nay, nhóm Laravel đã phát hành một phiên bản chính mới của “ laravel/installer ” bao gồm hỗ trợ khởi động nhanh các dự án Jetstream. Với phiên bản mới này khi bạn chạy laravel new project-name , bạn sẽ nhận được các tùy chọn Jetstream. Ví dụ: API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth Cách sử dụng Laravel với Socket.IO laravel new foo --jet --dev Sau đó, nó sẽ hỏi bạn thích stack Jetstream nào hơn: Which Jetstream stack do you prefer? [0] Livewire [1] inertia > livewire Will your application use teams? (yes/no) [no]: ... Nếu bạn đã cài bộ Laravel Installer, để nâng cấp lên phiên bản mới bạn chạy lệnh: composer global update Một số trường hợp cập nhật bị thất bại, bạn hãy thử, gỡ đi và cài đặt lại nha composer global remove laravel/installer composer global require laravel/installer Bài viết gốc được đăng tải tại chungnguyen.xyz Có thể bạn quan tâm: Cài đặt Laravel Làm thế nào để chạy Sql Server Installation Center sau khi đã cài đặt xong Sql Server? Quản lý các Laravel route gọn hơn và dễ dàng hơn Xem thêm Tuyển dụng lập trình Laravel hấp dẫn trên Station D

By stationd
Principle thiết kế của các sản phẩm nổi tiếng

Principle thiết kế của các sản phẩm nổi tiếng

Tác giả: Lưu Bình An Phù hợp cho các bạn thiết kế nào ko muốn làm code dạo, design dạo nữa, bạn muốn cái gì đó cao hơn ở tầng khái niệm Nếu lập trình chúng ta có các nguyên tắc chung khi viết code như KISS , DRY , thì trong thiết kế cũng có những nguyên tắc chính khi làm việc. Những nguyên tắc này sẽ là kim chỉ nam, nếu có tranh cãi giữa các member trong team, thì cứ đè nguyên tắc này ra mà giải quyết (nghe hơi có mùi cứng nhắc, mình thì thích tùy cơ ứng biến hơn) Tìm các vị trí tuyển dụng designer lương cao cho bạn Nguyên tắc thiết kế của GOV.UK Đây là danh sách của trang GOV.UK Bắt đầu với thứ user cần Làm ít hơn Thiết kế với dữ liệu Làm mọi thứ thật dễ dàng Lặp. Rồi lặp lại lần nữa Dành cho tất cả mọi người Hiểu ngữ cảnh hiện tại Làm dịch vụ digital, không phải làm website Nhất quán, nhưng không hòa tan (phải có chất riêng với thằng khác) Cởi mở, mọi thứ tốt hơn Bao trừu tượng luôn các bạn, trang Gov.uk này cũng có câu tổng quát rất hay Thiết kế tốt là thiết kế có thể sử dụng. Phục vụ cho nhiều đối tượng sử dụng, dễ đọc nhất nhất có thể. Nếu phải từ bỏ đẹp tinh tế – thì cứ bỏ luôn . Chúng ta tạo sản phẩm cho nhu cầu sử dụng, không phải cho người hâm mộ . Chúng ta thiết kế để cả nước sử dụng, không phải những người đã từng sử dụng web. Những người cần dịch vụ của chúng ta nhất là những người đang cảm thấy khó sử dụng dịch...

By stationd
Hiểu về trình duyệt – How browsers work

Hiểu về trình duyệt – How browsers work

Bài viết được sự cho phép của vntesters.com Khi nhìn từ bên ngoài, trình duyệt web giống như một ứng dụng hiển thị những thông tin và tài nguyên từ server lên màn hình người sử dụng, nhưng để làm được công việc hiển thị đó đòi hỏi trình duyệt phải xử lý rất nhiều thông tin và nhiều tầng phía bên dưới. Việc chúng ta (Developers, Testers) tìm hiểu càng sâu tầng bên dưới để nắm được nguyên tắc hoạt động và xử lý của trình duyệt sẽ rất hữu ích trong công việc viết code, sử dụng các tài nguyên cũng như kiểm thử ứng dụng của mình. Cách để npm packages chạy trong browser Câu hỏi phỏng vấn mẹo về React: Component hay element được render trong browser? Khi hiểu được cách thức hoạt động của trình duyệt chúng ta có thể trả lời được rất nhiều câu hỏi như: Tại sao cùng một trang web lại hiển thị khác nhau trên hai trình duyệt? Tại sao chức năng này đang chạy tốt trên trình duyệt Firefox nhưng qua trình duyệt khác lại bị lỗi? Làm sao để trang web hiển thị nội dung nhanh và tối ưu hơn một chút?… Hy vọng sau bài này sẽ giúp các bạn có một cái nhìn rõ hơn cũng như giúp ích được trong công việc hiện tại. 1. Cấu trúc của một trình duyệt Trước tiên chúng ta đi qua cấu trúc, thành phần chung và cơ bản nhất của một trình duyệt web hiện đại, nó sẽ gồm các thành phần (tầng) như sau: Thành phần nằm phía trên là những thành phần gần với tương tác của người dùng, càng phía dưới thì càng sâu và nặng về xử lý dữ liệu hơn tương tác. Nhiệm...

By stationd
Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Lĩnh vực EdTech (ứng dụng công nghệ vào các sản phẩm giáo dục) trên toàn cầu hiện nay đã tương đối phong phú với nhiều tên tuổi lớn phân phối đều trên các hạng mục như Broad Online Learning Platforms (nền tảng cung cấp khóa học online đại chúng – tiêu biểu như Coursera, Udemy, KhanAcademy,…) Learning Management Systems (hệ thống quản lý lớp học – tiêu biểu như Schoology, Edmodo, ClassDojo,…) Next-Gen Study Tools (công cụ hỗ trợ học tập – tiểu biểu như Kahoot!, Lumosity, Curriculet,…) Tech Learning (đào tạo công nghệ – tiêu biểu như Udacity, Codecademy, PluralSight,…), Enterprise Learning (đào tạo trong doanh nghiệp – tiêu biểu như Edcast, ExecOnline, Grovo,..),… Hiện nay thị trường EdTech tại Việt Nam đã đón nhận khoảng đầu tư khoảng 55 triệu đô cho lĩnh vực này nhiều đơn vị nước ngoài đang quan tâm mạnh đến thị trường này ngày càng nhiều hơn. Là một trong những xu hướng phát triển tốt, và có doanh nghiệp đã hoạt động khá lâu trong ngành nêu tại infographic như Topica, nhưng EdTech vẫn chỉ đang trong giai đoạn sơ khai tại Việt Nam. Tại Việt Nam, hệ sinh thái EdTech trong nước vẫn còn rất non trẻ và thiếu vắng nhiều tên tuổi trong các hạng mục như Enterprise Learning (mới chỉ có MANA), School Administration (hệ thống quản lý trường học) hay Search (tìm kiếm, so sánh trường và khóa học),… Với chỉ dưới 5% số dân công sở có sử dụng một trong các dịch vụ giáo dục online, EdTech cho thấy vẫn còn một thị trường rộng lớn đang chờ được khai phá. *** Vừa qua Station D đã công bố Báo cáo Vietnam IT Landscape 2019 đem đến cái nhìn toàn cảnh về các ứng dụng công...

By stationd