js怎么判断对象是否通过new创建

最准确的判断方式是在构造函数内部使用 new.target,若函数通过 new 调用则 new.target 指向构造函数,否则为 undefined;2. 对于已创建的对象,可使用 instanceof 判断其原型链是否包含构造函数的 prototype,但该方法在跨 realm 或原型链被修改时会失效;3. 可通过 object.getprototypeof() 或 isprototypeof() 更精确地检查原型链关系;4. constructor 属性不可靠,因其可被修改;5. 可在构造函数中添加自定义标记(如 this._isnewinstance = true)来实现可靠的“事后”判断,前提是能控制构造逻辑。最终,最推荐的方案是在构造时用 new.target 控制行为,外部判断则结合 instanceof 与原型检查并注意其局限性。

js怎么判断对象是否通过new创建

在JavaScript里,要百分之百地“事后”判断一个对象是不是通过

new

关键字创建的,这事儿有点微妙,甚至可以说,没有一个完美的银弹。最直接、最准确的方式,其实是在构造函数内部利用

new.target

这个元属性来判断。如果对象已经创建出来了,我们通常会借助

instanceof

操作符,或者通过检查其原型链来推断,但这两种方法都有其局限性。

js怎么判断对象是否通过new创建

解决方案

判断一个对象是否通过

new

创建,最直接且推荐的做法是在其构造函数内部使用

new.target

。这个ES6引入的特性,会在函数被

new

调用时指向被

new

调用的构造函数,如果函数是普通调用,则

new.target

undefined

。这让我们可以精确地控制构造函数的行为,甚至强制它必须通过

new

来调用。

举个例子,假设我们有一个

Person

构造函数:

js怎么判断对象是否通过new创建

function Person(name) {  // 在这里判断 new.target  if (!new.target) {    // 如果没有使用 new 调用,则返回一个通过 new 创建的实例    console.warn("建议使用 new 关键字创建 Person 实例。");    return new Person(name);  }  this.name = name;  console.log(`Person 实例 ${this.name} 已创建。`);}const person1 = new Person('Alice'); // 正常创建const person2 = Person('Bob');       // 尝试不使用 new 创建,会被内部修正console.log(person1 instanceof Person); // trueconsole.log(person2 instanceof Person); // true

这种模式,在我日常写一些库或者框架的时候,用得特别多,它能有效避免用户误操作导致的问题。

如果对象已经创建,且我们无法修改其构造函数,那么

instanceof

是最常用的方法。它会检查对象的原型链上是否存在指定构造函数的

prototype

属性。

js怎么判断对象是否通过new创建

function Animal(type) {  this.type = type;}const dog = new Animal('Dog');const cat = new Animal('Cat');console.log(dog instanceof Animal); // trueconsole.log(cat instanceof Animal); // trueconst obj = {};console.log(obj instanceof Animal); // false

instanceof

并非没有缺陷,它依赖于原型链的完整性,如果原型链被修改或者对象来自不同的 JavaScript Realm (比如 iframe),它可能就不那么可靠了。

深入理解

new.target

:如何精准控制构造行为?

new.target

是一个非常精妙的语言特性,它不仅仅是用来判断“是否通过

new

创建”,更重要的是,它赋予了构造函数内部一个强大的自我感知能力。当一个函数被

new

操作符调用时,

new.target

会指向这个

new

表达式中直接被调用的构造函数。如果函数是作为普通函数被调用(没有

new

),那么

new.target

的值就是

undefined

这有什么用呢?在我看来,它最大的价值在于“防御性编程”和“弹性构造”。

防御性编程:强制使用

new

就像前面

Person

例子里展示的,我们可以利用

!new.target

来强制用户必须使用

new

来实例化对象。这避免了因为忘记

new

导致

this

指向全局对象(在非严格模式下)或者报错(在严格模式下),从而引发难以追踪的bug。

function Product(name, price) {  if (!new.target) {    // 没用 new?那我帮你 new 一个    console.warn("Product 构造函数必须通过 new 关键字调用!");    return new Product(name, price);  }  this.name = name;  this.price = price;}const p1 = new Product('Laptop', 1200); // 正常const p2 = Product('Mouse', 25);       // 会被自动修正并警告console.log(p1.name, p2.name);

这种做法,让你的API接口变得更加健壮,减少了用户的犯错空间。

弹性构造:根据调用方式调整行为

除了强制,

new.target

还能实现更灵活的构造逻辑。例如,你可以让同一个函数在

new

调用时作为一个构造函数,而在普通调用时作为一个工厂函数,返回一个预设的实例或者其他什么东西。

function Greeter(greeting) {  if (new.target) {    // 如果是 new 调用,初始化实例    this.greeting = greeting;    console.log("Greeter 实例被构造");  } else {    // 如果是普通调用,返回一个默认的 Greeter 实例    console.log("返回一个默认 Greeter 实例");    return new Greeter("Hello, default!");  }}const myGreeter = new Greeter("Hi there!");console.log(myGreeter.greeting); // "Hi there!"const defaultGreeter = Greeter();console.log(defaultGreeter.greeting); // "Hello, default!"

这让你的函数能够适应不同的使用场景,提供更友好的API。当然,这种灵活性也可能增加一点点理解成本,所以在使用时需要权衡。

instanceof

并非万能:何时会失灵?

instanceof

操作符在日常开发中非常常用,它通过检查一个对象的原型链(

[[Prototype]]

内部属性)是否包含某个构造函数的

prototype

属性来判断实例关系。听起来很直观,但它确实有自己的局限性,尤其是在一些复杂或跨环境的场景下。

一个很常见的场景就是跨 Realm (跨域/iframe) 对象。每个 JavaScript Realm(比如一个浏览器窗口、一个 iframe 或者 Node.js 的 vm 模块创建的上下文)都有自己独立的全局对象和内置构造函数。这意味着,一个在 iframe A 中创建的对象,即使它是

Array

类型,在 iframe B 中使用

instanceof Array

来判断,结果也可能是

false

。因为这两个

Array

构造函数是不同的对象,它们的

prototype

属性也指向不同的原型对象。

  const iframe = document.getElementById('myFrame');  const iframeDoc = iframe.contentWindow.document;  iframeDoc.write('parent.myArrayInIframe = [];');  iframeDoc.close();  setTimeout(() => {    const arrInParent = [];    const arrInIframe = window.myArrayInIframe;    console.log(arrInParent instanceof Array); // true (在当前 Realm)    console.log(arrInIframe instanceof Array); // false (来自不同 Realm 的 Array 构造函数)  }, 100);

你看,即使它们看起来都是数组,

instanceof

却给出了不同的结果。这在前端开发中,尤其是在涉及微前端或者嵌入第三方内容的场景下,是个需要特别注意的“坑”。

另一个是原型链被修改的情况。虽然不常见,但如果有人手动修改了对象的原型链,

instanceof

的结果也会变得不可靠。

function CustomObject() {}const obj = new CustomObject();// 正常情况console.log(obj instanceof CustomObject); // true// 修改原型链Object.setPrototypeOf(obj, Object.prototype);console.log(obj instanceof CustomObject); // false (原型链被截断,CustomObject.prototype 不再在其中)

最后,如果你的目标是判断一个对象是不是“某个类型”的实例,而不是特指“通过

new

某个构造函数创建”,那么

instanceof

也可能不是最佳选择。比如,你可能想检查一个对象是否“可迭代”,这时候会更倾向于检查它是否有

Symbol.iterator

方法,而不是它是不是

Array

Map

的实例。

除了

new.target

instanceof

,还有哪些辅助方法?

当我们无法使用

new.target

(因为对象已经创建且我们无法修改构造函数),并且

instanceof

又不够可靠时,还有一些辅助方法可以帮助我们进行更深层次的判断,或者说,从不同的角度来理解一个对象的“来源”或“类型”。

1. 使用

Object.getPrototypeOf()

检查原型链

Object.getPrototypeOf()

是一个非常实用的方法,它直接返回指定对象的原型(即

[[Prototype]]

内部属性的值)。结合

Object.prototype.isPrototypeOf()

,我们可以更灵活地检查一个对象是否在另一个对象的原型链上。

function MyConstructor() {}const myInstance = new MyConstructor();// 检查 myInstance 的原型链上是否存在 MyConstructor.prototypeconsole.log(MyConstructor.prototype.isPrototypeOf(myInstance)); // true// 也可以这样组合判断,虽然和 instanceof 效果类似,但理解起来更直接console.log(Object.getPrototypeOf(myInstance) === MyConstructor.prototype); // true// 注意:这只检查直接原型,如果中间有继承,则不为 true// 而 isPrototypeOf 会检查整个原型链
isPrototypeOf

instanceof

更底层,因为它不涉及

constructor

属性或

Symbol.hasInstance

,只是纯粹地检查原型链关系。这在某些需要精确控制原型检查的场景下很有用。

2. 检查

constructor

属性(谨慎使用!)

每个对象通常都有一个

constructor

属性,指向创建该实例的构造函数。

function AnotherConstructor() {}const anotherInstance = new AnotherConstructor();console.log(anotherInstance.constructor === AnotherConstructor); // trueconsole.log(anotherInstance.constructor.name); // "AnotherConstructor"

然而,这个方法非常不推荐作为判断对象是否通过

new

创建的可靠依据。为什么呢?因为

constructor

属性是可写的,它很容易被修改、覆盖,或者在继承链中指向非预期的构造函数。

function Parent() {}function Child() {}Child.prototype = new Parent(); // 继承 Parent 的原型,但 constructor 没改Child.prototype.constructor = Child; // 修正 constructorconst childInstance = new Child();console.log(childInstance.constructor === Child);   // trueconsole.log(childInstance.constructor === Parent);  // falseconsole.log(childInstance instanceof Child);        // trueconsole.log(childInstance instanceof Parent);       // true// 如果 constructor 没修正,或者被恶意修改function BadConstructor() {}const badInstance = new BadConstructor();badInstance.constructor = String; // 随便改console.log(badInstance.constructor === BadConstructor); // falseconsole.log(badInstance instanceof BadConstructor);      // true

所以,

constructor

属性更多是提供一个“线索”,而不是一个可靠的“证据”。

3. 添加自定义标记或属性

在某些特定场景下,如果你的设计允许,你可以在构造函数内部给实例添加一个私有(或伪私有)的标记,来明确它是否是通过

new

创建的。

function TaggedObject() {  if (!new.target) {    return new TaggedObject();  }  this._isNewInstance = true; // 添加一个标记  // ... 其他初始化}const tagInstance = new TaggedObject();const nonTagInstance = TaggedObject(); // 也会被 newconsole.log(tagInstance._isNewInstance);    // trueconsole.log(nonTagInstance._isNewInstance); // true

这种方法完全依赖于你自己的约定和实现,但它在你知道所有可能的创建路径时,可以提供最直接、最可靠的“事后”判断依据。这就像在产品出厂时贴一个“合格证”,简单直接。

总的来说,判断一个对象是否通过

new

创建,最佳时机是在构造函数内部使用

new.target

。如果是在外部判断,

instanceof

是最常用的,但要警惕其局限性。而

Object.getPrototypeOf()

和自定义标记则提供了更精细或更具控制力的替代方案。

以上就是js怎么判断对象是否通过new创建的详细内容,更多请关注创想鸟其它相关文章!

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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 07:40:57
下一篇 2025年12月20日 07:41:08

相关推荐

  • CSS mask属性无法获取图片:为什么我的图片不见了?

    CSS mask属性无法获取图片 在使用CSS mask属性时,可能会遇到无法获取指定照片的情况。这个问题通常表现为: 网络面板中没有请求图片:尽管CSS代码中指定了图片地址,但网络面板中却找不到图片的请求记录。 问题原因: 此问题的可能原因是浏览器的兼容性问题。某些较旧版本的浏览器可能不支持CSS…

    2025年12月24日
    900
  • 为什么设置 `overflow: hidden` 会导致 `inline-block` 元素错位?

    overflow 导致 inline-block 元素错位解析 当多个 inline-block 元素并列排列时,可能会出现错位显示的问题。这通常是由于其中一个元素设置了 overflow 属性引起的。 问题现象 在不设置 overflow 属性时,元素按预期显示在同一水平线上: 不设置 overf…

    2025年12月24日 好文分享
    400
  • 网页使用本地字体:为什么 CSS 代码中明明指定了“荆南麦圆体”,页面却仍然显示“微软雅黑”?

    网页中使用本地字体 本文将解答如何将本地安装字体应用到网页中,避免使用 src 属性直接引入字体文件。 问题: 想要在网页上使用已安装的“荆南麦圆体”字体,但 css 代码中将其置于第一位的“font-family”属性,页面仍显示“微软雅黑”字体。 立即学习“前端免费学习笔记(深入)”; 答案: …

    2025年12月24日
    000
  • 为什么我的特定 DIV 在 Edge 浏览器中无法显示?

    特定 DIV 无法显示:用户代理样式表的困扰 当你在 Edge 浏览器中打开项目中的某个 div 时,却发现它无法正常显示,仔细检查样式后,发现是由用户代理样式表中的 display none 引起的。但你疑问的是,为什么会出现这样的样式表,而且只针对特定的 div? 背后的原因 用户代理样式表是由…

    2025年12月24日
    200
  • inline-block元素错位了,是为什么?

    inline-block元素错位背后的原因 inline-block元素是一种特殊类型的块级元素,它可以与其他元素行内排列。但是,在某些情况下,inline-block元素可能会出现错位显示的问题。 错位的原因 当inline-block元素设置了overflow:hidden属性时,它会影响元素的…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 为什么使用 inline-block 元素时会错位?

    inline-block 元素错位成因剖析 在使用 inline-block 元素时,可能会遇到它们错位显示的问题。如代码 demo 所示,当设置了 overflow 属性时,a 标签就会错位下沉,而未设置时却不会。 问题根源: overflow:hidden 属性影响了 inline-block …

    2025年12月24日
    000
  • 为什么我的 CSS 元素放大效果无法正常生效?

    css 设置元素放大效果的疑问解答 原提问者在尝试给元素添加 10em 字体大小和过渡效果后,未能在进入页面时看到放大效果。探究发现,原提问者将 CSS 代码直接写在页面中,导致放大效果无法触发。 解决办法如下: 将 CSS 样式写在一个单独的文件中,并使用 标签引入该样式文件。这个操作与原提问者观…

    2025年12月24日
    000
  • 为什么我的 em 和 transition 设置后元素没有放大?

    元素设置 em 和 transition 后不放大 一个 youtube 视频中展示了设置 em 和 transition 的元素在页面加载后会放大,但同样的代码在提问者电脑上没有达到预期效果。 可能原因: 问题在于 css 代码的位置。在视频中,css 被放置在单独的文件中并通过 link 标签引…

    2025年12月24日
    100
  • 为什么在父元素为inline或inline-block时,子元素设置width: 100%会出现不同的显示效果?

    width:100%在父元素为inline或inline-block下的显示问题 问题提出 当父元素为inline或inline-block时,内部元素设置width:100%会出现不同的显示效果。以代码为例: 测试内容 这是inline-block span 效果1:父元素为inline-bloc…

    2025年12月24日
    400
  • css中的浏览器私有化前缀有哪些

    css中的浏览器私有化前缀有:1、谷歌浏览器和苹果浏览器【-webkit-】;2、火狐浏览器【-moz-】;3、IE浏览器【-ms-】;4、欧朋浏览器【-o-】。 浏览器私有化前缀有如下几个: (学习视频分享:css视频教程) -webkit-:谷歌 苹果 background:-webkit-li…

    2025年12月24日
    300
  • 如何利用css改变浏览器滚动条样式

    注意:该方法只适用于 -webkit- 内核浏览器 滚动条外观由两部分组成: 1、滚动条整体滑轨 2、滚动条滑轨内滑块 在CSS中滚动条由3部分组成 立即学习“前端免费学习笔记(深入)”; name::-webkit-scrollbar //滚动条整体样式name::-webkit-scrollba…

    2025年12月24日
    000
  • css如何解决不同浏览器下文本兼容的问题

    目标: css实现不同浏览器下兼容文本两端对齐。 在 form 表单的前端布局中,我们经常需要将文本框的提示文本两端对齐,例如: 解决过程: 立即学习“前端免费学习笔记(深入)”; 1、首先想到是能不能直接靠 css 解决问题 css .test-justify { text-align: just…

    2025年12月24日 好文分享
    200
  • 关于jQuery浏览器CSS3特写兼容的介绍

    这篇文章主要介绍了jquery浏览器css3特写兼容的方法,实例分析了jquery兼容浏览器的使用技巧,需要的朋友可以参考下 本文实例讲述了jQuery浏览器CSS3特写兼容的方法。分享给大家供大家参考。具体分析如下: CSS3充分吸收多年了web发展的需求,吸收了很多新颖的特性。例如border-…

    好文分享 2025年12月24日
    000
  • 360浏览器兼容模式的页面显示不全怎么处理

    这次给大家带来360浏览器兼容模式的页面显示不全怎么处理,处理360浏览器兼容模式页面显示不全的注意事项有哪些,下面就是实战案例,一起来看一下。  由于众所周知的情况,国内的主流浏览器都是双核浏览器:基于Webkit内核用于常用网站的高速浏览。基于IE的内核用于兼容网银、旧版网站。以360的几款浏览…

    好文分享 2025年12月24日
    000
  • 如何解决css对浏览器兼容性问题总结

    css对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了ie7,6与fireofx的兼容性处理方法并 整理了一下.对于web2.0的过度,请尽量用xhtml格式写代码,而且doctype 影响 css 处理,作为w3c的标准,一定要加 doctype声名.…

    好文分享 2025年12月23日
    000
  • 关于CSS3中选择符的实例详解

    英文原文: www.456bereastreet.com/archive/200601/css_3_selectors_explained/中文翻译: www.dudo.org/article.asp?id=197注:本文写于2006年1月,当时IE7、IE8和Firefox3还未发行,文中所有说的…

    好文分享 2025年12月23日
    000
  • 阐述什么是CSS3?

    网页制作Webjx文章简介:CSS3不是新事物,更不是只是围绕border-radius属性实现的圆角。它正耐心的坐在那里,已经准备好了首次登场,呷着咖啡,等着浏览器来铺上红地毯。            CSS3不是新事物,更不是只是围绕border-radius属性实现              …

    好文分享 2025年12月23日
    000
  • 用CSS hack技术解决浏览器兼容性问题

    什么是CSS Hack?   不同的浏览器对CSS的解析结果是不同的,因此会导致相同的CSS输出的页面效果不同,这就需要CSS Hack来解决浏览器局部的兼容性问题。而这个针对不同的浏览器写不同的CSS 代码的过程,就叫CSS Hack。 CSS Hack 形式   CSS Hack大致有3种表现形…

    好文分享 2025年12月23日
    000
  • 如何使用css去除浏览器对表单赋予的默认样式

    我们在写表单的时候会发现一些浏览器对表单赋予了默认的样式,如在chorme浏览器下,文本框及下拉选择框当载入焦点时,都会出现发光的边框,并且在火狐及谷歌浏览器下,多行文本框textarea还可以自由拖拽拉大,另外还有在ie10下,当文本框输入内容后,在文本框的右侧会出现一个小叉叉,等等。不容置疑,这…

    好文分享 2025年12月23日
    000

发表回复

登录后才能评论
关注微信