js怎么判断属性来自原型还是自身

要判断javascript对象的属性是否为自身属性而非继承自原型链,应使用hasownproperty方法。1. 使用对象的hasownproperty()方法可直接判断属性是否为自身所有,返回true表示是自身属性,false表示来自原型链或不存在;2. 为避免对象自身hasownproperty被覆盖导致异常,应使用object.prototype.hasownproperty.call(obj, ‘prop’)以确保调用原生方法;3. in操作符可用于检查属性是否存在于对象或其原型链上,只要存在即返回true;4. object.keys()返回对象自身所有可枚举的字符串键属性;5. object.getownpropertynames()返回自身所有字符串键属性,包括不可枚举的;6. object.getownpropertysymbols()返回自身所有symbol类型属性;7. object.getownpropertydescriptor()获取自身属性的完整描述符,若属性不存在则返回undefined;8. 原型链上的属性遮蔽不会影响hasownproperty的判断,它始终只关注对象自身是否定义了该属性;9. 修改原型会影响所有继承该原型的对象的属性访问,但不会改变hasownproperty对这些对象的判断结果,因其仍仅检测自身属性。因此,hasownproperty是区分自身与继承属性的可靠标准,结合其他方法可根据不同场景精准控制属性操作,避免遍历或配置时引入原型链上的意外属性,确保代码行为准确无误。

js怎么判断属性来自原型还是自身

要弄清楚一个JavaScript对象的某个属性究竟是它自己的“私有财产”,还是从它爹妈(原型链)那里继承来的,其实有个非常直接且稳妥的办法。核心就是用 hasOwnProperty 方法。

js怎么判断属性来自原型还是自身

解决方案

在我看来,hasOwnProperty就是那个金标准。它会检查对象本身是否拥有某个属性,而不会去原型链上找。这意味着,如果一个属性是从原型链上继承来的,hasOwnProperty就会返回 false。只有当属性是对象直接定义的,它才会返回 true

举个例子:

js怎么判断属性来自原型还是自身

function Person(name) {  this.name = name;}Person.prototype.greet = function() {  console.log(`Hello, I'm ${this.name}`);};const john = new Person('John');john.age = 30; // 自身属性console.log(john.hasOwnProperty('name'));  // true,因为name是john自身定义的console.log(john.hasOwnProperty('age'));   // true,age也是john自身定义的console.log(john.hasOwnProperty('greet')); // false,greet是原型链上的方法console.log(john.hasOwnProperty('toString')); // false,toString也是原型链上的方法console.log(john.hasOwnProperty('occupation')); // false,属性不存在// 有时候,对象可能会覆盖hasOwnProperty方法,这虽然不常见但确实可能发生。// 为了绝对安全,尤其是在处理来自外部的、不可控的对象时,// 最好使用 Object.prototype.hasOwnProperty.call()。// 这样可以确保始终调用的是原生的 hasOwnProperty 方法。const objWithBadHasOwnProperty = {  a: 1,  hasOwnProperty: 'oops, I broke it'};// console.log(objWithBadHasOwnProperty.hasOwnProperty('a')); // 这会报错或行为异常console.log(Object.prototype.hasOwnProperty.call(objWithBadHasOwnProperty, 'a')); // true,安全可靠console.log(Object.prototype.hasOwnProperty.call(john, 'greet')); // false,同样可靠

为什么区分自身属性和原型属性很重要?

这玩意儿为什么重要呢?我个人在工作中遇到过不少次,不分清楚这俩就容易踩坑。最典型的场景就是遍历对象属性的时候。我们经常会用 for...in 循环来遍历一个对象的属性,但 for...in 不仅仅会遍历对象自身的枚举属性,它还会遍历原型链上的可枚举属性。这在很多情况下都不是我们想要的。比如你只想处理对象自己的数据,却意外地操作了原型上的方法,那可就麻烦了。

再举个例子,假设你有一个配置对象,想把它的所有自身属性保存起来。如果你直接用 for...in,然后不加 hasOwnProperty 过滤,你可能就把 toStringvalueOf 这些方法也当成配置项给存进去了,这显然是错的。

js怎么判断属性来自原型还是自身

const myConfig = {  theme: 'dark',  fontSize: 16};// 假设原型链上不小心加了个东西(虽然不推荐这样做)Object.prototype.debugMode = true;const allProps = [];for (const key in myConfig) {  // 如果没有这个判断,debugMode也会被加进来  if (myConfig.hasOwnProperty(key)) {    allProps.push(key);  }}console.log(allProps); // ['theme', 'fontSize'],这才是我们想要的// 如果没有hasOwnProperty,会变成:const allPropsWithoutCheck = [];for (const key in myConfig) {  allPropsWithoutCheck.push(key);}// console.log(allPropsWithoutCheck); // ['theme', 'fontSize', 'debugMode'],这就不对了

所以,区分自身和原型属性,能让你更精准地控制代码行为,避免不必要的副作用。

除了hasOwnProperty,还有哪些方法可以检查属性来源或相关信息?

那除了hasOwnProperty,还有别的招儿吗?当然有,不过它们侧重点不一样,用起来得看具体需求。

一个常见的操作符是 inin 操作符会检查属性是否在对象或其原型链上,它不像 hasOwnProperty 那么严格,只要能找到就返回 true

const car = {  brand: 'Tesla'};Object.setPrototypeOf(car, {  engine: 'electric'}); // 设置原型console.log('brand' in car);  // trueconsole.log('engine' in car); // trueconsole.log(car.hasOwnProperty('brand'));  // trueconsole.log(car.hasOwnProperty('engine')); // false

如果你想获取对象自身的所有属性名(不包括原型链上的),可以用 Object.keys()。它只会返回对象自身可枚举的字符串键。

const obj = { a: 1, b: 2 };Object.defineProperty(obj, 'c', {  value: 3,  enumerable: false // 不可枚举});Object.setPrototypeOf(obj, { d: 4 });console.log(Object.keys(obj)); // ['a', 'b'],不包含c(不可枚举)和d(原型上的)

如果你需要获取对象自身所有属性名,包括不可枚举的,那就要用到 Object.getOwnPropertyNames()。如果还有Symbol类型的属性,就得用 Object.getOwnPropertySymbols()

const myObj = {  prop1: 'value1',  [Symbol('id')]: 123};Object.defineProperty(myObj, 'hiddenProp', {  value: 'secret',  enumerable: false});console.log(Object.getOwnPropertyNames(myObj));   // ['prop1', 'hiddenProp']console.log(Object.getOwnPropertySymbols(myObj)); // [Symbol(id)]

Object.getOwnPropertyDescriptor() 则能返回一个属性的完整描述符,包括它的值、是否可写、可枚举、可配置等信息。这个方法只针对自身属性。

const descObj = { x: 10 };const descriptor = Object.getOwnPropertyDescriptor(descObj, 'x');console.log(descriptor);/*{  value: 10,  writable: true,  enumerable: true,  configurable: true}*/const nonExistentDesc = Object.getOwnPropertyDescriptor(descObj, 'y');console.log(nonExistentDesc); // undefined

这些方法各有侧重,hasOwnProperty 是判断“是否是自己的”,in 是判断“有没有这个”,Object.keys 等是“列出自己的”。根据你的具体场景,选择最合适的工具就好。

原型链操作对属性检查有何影响?

原型链这东西,JavaScript的精髓之一,但它也确实能让属性查找变得有点儿意思。当你在原型链上添加或修改属性时,这会直接影响到属性的查找行为,但对 hasOwnProperty 的判断逻辑,影响其实很小,因为它只关心对象自身。

比如,你有一个对象,它的原型上有一个 methodA。如果你在对象自身也定义了一个 methodA,那么对象自身的 methodA 就会“遮蔽”掉原型上的那个。这就是所谓的“属性遮蔽”(shadowing)。

const proto = {  value: 'from prototype',  sayHello() { console.log('Hello from prototype'); }};const obj = Object.create(proto);obj.ownValue = 'from instance';console.log(obj.value); // 'from prototype'obj.sayHello(); // 'Hello from prototype'// 遮蔽原型属性obj.value = 'from instance, shadowing prototype';obj.sayHello = function() { console.log('Hello from instance'); };console.log(obj.value); // 'from instance, shadowing prototype'obj.sayHello(); // 'Hello from instance'console.log(obj.hasOwnProperty('value'));    // true (因为obj自身现在有了value)console.log(obj.hasOwnProperty('sayHello')); // true (因为obj自身现在有了sayHello)console.log(obj.hasOwnProperty('ownValue')); // true

你会发现,即使原型上的属性被遮蔽了,hasOwnProperty 依然只关心 obj 自身有没有这个属性。它不会去管原型链上有没有一个同名的、被遮蔽的属性。这正是 hasOwnProperty 的强大之处,它提供了一个清晰的边界。

但是,如果你直接修改了原型上的属性,那所有继承自这个原型的实例都会受到影响。

const Animal = {  type: 'mammal'};const dog = Object.create(Animal);const cat = Object.create(Animal);console.log(dog.type); // 'mammal'console.log(cat.type); // 'mammal'// 修改原型上的属性Animal.type = 'vertebrate';console.log(dog.type); // 'vertebrate'console.log(cat.type); // 'vertebrate'console.log(dog.hasOwnProperty('type')); // falseconsole.log(cat.hasOwnProperty('type')); // false

在这种情况下,hasOwnProperty 依然返回 false,因为它知道 type 属性不是 dogcat 自身的。这再次强调了 hasOwnProperty 的设计目标:只关注对象自身。所以,无论原型链怎么变,只要不是在对象自身上直接添加或修改属性,hasOwnProperty 的判断结果就不会改变。这使得它在处理复杂继承关系时,依然是一个非常可靠的工具。

以上就是js怎么判断属性来自原型还是自身的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1512803.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 07:21:16
下一篇 2025年12月20日 07:21:29

相关推荐

  • JavaScript 中日期时间格式化详解

    本文详细介绍了在 JavaScript 中格式化日期时间的方法,重点讲解了如何利用 date-fns 库将 API 返回的日期时间字符串转换为自定义格式,例如将 2023-05-12T09:14:34.742+00:00 转换为 2023-05-15 09:14:34 am。文章提供了详细的代码示例…

    2025年12月20日
    000
  • JavaScript日期时间格式化详解

    本文旨在帮助开发者掌握在JavaScript中格式化日期时间的技巧。通过引入date-fns库,我们可以轻松地将API返回的日期时间字符串转换为更易读的格式,例如”yyyy-MM-dd hh:mm:ss a”。本文提供详细的代码示例,并解释了如何使用format()函数进行自…

    2025年12月20日
    000
  • React Test Renderer:使用 findAll 按类名查找元素

    在 React 组件的单元测试中,我们经常需要根据特定的类名来查找元素,以便进行断言或进一步的操作。React Test Renderer 提供了一种轻量级的方式来渲染 React 组件,并允许我们访问组件的底层结构。虽然它没有直接提供按类名查找元素的方法,但我们可以通过自定义选择器函数来实现这一目…

    2025年12月20日
    000
  • React Test Renderer:使用 findAll 精准查找元素

    React Test Renderer 提供了一种在没有浏览器或 DOM 环境下渲染 React 组件的方式,非常适合编写单元测试。它允许你断言组件的输出,而无需依赖真实的 DOM。findAll 方法是 React Test Renderer 中一个强大的工具,可以用来查找组件树中的所有匹配特定条…

    2025年12月20日
    000
  • Vuex Mutations 正确使用指南:过滤 State 中的数组数据

    本文旨在帮助开发者正确理解和使用 Vuex mutations 来处理 state 中的数组数据,尤其是在需要过滤数据时。我们将探讨为什么直接在 mutation 中修改 state 可能不是最佳实践,并介绍如何使用 getters 来更有效地实现数据过滤。同时,我们也会强调代码规范的重要性,以提升…

    2025年12月20日
    000
  • 解决JavaScript书签脚本的语法错误:理解自动分号插入(ASI)的陷阱

    本文深入探讨了JavaScript代码在转化为书签脚本时常见的语法错误,特别是由于JavaScript自动分号插入(ASI)机制在代码扁平化后失效所导致的问题。文章解释了ASI的工作原理,并通过示例代码展示了缺少分号如何引发Unexpected identifier错误。最后,提供了手动添加分号和使…

    2025年12月20日
    000
  • 解决JavaScript书签工具中的语法错误:自动分号插入与代码压缩的冲突解析

    当JavaScript代码被转换为书签工具时,常见的语法错误,如Unexpected identifier,往往源于代码压缩过程中移除了换行符,从而破坏了JavaScript的自动分号插入(ASI)机制。本文将深入探讨ASI的工作原理及其与代码压缩的冲突,并提供两种解决方案:手动添加分号以确保语句完…

    2025年12月20日
    000
  • JavaScript书签脚本语法错误解析:自动分号插入与代码压缩的最佳实践

    本文深入探讨JavaScript代码在转换为书签脚本时出现SyntaxError的常见原因。当代码依赖自动分号插入(ASI)而转换工具移除换行符却未补充分号时,便会导致语法错误。文章将详细解释ASI机制,并提供两种解决方案:手动添加分号以增强代码健壮性,或使用专业的代码压缩工具,确保书签脚本的正确性…

    2025年12月20日
    000
  • js如何判断原型链是否有循环引用

    判断javascript原型链是否存在循环引用的核心方法是使用set记录已访问对象,在遍历__proto__链时若遇到重复对象则说明存在循环;2. 具体实现通过while循环结合object.getprototypeof逐级向上检查,利用set的唯一性检测重复引用,若到达null则无循环,否则存在循…

    2025年12月20日 好文分享
    000
  • MutationObserver的回调属于微任务吗?

    mutationobserver的回调属于微任务,会在当前宏任务结束后、浏览器渲染前执行。2. 它能批量处理dom变化,确保在最新且稳定的dom状态中回调,提升性能并避免布局抖动。3. 潜在挑战包括可能阻塞主线程、引发无限循环及调试复杂,需谨慎编写回调逻辑。4. 适用于动态内容加载、响应式组件、性能…

    2025年12月20日 好文分享
    000
  • 将外部 JavaScript 文件嵌入 HTML 的实用指南

    第一段引用上面的摘要: 本文介绍了一种将外部 JavaScript 文件嵌入到 HTML 文件中的方法,以便生成独立的 HTML 文件。通过使用 m4 宏处理器,我们可以轻松地将 JavaScript 代码直接嵌入到 标签中,从而简化开发流程并提高模块化程度。 使用 m4 宏处理器嵌入 JavaSc…

    2025年12月20日
    000
  • 将外部 JavaScript 文件嵌入 HTML 的教程

    本文介绍了一种将外部 JavaScript 文件嵌入到 HTML 文件中的方法,以便生成独立的 HTML 文件。通过使用 m4 宏处理器,可以轻松地将外部 JavaScript 文件的内容直接插入到 HTML 文件的 标签中,从而避免了对外部 JavaScript 文件的依赖,并简化了部署流程。 使…

    2025年12月20日
    000
  • 将外部 JavaScript 文件嵌入 HTML 的方法

    本文介绍了一种将外部 JavaScript 文件嵌入到 HTML 文件中的方法,以便生成独立的 HTML 文件。通过使用 m4 宏处理器,可以方便地将 JavaScript 文件的内容直接插入到 HTML 文件的 标签中,从而实现代码的模块化和便捷部署。本文提供详细的步骤和示例代码,帮助开发者快速掌…

    2025年12月20日
    000
  • javascript怎么求数组最小值

    javascript数组查找最小值的核心方法包括:使用for循环遍历比较,设初始最小值并逐个对比更新;2. 使用math.min()结合扩展运算符(math.min(…arr)),代码简洁但大数组可能存在性能或参数限制问题;3. 使用reduce()方法(arr.reduce((min,…

    2025年12月20日 好文分享
    000
  • javascript闭包如何防止内存泄漏

    闭包可能引起内存泄漏,关键在于闭包持续引用外部变量导致垃圾回收无法释放内存。1. 闭包通过保持对外部变量的引用,使这些变量在函数执行后仍驻留内存;若引用大型对象且长期不解除,就会造成内存泄漏。2. 避免方法包括:显式将闭包或其引用变量设为null以解除引用。3. 使用weakref创建弱引用,允许对…

    2025年12月20日 好文分享
    000
  • js如何检测原型链的终点

    javascript中,原型链的终点是null,因为object.prototype的原型被设计为null,从而避免无限递归并为属性查找提供明确的终止条件;通过反复调用object.getprototypeof()方法可追溯原型链,直到返回null即停止,例如使用while循环遍历currentpr…

    2025年12月20日 好文分享
    000
  • js如何判断对象的原型是否被代理

    无法直接判断javascript对象的原型是否被代理,但可通过间接方法推测:①通过object.getownpropertydescriptor和object.getprototypeof比较属性描述符与原型是否匹配;②在原型上定义临时属性并访问,观察get行为是否被拦截;③比较对象tostring…

    2025年12月20日 好文分享
    000
  • js如何判断对象的原型是否可删除

    javascript中无法直接删除对象的原型,因为原型是对象内部的[[prototype]]链接,而非普通属性;2. delete操作符只能删除对象自身的可配置属性,无法触及内部原型链接;3. 改变原型应使用object.setprototypeof(obj, prototype)或设置__prot…

    2025年12月20日 好文分享
    000
  • javascript闭包怎么实现函数节流

    函数节流和函数防抖的区别是:1. 节流保证在一定时间间隔内至少执行一次函数;2. 防抖则只在事件停止触发一段时间后执行最后一次调用。节流适用于如窗口滚动、调整大小等高频触发但需定期响应的场景,而防抖更适合搜索输入等需要等待用户操作结束的场景。闭包在节流中的作用是通过保存上次执行时间戳或定时器id,避…

    2025年12月20日 好文分享
    000
  • JavaScript可选链操作符 (?.) 的行为深度解析:短路机制与链式应用

    本文深入探讨JavaScript可选链操作符 (?.) 的行为特性,特别是其短路机制在链式调用中的作用。通过实例分析,揭示了当表达式链中某个环节为 null 或 undefined 时,?. 如何阻止后续属性访问错误,并导致整个表达式短路并返回 undefined,而非仅仅作用于紧邻的属性。理解其短…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信