Câu hỏi Làm cách nào để kiểm tra xem đối tượng có thuộc tính trong JavaScript không?


Làm cách nào để kiểm tra xem đối tượng có thuộc tính trong JavaScript không?

Xem xét:

x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
    //Do this
}

Đó có phải là cách tốt nhất để làm điều đó không?


1183
2017-09-25 19:27


gốc


Tôi đã viết một bài kiểm tra jsperf với câu trả lời của mọi người để xem câu trả lời nhanh nhất: jsperf.com/dictionary-contains-key - styfle
@styfle Cảm ơn rất nhiều, kiểm tra jsperf giúp tôi rất nhiều! - Luillyfe


Các câu trả lời:


Tôi thực sự bối rối bởi những câu trả lời đã được đưa ra - hầu hết trong số họ là hoàn toàn không chính xác. Tất nhiên bạn có thể có các thuộc tính đối tượng có giá trị không xác định, null hoặc false. Vì vậy, chỉ cần giảm kiểm tra thuộc tính để typeof this[property] hoặc, thậm chí tệ hơn, x.key sẽ cho bạn kết quả hoàn toàn sai lệch.

Nó phụ thuộc vào những gì bạn đang tìm kiếm. Nếu bạn muốn biết nếu một đối tượng vật lý có chứa một thuộc tính (và nó không phải là đến từ một nơi nào đó trên chuỗi nguyên mẫu) thì object.hasOwnProperty là con đường để đi. Tất cả các trình duyệt hiện đại đều hỗ trợ nó. (Nó bị thiếu trong các phiên bản cũ hơn của Safari - 2.0.1 trở lên - nhưng các phiên bản của trình duyệt này hiếm khi được sử dụng nữa.)

Nếu những gì bạn đang tìm kiếm là nếu một đối tượng có một thuộc tính trên nó có thể lặp lại (khi bạn lặp qua các thuộc tính của đối tượng, nó sẽ xuất hiện), sau đó thực hiện: prop in object sẽ cho bạn hiệu quả mong muốn.

Kể từ khi sử dụng hasOwnProperty có lẽ là những gì bạn muốn, và xem xét rằng bạn có thể muốn có một phương pháp dự phòng, tôi trình bày cho bạn giải pháp sau đây:

var obj = {
    a: undefined,
    b: null,
    c: false
};

// a, b, c all found
for ( var prop in obj ) {
    document.writeln( "Object1: " + prop );
}

function Class(){
    this.a = undefined;
    this.b = null;
    this.c = false;
}

Class.prototype = {
    a: undefined,
    b: true,
    c: true,
    d: true,
    e: true
};

var obj2 = new Class();

// a, b, c, d, e found
for ( var prop in obj2 ) {
    document.writeln( "Object2: " + prop );
}

function hasOwnProperty(obj, prop) {
    var proto = obj.__proto__ || obj.constructor.prototype;
    return (prop in obj) &&
        (!(prop in proto) || proto[prop] !== obj[prop]);
}

if ( Object.prototype.hasOwnProperty ) {
    var hasOwnProperty = function(obj, prop) {
        return obj.hasOwnProperty(prop);
    }
}

// a, b, c found in modern browsers
// b, c found in Safari 2.0.1 and older
for ( var prop in obj2 ) {
    if ( hasOwnProperty(obj2, prop) ) {
        document.writeln( "Object2 w/ hasOwn: " + prop );
    }
}

Trên đây là một giải pháp làm việc, qua trình duyệt, hasOwnProperty, với một caveat: Nó không thể phân biệt giữa các trường hợp mà một tài sản giống hệt nhau trên nguyên mẫu và trên dụ - nó chỉ giả định rằng nó đến từ nguyên mẫu. Bạn có thể thay đổi nó để được khoan dung hơn hoặc nghiêm ngặt, dựa trên tình hình của bạn, nhưng ít nhất điều này sẽ hữu ích hơn.


1203
2017-09-25 21:52



@grantwparks Nếu bạn đang xây dựng một plugin trượt đơn giản và muốn kiểm tra sự tồn tại của một mục tùy chọn, thì điều này có thể thực sự cần thiết hơn. Bạn chỉ có thể làm một cái gì đó như var w = opts.w || 100;. Nhưng nếu bạn đang vào một loại thư viện của một cái gì đó, bạn có thể cần phải đi xa hơn một chút ở một số bộ phận. - Halil Özgür
@ kralco626: Vâng, ngày nay tôi cảm thấy khá an toàn khi sử dụng hasOwnProperty () - nhưng đối với giải pháp trình duyệt chéo thực sự an toàn, hãy đi với John's. - Jacob
Thế còn tạm thờithay đổi __proto__ để null? Impl đơn giản: function hasOwnProperty(obj, prop) { var temp = obj.__proto__; obj.__proto__ = null; var ret = prop in obj; obj.__proto__ = temp; return ret; } (Trường hợp với obj.constructor.prototype nên được thêm vào). - Kasztan
@Kasztan __proto__ không chuẩn và không hoạt động trong một số trình duyệt cũ hơn. Và ngay cả với việc bổ sung gần đây Object.getPrototypeOf tiêu chuẩn nói rằng bạn vẫn không thể thay đổi nguyên mẫu của một đối tượng hiện có. - Matt Browne
A for(prop in object) vòng lặp chỉ lặp lại các thuộc tính đếm được. Tuy nhiên, prop in object kiểm tra xem object có tài sản prop ở đâu đó trong chuỗi nguyên mẫu, độc lập về việc nó có đếm được hay không. - Oriol


Với Underscore.js hoặc là (thậm chí còn tốt hơn) lodash:

_.has(x, 'key');

Cuộc gọi nào Object.prototype.hasOwnPropertynhưng (a) ngắn hơn, và (b) sử dụng "một tham chiếu an toàn để hasOwnProperty"(tức là nó hoạt động ngay cả khi hasOwnProperty được ghi đè).

Đặc biệt, lodash định nghĩa _.has như:

   function has(object, key) {
      return object ? hasOwnProperty.call(object, key) : false;
   }
   // hasOwnProperty = Object.prototype.hasOwnProperty

235
2017-07-03 17:01



Tôi đoán đó là bởi vì "thêm thư viện này" hiếm khi là một giải pháp phổ biến ngay cả khi câu hỏi là về thao tác DOM phức tạp và câu trả lời là "đi sử dụng jQuery". - Winfield Trail
Tôi thấy quan điểm của bạn, cảm ơn, cảm ơn. Ngẫu nhiên, nếu một người không thích bao gồm toàn bộ thư viện lodash thì người ta có thể biên dịch thành phần con hoặc npm install lodash.has hiển thị mô-đun npm chỉ với một has chức năng biên dịch xuống 175 byte khi được rút gọn. Nó cũng là sâu sắc để nhìn vào lodash.has/index.js để xem cách một thư viện rất phổ biến và đáng tin cậy hoạt động. - Brian M. Hunt
và lodashCác phiên bản làm việc với điều này: .has(undefined, 'someKey') => false trong khi underscore trả về undefined - Brad Parks
Để mọi người rên rỉ về việc thêm lodash là phụ thuộc "khác": đó là thư viện khá phổ biến (nếu không phải là phổ biến nhất) cho loại điều này. Vui chơi sáng tạo lại bánh xe. - Priidu Neemre
Ngay cả khi bạn muốn phát minh lại bánh xe, hãy kiểm tra các bánh xe hiện có không phải là một ý tưởng tồi. - wolfdawn


chú thích: những điều sau đây phần lớn là lỗi thời nhờ vào chế độ nghiêm ngặt và hasOwnProperty. Giải pháp đúng là sử dụng chế độ nghiêm ngặt và để kiểm tra sự hiện diện của một thuộc tính bằng cách sử dụng obj.hasOwnProperty. Câu trả lời này tiền thân cả hai điều này, ít nhất là được thực hiện rộng rãi (có, nó là cũ). Lấy phần sau đây làm ghi chú lịch sử.


Ghi nhớ rằng undefined là (không may) không phải một từ dành riêng trong JavaScript nếu bạn không sử dụng chế độ nghiêm ngặt. Do đó, ai đó (một người nào đó, rõ ràng) có thể có ý tưởng lớn về việc xác định lại nó, phá vỡ mã của bạn.

Do đó, một phương pháp mạnh mẽ hơn như sau:

if (typeof(x.attribute) !== 'undefined')

Mặt khác, phương pháp này có nhiều chi tiết hơn và cũng chậm hơn. : - /

Một giải pháp thay thế phổ biến là đảm bảo rằng undefined Là thực ra không xác định, ví dụ: bằng cách đặt mã vào một hàm chấp nhận tham số bổ sung, được gọi là undefined, đó không phải là giá trị. Để đảm bảo rằng nó không được chuyển một giá trị, bạn chỉ có thể gọi nó ngay lập tức, ví dụ:

(function (undefined) {
    … your code …
    if (x.attribute !== undefined)
        … mode code …
})();

108
2017-09-25 19:48



Chỉ tò mò thôi, vì void 0 được định nghĩa để trả về kinh điển undefined, có thể làm được không x.attribute !== void 0? - Brian M. Hunt
Brian: Tôi không phải là chuyên gia, nhưng chắc chắn đó có vẻ là một cách thông minh để làm đúng. - Christopher Smith
Nếu 'người khác' nổi tiếng đã định nghĩa lại những gì không xác định là, tôi nghĩ rằng hành động tốt nhất sẽ là viết lại mã THAT. - Oskar Holmkratz
undefined = (function () {}()); if (a.attribute !== undefined) 'foo'; - Joe Simmons
Tốt nhất để có một var không xác định chắc chắn, là để làm việc trong một đóng cửa, và có một chữ ký hàm chưa từng có: (function (undefined) { // undefined is actually undefined here })(); - bgusach


Thế còn?

var x = {'key': 1};

if ('key' in x) {
    console.log('has');
}

93
2018-02-02 17:56



Chỉ cần lưu ý, nó hoạt động với 'các đối tượng' theo nghĩa hẹp, vì vậy được khai báo là {} hoặc được tạo ra bằng cách sử dụng hàm tạo, nó không chấp nhận các mảng hoặc nguyên thủy. Không phải là OP đã yêu cầu nó, nhưng một số câu trả lời khác trình bày các kỹ thuật rộng hơn (làm việc với mảng, dây, vv) - Danubian Sailor
@ РСТȢѸФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ cảm ơn vì đã chỉ ra rằng (câu trả lời được chấp nhận không đi vào chi tiết về lý do tại sao người ta nên sử dụng in nhà điều hành hay không. Cũng lưu ý rằng in toán tử có hỗ trợ trình duyệt tuyệt vời IE 5.5+, Chrome 1.0+, Firefox 1.0+, Safari 3.0+  stackoverflow.com/questions/2920765/… - Adrien Be
Nhà điều hành in cũng kiểm tra các thuộc tính nguyên mẫu, trong khi hasOwnProperty chỉ lặp lại thuộc tính do người dùng xác định. Tài liệu tham khảo: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - adi518
'key' in x  làm làm việc với mảng. Bằng chứng: stackoverflow.com/questions/33592385/… - CosmoMyzrailGorynych


if (x.key !== undefined)

Armin Ronacher dường như đã đánh tôi, nhưng:

Object.prototype.hasOwnProperty = function(property) {
    return this[property] !== undefined;
};

x = {'key': 1};

if (x.hasOwnProperty('key')) {
    alert('have key!');
}

if (!x.hasOwnProperty('bar')) {
    alert('no bar!');
}

Một giải pháp an toàn hơn, nhưng chậm hơn, Như đã chỉ ra bởi Konrad Rudolph và Armin Ronacher sẽ là:

Object.prototype.hasOwnProperty = function(property) {
    return typeof this[property] !== 'undefined';
};

35
2017-09-25 19:32



Tôi không nghĩ thế là đủ rồi. x.hasOwnProperty('toString') === true; - Joe Simmons
Không yêu cầu không đồng ý, nhưng để hiểu. Có bất kỳ điểm nào mà x.hasOwnProperty sẽ trả về bất cứ điều gì ngoài một boolean đúng hay sai? Nếu không, mã như được đăng sẽ hoạt động mọi lúc. Tôi cho rằng có lẽ nếu phương pháp bị ghi đè, nhưng sau đó, dựa vào kết quả sẽ không bao giờ đáng tin cậy trừ khi bạn biết phương pháp ghi đè. - enobrev
Tôi nghĩ chúng ta có thông tin sai lạc. Tôi có nghĩa là sử dụng phương pháp của bạn, nó sẽ nói rằng 'toString' là tài sản riêng của nó, nhưng nó không phải là. - Joe Simmons
Object.prototype đã tích hợp sẵn, chính xác hasOwnProperty. Ghi đè nó bằng cách triển khai không chính xác (1. Thuộc tính có thể có giá trị undefined, 2. Điều này sẽ cho kết quả dương tính giả cho các thuộc tính kế thừa) chỉ là một ý tưởng xấu xa. Câu trả lời không chính xác có thể và sẽ bị xóa. Tôi không biết nếu bạn có thể làm điều đó trở lại trong tháng chín '08 khi bạn nhìn thấy câu trả lời của Resig, vì vậy hãy bình luận để đề xuất làm ngay bây giờ. - T.J. Crowder


Bạn có thể dùng in toán tử để kiểm tra xem thuộc tính có tồn tại trên một đối tượng hay không:

x = {'key': 1};
alert("key" in x);

Bạn cũng có thể lặp qua tất cả các thuộc tính của đối tượng bằng cách sử dụng for - in lặp lại và sau đó kiểm tra thuộc tính cụ thể:

for (prop in x) {
    if (prop == "key") {
        //Do something
    }
}

Bạn phải xem xét nếu thuộc tính đối tượng này có thể đếm được hay không, vì các thuộc tính không liệt kê sẽ không hiển thị trong một for-in vòng lặp. Ngoài ra, nếu thuộc tính enumerable là shadowing một thuộc tính không thể đếm được của nguyên mẫu, nó sẽ không hiển thị trong Internet Explorer 8 và sớm hơn.

Nếu bạn muốn danh sách tất cả các thuộc tính mẫu, cho dù có đếm được hay không, bạn có thể sử dụng

Object.getOwnPropertyNames(x);

Điều này sẽ trả về một mảng tên của tất cả các thuộc tính tồn tại trên một đối tượng.

Cuối cùng, bạn có thể sử dụng toán tử typeof để trực tiếp kiểm tra kiểu dữ liệu của thuộc tính đối tượng:

if (typeof x.key == "undefined") {
    alert("undefined");
}

Nếu thuộc tính không tồn tại trên đối tượng, nó sẽ trả về chuỗi không xác định. Khác nó sẽ trả về kiểu thuộc tính thích hợp. Tuy nhiên, lưu ý rằng đây không phải là cách kiểm tra hợp lệ nếu đối tượng có thuộc tính hay không, vì bạn có thể có thuộc tính được đặt thành không xác định, trong trường hợp này, sử dụng typeof x.key vẫn sẽ trả về true (mặc dù khóa vẫn nằm trong đối tượng).

Cập nhật: Bạn có thể kiểm tra xem thuộc tính có tồn tại hay không bằng cách so sánh với thuộc tính javascript không xác định

if (x.key === undefined) {
    alert("undefined");
}

Điều này sẽ hoạt động trừ khi khóa được đặt cụ thể thành undefined trên đối tượng x


30
2018-03-30 06:18



Phần cập nhật của bạn sai. Xin hãy xem ở đây: jsfiddle.net/sbgg04yg - Breaking Benjamin
Đã cập nhật để hiển thị các tình huống khi so sánh với thuộc tính không xác định JavaScript có thể không thành công - goonerify


Hãy cắt qua một số rắc rối ở đây. Trước tiên, hãy đơn giản hóa bằng cách giả sử hasOwnProperty đã tồn tại; điều này đúng với phần lớn các trình duyệt hiện tại đang được sử dụng.

hasOwnProperty trả về true nếu tên thuộc tính được truyền cho nó đã được thêm vào đối tượng. Nó hoàn toàn độc lập với giá trị thực tế được gán cho nó có thể chính xác undefined.

Vì thế:

var o = {}
o.x = undefined

var a = o.hasOwnProperty('x')  // a is true
var b = o.x === undefined // b is also true

Tuy nhiên:

var o = {}

var a = o.hasOwnProperty('x')  // a is now false
var b = o.x === undefined // b is still true

Vấn đề là những gì sẽ xảy ra khi một đối tượng trong chuỗi nguyên mẫu có một thuộc tính với giá trị của undefined? hasOwnProperty sẽ là sai cho nó, và như vậy sẽ !== undefined. Chưa, for..in vẫn sẽ liệt kê nó trong liệt kê.

Điểm mấu chốt là không có cách trình duyệt chéo (vì Internet Explorer không lộ ra __prototype__) để xác định rằng một định danh cụ thể chưa được gắn vào một đối tượng hoặc bất kỳ thứ gì trong chuỗi nguyên mẫu của nó.


24
2017-09-26 09:16