Tìm hiểu về Duck Typing trong ECMAScript

Xem thêm các chuyên mục:

1- Duck Typing là gì?

Trước khi đưa ra một định nghĩ về "Duck Typing" tôi muốn nói với bạn về khái niêm Interface trong ngôn ngữ lập trình.
Interface là một khái niệm có trong một vài ngôn ngữ lập trình, chẳng hạn như Java, CSharp,... Một Interface sẽ khai báo ra danh sách các phương thức của nó, các phương thức này không có nội dung (không có thân). Lớp thực hiện (implements) Interface này phải có tất cả các phương thức được khai báo trong Interface với nội dung đầy đủ. (Chú ý: Ở đây tôi không đề cập tới các lớp trừu tượng).
Như vậy InterfaceClass là hai khái niệm khác nhau, Interface định nghĩa ra một tiêu chuẩn nào đó mà các lớp thực hiện (implements) nó phải tuân thủ.
Các ngôn ngữ như Ruby, ECMAScript không có khái niệm Interface một cách tường minh, nó chỉ có khái niệm Class. Nhưng "Duck Typing" có thể là một cách để bạn tạo ra một thứ gì đó tương tương tự như Interface trong ECMAScript.

Duck Typing?

Duck Typing (Phân loại Vịt) ám chỉ một chương trình thử nghiệm Vịt (Duck Test), bạn sẽ kiểm tra một thứ gì đó, nếu nó đi như vịt, và bay giống như Vịt thì nó là Vịt.
Một cách hài ước, nếu bạn kiểm tra cái máy bay (Airplane), bạn thấy rằng nó đi giống như vịt, nó bay như vịt, vậy kết luận nó là Vịt.
Nhược điểm của Duck Typing:
Duck Typing được sử dụng trong nhiều ngôn ngữ lập trình chẳng hạn Ruby, ECMAScript,.. và nó thực sự có ích, nhưng đôi khi nó tạo ra các hành vi không mong muốn trong ứng dụng, bởi vì quy tắc của Duck Typing quá đơn giản và có thể dẫn tới các kết luận sai lầm, bạn có thể hiểu hơn về lời cảnh báo này trong các ví dụ.

2- Ví dụ với Duck Typing

OK, ECMAScript không có khái niệm Interface. Ở dưới đây tôi có một lớp Duck (Vịt), nó có 2 phương thức walk() & fly().
class Duck  {

  fly()  {
     console.log("Duck fly");
  }

  walk()  {
    console.log("Duck walk");
  }

}
Lớp Airplane cũng có tất các phương thức giống như lớp Duck, theo quy tắc Duck Typing, bạn có thể nói rằng Airplane thuộc kiểu Duck.
class Airplane  {

  fly()  {
     console.log("Airplane fly");
  }

  walk()  {
    console.log("Airplane walk");
  }

  shoot(target)  {
    console.log("Airplane shoot " + target);
  }

}
Lớp Cat có phương thức walk() nhưng không có phương thức fly(). Theo quy tắc Duck Typing bạn có thể kết luận Cat không thuộc kiểu Duck.
class Cat  {

  walk() {
    console.log("Cat walk");
  }
}
Xem ví dụ đầy đủ:
duck-typing-example1.js
class Duck  {

  fly()  {
     console.log("Duck fly");
  }

  walk()  {
    console.log("Duck walk");
  }

}

class Airplane  {

  fly()  {
     console.log("Airplane fly");
  }

  walk()  {
    console.log("Airplane walk");
  }

  shoot(target)  {
    console.log("Airplane shoot " + target);
  }

}

class Cat  {

  walk() {
    console.log("Cat walk");
  }
}


let duck1 = new Duck();
let airplane1 = new Airplane();
let cat1 = new Cat();

function checkDuck(testObj) {
   if(typeof testObj.fly == "function" && typeof testObj.walk == "function" ) {
       return true;
   }
   return false;
}

// Array
let testArray = [duck1, airplane1, cat1];

for( let i = 0; i < testArray.length; i++) {
   let testObj = testArray[i];

   if( checkDuck(testObj) )  {
     testObj.fly();
   }
}
 
Ví dụ 2:
duck-typing-example2.js
var duck = {
    type: "bird",
    cry: function duck_cry(what) {
        console.log(what + " quack-quack!");
    },
    color: "black"
};

var someAnimal = {
    type: "bird",
    cry: function animal_cry(what) {
        console.log(what + " whoof-whoof!");
    },
    eyes: "yellow"
};

function check(who) {
    if ((who.type == "bird") && (typeof who.cry == "function")) {
        who.cry("I look like a duck!\n");
        return true;
    }
    return false;
}

check(duck);  // true
check(someAnimal);  // true

Xem thêm các chuyên mục: