一、前言
在项目开发完成后,进行版本测试过程中,更换了浏览器,遇到Uncaught(in promise)TypeError:0bject.hasOwn is not a function
报错
控制台:
报错定位:
二、原因
报错由该项目中使用的react-markdown
插件导致,hasOwn是es2022新语法,旧浏览器不支持。
三、解决
提案方法 Object.hasOwn
与 Object.prototype.hasOwnProperty.call(object, property)
具有相同的行为。
方案一:
直接修改react-markdown
插件中的源码,相当于去修改了node_modules
模块,你下次再npm i
时还是会被重新覆盖的,当然也可以去搜索如何优雅的修改node_modules
中的代码而不被覆盖。但此方案,治标不治本。
方案二:
polyfill 支持
在不支持的浏览器中,我们需要使用一些回退方式。我们利用 Object.hasOwn
与 Object.prototype.hasOwnProperty.call(object, property)
的相同行为实现支持方案:
if (!Object.hasOwn) {
Object.defineProperty(Object, 'hasOwn', {
value: function (object, property) {
if (object == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
return Object.prototype.hasOwnProperty.call(Object(object), property);
},
configurable: true,
enumerable: false,
writable: true,
});
}
将此js文件放在项目入口文件index.js中,项目初始化时执行一次,就全局修改了。
这里附上代码解读:
这段代码是为了在运行环境中添加
Object.hasOwn
方法。Object.hasOwn
是一个用于检查对象是否具有指定属性的方法,它类似于Object.prototype.hasOwnProperty
,但不同的是它直接在对象上调用,而不是通过原型链。在一些老旧的 JavaScript 环境中,
Object.hasOwn
方法可能不存在,因此这段代码的作用是在运行时检测如果Object.hasOwn
不存在,则定义这个方法。这样可以确保在任何环境中都可以使用Object.hasOwn
方法来检查对象的属性。代码中的实现使用了
Object.defineProperty
来定义一个新的属性hasOwn
,该属性是一个函数,它接受两个参数:object
和property
。这个函数会检查object
是否为null
或undefined
,如果是,则抛出一个类型错误。否则,它会调用Object.prototype.hasOwnProperty.call
来检查object
是否具有指定的property
。最后,
Object.defineProperty
的参数设置了这个新属性的特性:
configurable: true
表示这个属性可以被删除或重新定义。enumerable: false
表示这个属性不会出现在对象的枚举属性中。writable: true
表示这个属性的值可以被修改。这样定义的
Object.hasOwn
方法可以在任何 JavaScript 环境中使用,包括老旧的环境,从而提高代码的兼容性。
四、原理
Object.prototype.hasOwnProperty
和 Object.hasOwn
是 JavaScript 中用于检查对象属性的两种方法。
-
Object.prototype.hasOwnProperty
:- 作用: 这是一个用于检测对象自身是否有某个属性的方法。它会返回一个布尔值,指示对象是否拥有指定的属性,而不是从原型链上继承来的属性。
- 用法: 你可以通过
obj.hasOwnProperty('propertyName')
来使用它。 - 缺点: 如果对象上覆盖了
hasOwnProperty
方法(比如通过对象的原型链或直接在对象上定义),可能会导致调用该方法时出现问题。
-
Object.hasOwn
:- 作用: 这是一个在 ES2022 中引入的新方法,用于检查对象是否有某个属性。它作为
Object
对象上的静态方法存在,不依赖于对象实例,因此不会受到实例上重写hasOwnProperty
方法的影响。 - 用法: 你可以通过
Object.hasOwn(obj, 'propertyName')
来使用它。 - 优点: 因为它是静态方法,所以不受对象实例的影响,避免了由于对象上覆盖了
hasOwnProperty
而导致的问题。此外,它提供了更清晰的语法和更高的可读性。
- 作用: 这是一个在 ES2022 中引入的新方法,用于检查对象是否有某个属性。它作为
举个栗子:
const obj = {
hasOwnProperty: function () {
return false;
},
ab: 'own property',
};
对象obj重新定义的 hasOwnProperty
方法,该方法直接覆盖了从 Object.prototype
继承的方法 hasOwnProperty
,此时你再调用hasOwnProperty
方法去判断ab是否是obj对象上的属性时,只会返回false。原因:JavaScript 普通对象的原型可以被覆盖。所以有了Object.hasOwn 提案,提案方法 Object.hasOwn
与 Object.prototype.hasOwnProperty.call(object, property)
具有相同的行为。
总的来说,Object.hasOwn
作为一种静态方法,提供了比 Object.prototype.hasOwnProperty
更可靠和一致的方式来检查对象自身的属性。