Tại sao kết quả khác nhau khi chạy 1 đoạn code trên Console của browser và Terminal?

var obj = {a: 'Custom'};

// This property is set on the global object
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // The value of this is dependent on how the function is called
}

whatsThis();          // Returns 'Global'
whatsThis.call(obj);  // Returns 'Custom'
whatsThis.apply(obj); // Returns 'Custom'

Nguồn: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
mình chạy lệnh này từng dòng một trên ‘Console của browser’ và Terminal nó ra kết quả giống như comment ở trên.
Những khi đánh cả một đoạn giống y hết hoặc copy sang y nguyên rùi dùng ‘node’ chạy thì… Kết quả lại khác ? Tại sao vậy? Ai rành giúp mình với…

1 Like

Mình không rành JavaScript, nên mình thấy đoạn này sai sai:

function whatsThis(arg) {
  return this.a;
}

whatsThis();

Ở trên thì là định nghĩa hàm whatsThis có tham số. Ở dưới lại gọi hàm whatsThis không có tham số. Như vậy nếu theo các ngôn ngữ mình đã biết thì hàm whatsThis không có tham số là chưa được định nghĩa → Kết quả nhận được sẽ là undefined

3 Likes

Trong 1 file JS, chính xác hơn là trong 1 module, tất cả câu lệnh khai báo (khai báo biến, khai báo hàm) được bao bởi 1 object và gán nó vào 1 biến ngầm this. Với đoạn JS của bạn, object ngầm như thế này:

var this = {
  obj: { a: 'Custom' }
  a: 'Global',
  whatsThis: function (arg) { return this.a; }
};

Ba lời gọi hàm (function call) trở thành:

whatsThis();
whatsThis.call(obj);
whatsThis.apply(obj);

this.whatsThis(); // 1
this.whatsThis.call(obj); // 2
this.whatsThis.apply(obj); // 3

Việc xác định từ khoá this phụ thuộc vào vị trí lời gọi hàm.
Trong trường hợp 1, this ngầm toàn cục truyền vào hàm whatsThis, this.a có giá trị là ‘Global’
Trường hợp 2 và 3, do gọi thêm method call() và method apply() (function trong JS là object, vì vậy function có method, bạn chú ý sau whatsThis không có cặp () ), sẽ thay đổi this ngầm thành giá trị được truyền vào call(), apply(). Lúc này, this được thay thành obj. Trong hàm whatsThis, this.a là obj.a, kết quả trả về là ‘Custom’

2 Likes

Đúng rùi anh. Nhưng sao trên Terminal nó lại ra kết quả khác với thực tế nhỉ @@! cái này mới khiến em thắc mắc anh ạ.

Vậy chắc mình nhầm bên Front-end. Mỗi file sẽ được gán ngầm định 1 biến global, là biến window, nên 2 lệnh này như nhau:

var a = 'Global';
window.a = 'Global';

Còn bên Node chắc không có vụ gán ngầm this, khai báo sau thì biến this luôn là object rỗng { }. Đoán vậy thôi.

2 Likes

Cảm ơn anh đã nhiệt tình giúp đỡ newbie trong như em :slight_smile: g9! cái này chắc em học thêm vài tháng or vài năm mới biết mất! dù sao cũng cảm ơn anh nhé :blush:

1 Like

Môi trường node và môi trường browser là khác nhau.
Khi học về this hay “strict” mode thì thường họ sẽ nói về sự khác nhau này.

1 Like

Hi,

Ở trong javascript, nếu bạn chạy trên môi trường nodejs thì global object là global còn trên trình duyệt là object window.

Khi bạn khai báo var a = 'Global' thì a sẽ ở module wrapper.

(function(exports, require, module, __filename, __dirname) {
// It keeps top-level variables (defined with var, const or let)
// scoped to the module rather than the global object.
});

Nên khi bạn gọi hàm whatsThis() ở global thì tức là bạn đang chạy whatsThis.call(this), this ở đây lại là một object không cùng context với module wrapper function.vì vậy athis.a trong function whatsThis không cùng 1 context nên this.a sẽ return undefined. ( Mình đoán vậy :smile: )

  ...
  var a = 'Global';
  ...
  whatsThis(); // hay whatsThis.call(this) -> a === 'undefined'

Nhưng nếu bạn chạy trên google dev tool trên trình duyệt. Lúc này biến khai báo và từ khóa this nằm cùng 1 context nên kết quả sẽ trả về đúng a === 'Global'

Bạn có thể log trên console của window để xem các biến Javascript engine xử lý như thế nào.

Quay trở lại console của linux. Bắt đầu thử xem các biến được nodejs sắp xếp như thế nào

Khi nhấn enter và bạn tìm xuống cuối object được log ra màn hình. Bạn vấn thấy kết quả ra đúng Global và các biến được khai báo nằm trong context này.

Nhưng khi bạn viết trong file. và chạy bằng lệnh node tenfile.js Kết quả sẽ ra như thế này:

Là do ở browser thì scope to nhất là global. Nhưng trong nodejs, khi bạn sử dụng file hay module thì các biến, hàm khai báo chỉ nằm trong module đó. sử dụng context của module đó. Các biến này thì private trong module.
Cơ chế của nodejs khá phức tạp. bạn có thể đọc document của nodejs để tìm hiểu thêm. Nếu bạn muốn đưa các biến khai báo ra scope to nhất. bạn có thể sử dụng luôn biến đó mà không cần khai báo bằng từ khóa var

a = 'Global'; // Not recommend!!!

var obj = { a: 'Custom' };

function whatsThis(arg) {
  console.info(this);
  return this.a; 
}

whatsThis();

Khi đó kết quả sẽ là :

Còn khi bạn chạy hàm whatsThis() nhưng được call bởi 1 Object khác. Thì biến this trong function sẽ trỏ đến object này.

  ...
  var a = 'Global';
  var obj = { a: 'Custom' };

  function whatsThis(arg) {
    // Khi hàm này được call bởi 1 object khác.
    // Lúc này this trong context của function này sẽ trỏ đến obj đó.
    console.log(this); // -> { a: 'Custom' }
    return this.a; // === 'Custom'
  } 

  whatsThis.call(obj);
  ...

Nói chung là biến this trong javascript khá phức tạp. Bạn nên làm quen dần. =))) Đúng là phải mất mấy năm mới hiểu được phần nào của JS.

welcome to Js world! =)))

4 Likes

Bạn làm mình nhớ tới là Node sử dụng CommonJS để phân chia module. Học lâu chưa xem lại. :smile:

3 Likes

Hay quá :slight_smile: cảm ơn anh @hibariwl

1 Like

@hungaya cho em hỏi cần đọc quyền sách JS nào để có những kiến thức cơ bản như này vậy?

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?