Chào các bạn, hôm nay cafedev chia sẻ cho ace một danh sách các bài tập từ cơ bản tới nâng cao liên quan tới các kiến thức cơ bản trong lập trình Javascript. Cụ thể, trong bài này chúng ta sẽ làm quen với Prototypes, inheritance. Từ đó giúp ace nâng cao kiến thức, kỹ năng, kinh nghiệm lập trình của mình và áp dụng nó vào thực tế.

Trước khi đi vào chi tiết bài tập, cafedev khuyến khích ace tự code bài tập của mình trước khi tham khảo bài hướng dẫn nhé.

Để chạy hoặc code các bài tập sau, ace có thể code trên trang web này như sau:

  • Chọn new
  • Chọn dự án bạn muốn code, ở đây có nhiều lựa chọn như Javascript, AngularJS, React,…. Tất nhiên mình sẽ chọn Javascript.
  • Sau đó bạn sẽ thấy nơi bạn code.
  • Sau khi code sau chọn Preview để xem kết quả.

Ngoài ra ace cũng có thể dùng các IDE đã được giới thiệu tại đây để code và chạy code đó trên máy tính của mình nhé.

Lưu ý: Mọi bài tập bên dưới cũng như các bài tập khác trong Series Javascript này được tạo ra từ các bài học và kiến thức của từng phần trong series tự học Javascript này. Nếu ace nào chưa làm được hoặc chưa hiểu kỹ về bài học thì bạn có thể tham khảo lại series tự học này nhé. Chúc các bạn thành công.

Bài 1

Đây là code tạo một cặp đối tượng, sau đó sửa đổi chúng.

Những giá trị nào được hiển thị trong quá trình?

let animal = {
  jumps: null
};
let rabbit = {
  __proto__: animal,
  jumps: true
};

alert( rabbit.jumps ); // ? (1)

delete rabbit.jumps;

alert( rabbit.jumps ); // ? (2)

delete animal.jumps;

alert( rabbit.jumps ); // ? (3)

Bài 2

Bài có hai phần.

Cho các đối tượng sau:

let head = {
  glasses: 1
};

let table = {
  pen: 3
};

let bed = {
  sheet: 1,
  pillow: 2
};

let pockets = {
  money: 2000
};
  • Sử dụng __proto__ để gán các nguyên mẫu theo cách mà bất kỳ tra cứu thuộc tính nào cũng sẽ đi theo đường dẫn: pocketsbedtablehead. Ví dụ: pocket.pen nên là 3 (tìm thấy trong table) và bed.glasses nên là 1 (tìm thấy trong head).
  • Trả lời câu hỏi: lấy glasses làm pockets.glasses hay head.glasse. Cái này nhanh hơn?

Bài 3

Chúng ta có animal thừa hưởng từ animal.

Nếu chúng ta gọi là Rabbit.eat (), đối tượng nào nhận được full thuộc tính: animal or rabbit?

let animal = {
  eat() {
    this.full = true;
  }
};

let rabbit = {
  __proto__: animal
};

rabbit.eat();

Bài 4

Chúng ta có hai loại hamster: thừa hưởng speedylazy từ đối tượng hamster nói chung.

Khi chúng ta cho một con nào đó, con kia cũng no. Tại sao? Làm thế nào chúng ta có thể sửa chữa nó?

let hamster = {
  stomach: [],

  eat(food) {
    this.stomach.push(food);
  }
};

let speedy = {
  __proto__: hamster
};

let lazy = {
  __proto__: hamster
};

// This one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple

// This one also has it, why? fix please.
alert( lazy.stomach ); // apple

Bài 5

Trong đoạn code bên dưới, chúng ta tạo Rabbit mới và sau đó cố gắng sửa đổi nguyên mẫu của nó.

Đầu tiên, chúng ta có code này:

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

alert( rabbit.eats ); // true
  • Chúng ta đã thêm một chuỗi nữa (nhấn mạnh). Cảnh báo sẽ hiển thị gì bây giờ?
function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats ); // ?

… Và nếu code là như thế này (thay thế một dòng)?

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype.eats = false;

alert( rabbit.eats ); // ?
  • Và như thế này (thay thế một dòng)?
function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

delete rabbit.eats;

alert( rabbit.eats ); // ?
  • Biến thể cuối cùng:
function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

delete Rabbit.prototype.eats;

alert( rabbit.eats ); // ?

Bài 6

Hãy tưởng tượng, chúng ta có một đối tượng obj tùy ý, được tạo bởi một hàm tạo – chúng ta không biết cái nào, nhưng chúng ta muốn tạo một đối tượng mới bằng cách sử dụng nó.

Chúng ta có thể làm như vậy được không?

let obj2 = new obj.constructor();

Đưa ra một ví dụ về một hàm tạo cho obj để cho phép code như vậy hoạt động đúng. Và một ví dụ làm cho nó hoạt động sai.

Hướng dẫn cách xem và tải tài liệu từ trang cafedev tại đây.


Giải bài 1,2,3,4,5,6

Bài 7

Thêm vào nguyên mẫu của tất cả các hàm phương thức defer(ms), phương thức này sẽ chạy hàm sau mili giây.

Sau khi bạn làm điều đó, code như vậy sẽ hoạt động:

function f() {
  alert("Hello!");
}

f.defer(1000); // shows "Hello!" after 1 second

Bài 8

Thêm vào nguyên mẫu của tất cả các hàm phương thức defer(ms), trả về một trình bao bọc, trì hoãn cuộc gọi theo mili giây.

Dưới đây là một ví dụ về cách nó sẽ hoạt động:

function f(a, b) {
  alert( a + b );
}

f.defer(1000)(1, 2); // shows 3 after 1 second

Bài 9

Có một đối tượng dictionary, được tạo dưới dạng Object.create(null), để lưu trữ bất kỳ cặp khóa / giá trị nào.

Thêm phương thức dictionary.toString () vào đó, sẽ trả về danh sách các khóa được phân tách bằng dấu phẩy. Chuỗi toString của bạn không được hiển thị trong for..in trên đối tượng.

Đây là cách nó sẽ hoạt động:

let dictionary = Object.create(null);

// your code to add dictionary.toString method

// add some data
dictionary.apple = "Apple";
dictionary.__proto__ = "test"; // __proto__ is a regular property key here

// only apple and __proto__ are in the loop
for(let key in dictionary) {
  alert(key); // "apple", then "__proto__"
}

// your toString in action
alert(dictionary); // "apple,__proto__"

Bài 10

Hãy tạo một đối tượng rabbit mới:

function Rabbit(name) {
  this.name = name;
}
Rabbit.prototype.sayHi = function() {
  alert(this.name);
};

let rabbit = new Rabbit("Rabbit");

Những cuộc gọi này có làm điều tương tự hay không?

rabbit.sayHi();
Rabbit.prototype.sayHi();
Object.getPrototypeOf(rabbit).sayHi();
rabbit.__proto__.sayHi();

Giải bài 7,8,9,10

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!