Tại sao sử dụng Object.prototype.hasOwnProperty.call (myObj, prop) thay vì myObj.hasOwnProperty (prop)?


104

Nếu tôi hiểu chính xác, mỗi và mọi đối tượng trong Javascript kế thừa từ nguyên mẫu Đối tượng, có nghĩa là mỗi và mọi đối tượng trong Javascript đều có quyền truy cập vào hàm hasOwnProperty thông qua chuỗi nguyên mẫu của nó.

Trong khi đọc mã nguồn của request.js, tôi tình cờ gặp hàm này:

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwnlà một tham chiếu đến Object.prototype.hasOwnProperty. Có sự khác biệt thực tế nào khi viết hàm này dưới dạng

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

Và vì chúng ta đang ở đó, tại sao chúng ta lại xác định chức năng này? Đó chỉ là câu hỏi về các phím tắt và bộ nhớ đệm cục bộ của quyền truy cập thuộc tính để tăng hiệu suất (nhẹ) hay tôi bỏ lỡ bất kỳ trường hợp nào mà hasOwnProperty có thể được sử dụng trên các đối tượng không có phương thức này?

Câu trả lời:


109

Có bất kỳ sự khác biệt thực tế nào [giữa các ví dụ của tôi] không?

Người dùng có thể có một đối tượng JavaScript được tạo bằng Object.create(null), đối tượng này sẽ có một null [[Prototype]]chuỗi và do đó sẽ không có hasOwnProperty()sẵn trên đó. Sử dụng biểu mẫu thứ hai của bạn sẽ không hoạt động vì lý do này.

Nó cũng là một tham chiếu an toàn hơn cho Object.prototype.hasOwnProperty()(và cũng ngắn hơn).

Bạn có thể tưởng tượng ai đó có thể đã làm ...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

Điều sẽ gây ra hasProp(someObject)lỗi nếu nó được triển khai như ví dụ thứ hai của bạn (nó sẽ tìm thấy phương thức đó trực tiếp trên đối tượng và gọi phương thức đó, thay vì được ủy quyền Object.prototype.hasOwnProperty).

Nhưng ít có khả năng ai đó sẽ ghi đè Object.prototype.hasOwnPropertytham chiếu.

Và vì chúng ta đang ở đó, tại sao chúng ta lại xác định chức năng này?

Xem ở trên.

Nó chỉ là một câu hỏi về các phím tắt và bộ nhớ đệm cục bộ của quyền truy cập thuộc tính để tăng hiệu suất (nhẹ) ...

Về lý thuyết, nó có thể làm cho nó nhanh hơn[[Prototype]]chuỗi không phải được tuân theo, nhưng tôi nghi ngờ điều này là không đáng kể và không phải lý do thực hiện là tại sao.

... hoặc tôi thiếu bất kỳ trường hợp nào hasOwnPropertycó thể được sử dụng trên các đối tượng không có phương thức này?

hasOwnProperty()tồn tại trên Object.prototype, nhưng có thể bị ghi đè. Mọi đối tượng JavaScript gốc (nhưng các đối tượng máy chủ không được đảm bảo tuân theo điều này, hãy xem phần giải thích chuyên sâu của RobG ) đều có Object.prototypeđối tượng cuối cùng trên chuỗi trước đó null(tất nhiên là ngoại trừ đối tượng được trả về Object.create(null)).


Logic của bạn có thể đúng, nhưng tôi nghĩ bạn đang tử tế. Nếu các tác giả của request.js nghĩ rằng hasOwnProperty có thể đã bị ghi đè (điều này cực kỳ khó xảy ra), thì họ nên gọi tất cả các phương thức tích hợp theo cách đó (có lẽ họ làm vậy).
RobG

@Periback Thật không? Tôi khá chắc chắn rằng nó đã hỗ trợ nó.
alex

Phím tắt ES6 nếu thường xuyên sử dụng. const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
Richard Ayotte

15

Nếu tôi hiểu đúng, mỗi và mọi đối tượng trong Javascript đều kế thừa từ nguyên mẫu Đối tượng

Nó có vẻ giống như những sợi tóc chẻ đôi, nhưng có sự khác biệt giữa javascript (thuật ngữ chung cho các triển khai ECMAScript) và ECMAScript (ngôn ngữ được sử dụng để triển khai javascript). Đó là ECMAScript định nghĩa một lược đồ kế thừa, không phải javascript, vì vậy chỉ các đối tượng ECMAScript gốc mới cần triển khai lược đồ kế thừa đó.

Một chương trình javascript đang chạy bao gồm ít nhất các đối tượng ECMAScript được tích hợp sẵn (Đối tượng, Hàm, Số, v.v.) và có thể là một số đối tượng gốc (ví dụ: các hàm). Nó cũng có thể có một số đối tượng máy chủ lưu trữ (chẳng hạn như đối tượng DOM trong trình duyệt hoặc các đối tượng khác trong môi trường máy chủ lưu trữ khác).

Trong khi các đối tượng tích hợp sẵn và các đối tượng gốc phải triển khai sơ đồ kế thừa được định nghĩa trong ECMA-262, các đối tượng máy chủ lưu trữ thì không. Do đó, không phải tất cả các đối tượng trong môi trường javascript đều phải kế thừa từ Object.prototype . Ví dụ, các đối tượng máy chủ lưu trữ trong IE được triển khai dưới dạng đối tượng ActiveX sẽ phát sinh lỗi nếu được coi là đối tượng gốc (do đó tại sao try..catch được sử dụng để khởi tạo đối tượng MS XMLHttpRequest). Một số đối tượng DOM (như NodeLists trong IE ở chế độ quirks) nếu được chuyển đến các phương thức Array sẽ gây ra lỗi, các đối tượng DOM trong IE 8 trở xuống không có lược đồ kế thừa giống như ECMAScript, v.v.

Do đó, không nên cho rằng tất cả các đối tượng trong môi trường javascript đều kế thừa từ Object.prototype.

có nghĩa là mỗi đối tượng trong Javascript đều có quyền truy cập vào hàm hasOwnProperty thông qua chuỗi nguyên mẫu của nó

Điều này không đúng với một số đối tượng máy chủ nhất định trong IE ở chế độ quirks (và IE 8 trở xuống luôn luôn).

Với những điều trên, thật đáng cân nhắc tại sao một đối tượng có thể có phương thức hasOwnProperty của riêng nó và khả năng tư vấn của việc gọi một số phương thức hasOwnProperty khác mà không cần thử nghiệm trước xem đó có phải là một ý tưởng tốt hay không.

Biên tập

Tôi nghi ngờ rằng lý do sử dụng Object.prototype.hasOwnProperty.calllà trong một số trình duyệt, các đối tượng máy chủ lưu trữ không có phương thức hasOwnProperty , sử dụng lệnh gọi và phương thức tích hợp là một phương thức thay thế. Tuy nhiên, làm như vậy chung chung không phải là một ý tưởng hay vì những lý do đã nêu ở trên.

Khi có liên quan đến các đối tượng chủ, toán tử in có thể được sử dụng để kiểm tra các thuộc tính nói chung, ví dụ

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in IE 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

Một giải pháp thay thế (được thử nghiệm trong IE6 và các phiên bản khác):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

Bằng cách đó, bạn chỉ gọi cụ thể hasOwnProperty tích hợp trong đó đối tượng không có nó (kế thừa hoặc cách khác).

Tuy nhiên, nếu một đối tượng không có hasOwnPropertyphương thức, nó có thể phù hợp để sử dụng toán tử in vì đối tượng có thể không có lược đồ kế thừa và tất cả các thuộc tính đều nằm trên đối tượng (đó chỉ là giả định), ví dụ: trong toán tử là một cách phổ biến (và dường như thành công) để kiểm tra hỗ trợ đối tượng DOM cho các thuộc tính.


Cảm ơn. Object.prototype.hasOwnProperty.call (o, 'bar') không hoạt động trong FF 18.0 (ít nhất là trong trường hợp của tôi). Vì vậy, tôi quyết định sử dụng ('bar' trong o) - và nó đã hữu ích.
Tối đa

@Max inkhông thực hiện hasOwnProperty()tra cứu, tôi nghi ngờ thuộc tính bạn đang tìm đã tồn tại trên chuỗi nguyên mẫu.
alex

Đây là một ví dụ thú vị từ eslint.org/docs/rules/no-prototype-builtins : Ví dụ: máy chủ web sẽ không an toàn khi phân tích dữ liệu đầu vào JSON từ máy khách và gọi hasOwnPropertytrực tiếp đối tượng kết quả, vì máy khách độc hại có thể gửi một giá trị JSON giống như {"hasOwnProperty": 1}và khiến máy chủ gặp sự cố.
naught101 ngày

Chắc chắn rồi, nhưng sẽ là khôn ngoan nếu bạn kiểm tra hoặc xác thực bất kỳ JSON nào do máy khách cung cấp bằng lược đồ JSON để ngăn chặn các vấn đề như vậy, ngay cả khi mối quan tâm của bạn chỉ là chất lượng dữ liệu. Và nó sẽ không gây ra sự cố cho máy chủ. :-)
RobG ngày

8

JavaScript không bảo vệ tên thuộc tính hasOwnProperty

Nếu có khả năng một đối tượng có thể có thuộc tính với tên này, thì cần phải sử dụng hasOwnProperty bên ngoài để nhận được kết quả chính xác:

Bạn có thể sao chép, dán các đoạn mã dưới đây vào bảng điều khiển trình duyệt của mình để hiểu rõ hơn

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

Luôn trả về false

foo.hasOwnProperty('bar'); // false

Sử dụng hasOwnProperty của đối tượng khác và gọi nó với bộ này thành foo

({}).hasOwnProperty.call(foo, 'bar'); // true

Cũng có thể sử dụng thuộc tính hasOwnProperty từ nguyên mẫu Đối tượng cho mục đích này

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

1
Điểm bạn đang thực hiện đã được thực hiện trong câu trả lời được chấp nhận , ngoại trừ việc ghi đè hasOwnPropertylợi nhuận true.
Louis

1

Thông tin được đưa ra trong cả hai câu trả lời hiện có đều được hiển thị tại chỗ. Tuy nhiên, việc sử dụng:

('propertyName' in obj)

được đề cập một vài lần. Cần lưu ý rằng các hasOwnPropertytriển khai sẽ chỉ trả về true nếu thuộc tính được chứa trực tiếp trên đối tượng đang được kiểm tra.

Nhà inđiều hành cũng sẽ kiểm tra thông qua chuỗi nguyên mẫu.

Điều này có nghĩa là các thuộc tính cá thể sẽ trả về true khi được chuyển đến hasOwnPropertynơi mà các thuộc tính nguyên mẫu sẽ trả về false.

Sử dụng intoán tử cả thuộc tính instance và prototype sẽ trả về true.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.