教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本文對應 jstips 倉庫第 10 期技巧繁體中文版_posts/zh_TW/javascript/2016-01-10-check-if-a-property-is-in-a-object.md另有英文原版、簡體中文版與西班牙語版。本篇將從最常見的直覺寫法出發完整對比 JavaScript 中檢查物件屬性是否存在的兩大原生手段——in運算子與Object.prototype.hasOwnProperty剖析兩者在「自身屬性」與「原型鏈繼承屬性」上的核心差異並結合本倉庫其他技巧如無原型物件、屬性挑選等說明何時該用哪一種幫你寫出正確、高效且無隱患的屬性存在性判斷。一、最常見的寫法if (myObject.name)及其陷阱檢查某個屬性是否存在於物件中許多開發者的第一反應是直接讀取值並判斷真偽var myObject { name: tips_js }; if (myObject.name) { ... }這段寫法「能用」但它其實隱藏著一個關鍵缺陷它判斷的是屬性的「真值truthy」狀態而不是屬性的「存在與否」。JavaScript 中所有 falsy 值——0、空字串、false、null、undefined、NaN——都會讓這個條件判斷失敗即使屬性本身確實存在var config { retries: 0, // 屬性存在但值為 falsy label: , // 屬性存在但值為 falsy enabled: false // 屬性存在但值為 falsy }; if (config.retries) { /* 不會執行即使 retries 已定義且等於 0 */ } if (config.label) { /* 不會執行即使 label 已定義為空字串 */ }換言之只要屬性的值恰好落在 falsy 集合裡if (obj.prop)就會誤判為「屬性不存在」。若要精確回答「這個 key 到底存不存在」JavaScript 提供了兩個原生方法in運算子與Object.hasOwnProperty。任何繼承自Object的物件都可以使用這兩種方式——這是本技巧tip 10的核心內容也與倉庫中第 5 期「undefined與null的差異」所討論的 falsy/truthy 語義一脈相承。二、兩種原生方法in運算子與hasOwnProperty2.1in運算子in是 JavaScript 的內建運算子語法為propertyName in object。它會沿著物件的整個原型鏈向上查找只要在自身屬性或任何一層繼承屬性中找到該 key就回傳truevar myObject { name: tips_js }; name in myObject; // true自身屬性 valueOf in myObject; // true繼承自原型鏈注意in運算子的左側必須是字串形式的屬性名稱或會被轉換為字串的表達式且當右側不是物件時會拋出TypeError。2.2Object.prototype.hasOwnPropertyhasOwnProperty是定義在Object.prototype上的方法任何普通物件都能直接呼叫。它只檢查自身屬性不往上追溯原型鏈var myObject { name: tips_js }; myObject.hasOwnProperty(name); // true myObject.hasOwnProperty(valueOf); // falsevalueOf 繼承自原型鏈2.3 兩者的本質差異原文用一段對比清晰地呈現了兩者的差別var myObject { name: tips_js }; myObject.hasOwnProperty(name); // true name in myObject; // true myObject.hasOwnProperty(valueOf); // false, valueOf 繼承自原型鏈結 valueOf in myObject; // true兩者不同的地方在於確認屬性的深度不同。換句話說如果 key 直接存在於物件本身hasOwnProperty才會回傳true而in運算子無法分辨屬性是建立在物件上還是繼承自原型鏈——只要是沿著原型鏈可達的屬性in一律回答「存在」。這個差異在實務上非常關鍵任何普通物件都繼承了Object.prototype上的方法例如constructor、toString、valueOf、hasOwnProperty、isPrototypeOf等。因此toString in {}→true繼承而來{}.hasOwnProperty(toString)→false並非自身屬性三、原型鏈情境下的對比構造函數範例原文給出了第二組更貼近真實開發的範例透過構造函數與prototype展示繼承屬性的行為var myFunc function() { this.name tips_js; // 建立「自身屬性」 }; myFunc.prototype.age 10 days; // 在原型上建立「繼承屬性」 var user new myFunc(); user.hasOwnProperty(name); // true user.hasOwnProperty(age); // false, 因為 age 繼承自原型鏈結這段程式碼說明了三件事在構造函數內用this.name ...賦值的屬性會成為每個實例的自身屬性因此user.hasOwnProperty(name)為true掛在myFunc.prototype上的age會被所有實例透過原型鏈「看到」但它不是實例的自身屬性所以user.hasOwnProperty(age)為false若改用in運算子age in user則會回傳true——因為in會沿著user → myFunc.prototype → Object.prototype這條鏈逐一查找。由此可以歸納出選擇原則判斷目標推薦方式行為只關心「自身屬性」是否存在例如資料校驗、白名單過濾Object.prototype.hasOwnProperty不追溯原型鏈關心「可讀取到該屬性」含繼承屬性例如特性偵測in運算子沿原型鏈完整查找四、現代進化Object.hasOwn與無原型物件4.1Object.hasOwnES2022hasOwnProperty有一個已知弱點如果物件本身被賦予了名為hasOwnProperty的屬性例如var o { hasOwnProperty: null }直接呼叫o.hasOwnProperty(...)就會失敗或行為異常。ES2022 提供了更穩健的靜態方法Object.hasOwn(obj, prop)它不依賴物件自身的同名屬性是取代hasOwnProperty的推薦寫法Object.hasOwn({ name: tips_js }, name); // true Object.hasOwn({ name: tips_js }, valueOf); // false4.2Object.create(null)完全繞過原型鏈當你需要一個「純資料容器」、不想被任何繼承屬性干擾時可以建立無原型物件。本倉庫第 73 期「無副作用雜湊表Hash maps without side effects」正是這個主題的代表透過Object.create(null)我們明確指定null作為其原型。因此它完全沒有任何屬性——連constructor、toString、hasOwnProperty等都沒有——你可以放心地在資料結構中使用這些 key 當作鍵名。該文同時展示了在遍歷雜湊表時使用hasOwnProperty來排除繼承屬性的典型寫法if (dirtyMap.hasOwnProperty(key)) { // 檢查以避開繼承屬性 // 僅處理自身屬性 }這與本期技巧正好互為表裡當你面對普通物件帶有Object.prototype繼承鏈時必須用hasOwnProperty/Object.hasOwn或in來明確控制檢查深度而Object.create(null)則從根源上消除繼承屬性的干擾。五、倉庫中的實際應用佐證jstips 倉庫內多篇技巧都在真實使用這兩種檢查方式可作為最佳實踐的參考第 70 期「挑選與排除物件屬性」其pick函式用k in obj判斷 key 是否存在於目標物件再決定是否取出該屬性function pick(obj, keys) { return keys.map(k k in obj ? {[k]: obj[k]} : {}) .reduce((res, o) Object.assign(res, o), {}); }這裡使用in而非hasOwnProperty是因為pick的語義是「取出該物件含繼承鏈可讀到的屬性」與in的深度行為一致。第 73 期「無副作用雜湊表」如上所述在for...in這類會遍歷繼承屬性的語法中用hasOwnProperty過濾掉非自身屬性是經典的安全寫法。第 39 期「進階屬性Advanced Properties」講解Object.defineProperty定義value、writable、enumerable、configurable等屬性描述元。當屬性被設為enumerable: false時for...in不會列出它但in與hasOwnProperty仍會正確回報其存在——這提醒我們屬性是否「可列舉」與屬性是否「存在」是兩個獨立維度。六、實務選擇建議與常見錯誤總結綜合原文與倉庫內相關技巧給出以下決策指引判斷「是否存在」而非「是否 truthy」當屬性值可能為0、、false、null、undefined、NaN時if (obj.prop)必然誤判。此時改用in或hasOwnProperty。只要自身屬性如表單欄位校驗、資料欄位白名單、for...in過濾優先使用Object.hasOwn(obj, prop)現代環境或obj.hasOwnProperty(prop)相容舊環境。需要沿原型鏈查找如特性偵測、判斷某方法是否「可被呼叫」使用in運算子。避免呼叫被覆寫的hasOwnProperty若物件可能帶有同名自訂屬性改用Object.hasOwn或Object.prototype.hasOwnProperty.call(obj, key)。純資料容器需要徹底不受繼承屬性干擾時使用Object.create(null)建立無原型物件參見第 73 期。常見錯誤的根源在於把「屬性值為 falsy」誤當成「屬性不存在」以及把「屬性可沿原型鏈讀取」誤當成「屬性為自身所有」。釐清in與hasOwnProperty的深度差異後這兩類問題都能迎刃而解——這正是本期 jstips 技巧tip 10要傳達的核心價值。七、延伸閱讀第 5 期「undefined與null的差異」falsy 值語義與typeof檢查的完整說明第 73 期「無副作用雜湊表」Object.create(null)與hasOwnProperty的實戰組合第 70 期「挑選與排除物件屬性」in運算子在屬性挑選工具中的應用第 39 期「進階屬性」屬性描述元與可列舉性的深入講解POST_TEMPLATE.mdjstips 文章格式範本可了解本期技巧的標準結構赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐jstips 第 10 期检查对象属性是否存在的正确姿势 —— in 操作符与 hasOwnProperty 深度对比jstips 第 10 期检查对象属性是否存在的正确姿势 —— in 操作符与 hasOwnProperty 深度对比 导读 在 JavaScript 日常开教程jstips 技巧 10 深度解读用 in 与 hasOwnProperty 正确检查 JavaScript 对象属性是否存在jstips 技巧 10 深度解读用 in 与 hasOwnProperty 正确检查 JavaScript 对象属性是否存在 导读 在 JavaScrip教程如何看懂 video-compress-cj 压缩质量调优高、中、低三档背后的码率缩放原理如何看懂 video compress cj 压缩质量调优高、中、低三档背后的码率缩放原理 video compress cj 是一款基于硬件编解码 API教程上一篇Apache JMeter 完全技术指南性能测试、安装运行与源码构建实战下一篇WebMCP 实战案例拆解电商导购、创意设计与代码评审中 AI Agent 的 3 大应用场景创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考