本机对象和宿主对象有啥区别?
Posted
技术标签:
【中文标题】本机对象和宿主对象有啥区别?【英文标题】:What is the difference between native objects and host objects?本机对象和宿主对象有什么区别? 【发布时间】:2011-11-28 16:23:45 【问题描述】:我不明白 javascript 中 native objects 和 host objects 之间的区别。后者是否只是引用由自定义构造函数创建的非原始函数对象(例如,var bird1 = new Bird();
)?
【问题讨论】:
原生对象在 ECMAScript 规范中定义,宿主对象没有。 一个 DOM 元素——比如说,new Image()
——是一个宿主对象,例如。
@ŠimeVidas:您留下的评论与您的回答相矛盾吗?
@Ӫ_._Ӫ 那是我现在的事:)
@ŠimeVidas:您的评论指出主机对象未在 ECMAScript 规范中定义。您的回答指出“两者的定义都在 ECMAScript 规范中”。
【参考方案1】:
除了关于主机对象的其他答案。
主机对象特定于环境。所以除了浏览器的宿主对象之外,nodejs中也有特定的对象。
为了示例,首先从 Javascript 中定义的标准对象开始。然后是浏览器/DOM 的通用对象。节点有它自己的对象。
-
标准 Javascript 内置对象示例:
-
宿主对象文档对象模型示例:
-
Node.js 中的宿主对象:
【讨论】:
【参考方案2】:考虑三个对象:Host、Native、Custom。
主机对象由环境创建并且是特定于环境的。最著名的环境是网络浏览器,但也可能是另一个平台。在 Web 浏览器中创建的宿主对象可以是窗口对象或文档。通常,浏览器使用 API 创建主机对象以将文档对象模型反映到 JavaScript 中。 (网络浏览器有不同的 JavaScript 引擎来执行此操作)当页面在浏览器中呈现时,会自动创建一个主机对象。
原生对象是由开发人员使用预定义的 JavaScript 类创建的。原生对象在您编写的脚本中。
然后,自定义对象是由开发人员根据自定义(未预定义或部分预定义)类创建的。
【讨论】:
【参考方案3】:这两个术语都在 ECMAScript 规范中定义:
原生对象
ECMAScript 实现中的对象,其语义完全 由本规范而非宿主环境定义。
注意标准本机对象在本规范中定义。一些 原生对象是内置的;其他的可以在施工期间建造 ECMAScript 程序的执行过程。
来源:http://es5.github.com/#x4.3.6
宿主对象
由宿主环境提供的对象来完成 ECMAScript的执行环境。
注意任何非本地对象都是宿主对象。
来源:http://es5.github.com/#x4.3.8
几个例子:
本机对象:Object
(构造函数)、Date
、Math
、parseInt
、eval
、indexOf
和 replace
等字符串方法、数组方法……
主机对象(假设浏览器环境):window
、document
、location
、history
、XMLHttpRequest
、setTimeout
、getElementsByTagName
、querySelectorAll
、...
【讨论】:
也给他一些例子,原生对象:Array、String ..,宿主对象:window ... 自定义 custructor 怎么样?例如,我帖子中的鸟类示例 @ŠimeVidas:“那么它是一个宿主对象。” 这不正确。参见in this answer 描述的host object
的定义。
ŠimeVidas:但规范声明 '主机对象的 [[Class]] 内部属性的值可以是任何字符串值除了 “参数”、“数组”、“布尔”、“日期”、“错误”、“函数”、“JSON”、“数学”、“数字”、“对象”之一、“RegExp”和“String”。' Bird 对象的内部 [[Class]] 属性将为 'Object'
,或通过 Object.prototype.toString
呈现为 '[object Object]'
。
@ŠimeVidas,我不同意,如果Bird
是用户定义的函数,它的语义是“完全定义” 由 ES 规范(函数对象如何工作,它们如何被创建、执行、与new
运算符等一起使用,等等)它是一个本机对象...我可能会放弃答案...【参考方案4】:
对于var bird1 = new Bird();
是本机对象还是宿主对象的问题,无法给出令人信服的答案。假设 Bird 是一个用户定义的函数,则 javascript 实现将根据 http://es5.github.io/#x13.2 创建一个原生 非内置 对象。相反,原生内置 对象将在 JavaScript 程序启动时出现(例如 Object 和许多其他程序)。本机对象和宿主对象之间的区别在于前者由 javascript 实现创建,后者由宿主环境提供。因此,宿主对象的内部 [[class]] 属性可能与内置对象使用的属性不同(即“Arguments”、“Array”、“Boolean”、“Date”、“Error”、“Function”、“ JSON”、“数学”、“数字”、“对象”、“正则表达式”和“字符串”)。
另外,值得注意的是,ECMA6 http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 不再使用术语本机和主机对象。相反,它定义了以下对象类型,并对其预期行为进行了更清晰的解释。
4.3.6 普通对象
具有所有对象必须支持的基本内部方法的默认行为的对象
4.3.7 奇异物体
对象不具有所有对象必须支持的一种或多种基本内部方法的默认行为 笔记 任何不是普通物体的物体都是奇异物体。
4.3.8 标准对象
其语义由本规范定义的对象
4.3.9 内置对象
由 ECMAScript 实现指定和提供的对象
【讨论】:
【参考方案5】:如果我们区分三种对象就更清楚了:
内置对象:String
、Math
、RegExp
、Object
、Function
等 - JavaScript 中始终可用的核心预定义对象。在 ECMAScript 规范中定义。
宿主对象:浏览器环境提供的window
、XmlHttpRequest
、DOM节点等对象。它们与内置对象不同,因为并非所有环境都具有相同的宿主对象。如果 JavaScript 在浏览器之外运行,例如在 Node.js 中作为服务器端脚本语言,则可以使用不同的宿主对象。
用户对象:在 JavaScript 代码中定义的对象。因此,您示例中的“鸟”将是一个用户对象。
JavaScript 规范将内置对象和用户对象组合为原生对象。这是对术语“native”的非正统用法,因为用户对象显然是用 JavaScript 实现的,而内置对象很可能在底层用不同的语言实现,就像宿主对象一样。但是从 JavaScript 规范的角度来看,内置对象和用户对象都是 JavaScript 原生的,因为它们是在 JavaScript 规范中定义的,而宿主对象不是。
【讨论】:
原生对象是指那些由 javascript 实现(引擎)创建的对象。内置对象和其他本机对象(用户对象)之间的区别在于,从符合相关 ECMA 规则的 javascript 程序开始就存在以前的对象。由于 ECMA6 (这可能有点矫枉过正,但为了简单起见,原生对象是存在的,并且可以在任何实现 ECMAScript 兼容引擎的环境中使用。这通常(但不总是)是浏览器。
因此,例如,您的 Internet Explorer 或 Google Chrome 不会使 String 对象对您可用。您可以使用 String 对象的原因是因为它是 JavaScript 语言本身的“原生”(内置)。
但是,如果您想创建一个弹出窗口,则需要使用 window 对象。窗口对象由浏览器软件本身提供,因此它不是 JavaScript 原生的,而是“浏览器对象模型”或 BOM 的一部分。
【讨论】:
【参考方案7】:原生对象是符合规范的对象,即“标准对象”。
主机对象是浏览器(或其他运行时环境,如 Node)提供的对象。
大多数宿主对象都是原生对象,每当你使用new
实例化某个东西时,你可以 99.99% 确定它是原生对象,除非你弄乱了奇怪的宿主对象。
由于 IE(和其他旧浏览器?) 中存在非常奇怪的对象,引入了这个概念。例如:
typeof document.all == "undefined"; // true
document.all.myElementId; // object
看到这里,每个人都会同意document.all
显然是“非标准的”,因此是一个非本地宿主对象。
那么为什么不首先调用原生对象标准对象呢?很简单:毕竟Standard(!) document 也谈到了非本地对象,称它们为非标准 会导致悖论。
再次:
本机 == “标准” host == 由浏览器或 Node 提供或... 大部分宿主对象都是原生的,所有非宿主对象也是原生的【讨论】:
你已经偏离了轨道。 “大多数主机对象都是原生的”是不正确的。事实上,根据定义,所有主机对象都不是原生的。 Native当然意味着“标准”,但它意味着语言规范中的标准,而不是不寻常意义上的标准。 JavaScript (ECMASCript) 定义了几个由浏览器和其他主机实现的接口/API,例如:String、Date、MATH、Boolean、Number、JSON 和 XmlHTTP。这些对象是可用的,因为主机实现了 ECMAScript 兼容引擎并满足 ECMA 标准。【参考方案8】:这是我对规范的理解。
这个:
var bird = new Bird();
...生成一个本机对象,该对象恰好是使用 new
运算符创建的。
本机对象具有以下之一的内部 [[Class]] 属性:
“参数”、“数组”、“布尔”、“日期”、“错误”、“函数”、“JSON”、“数学”、“数字”、“对象”、“正则表达式”、和“字符串”。
对于您的bird1
,它将是:
“对象”
就像你创建一个函数一样:
function my_func()
// ...
...my_func
没有在 ECMAScript 中定义,但它仍然是具有内部 [[Class]] 的原生对象:
“功能”
宿主对象是环境提供的对象,目的是为规范中未定义的环境提供特定目的。
例如:
var divs = document.getElementsByTagName('div')
divs
引用的对象是一个 NodeList,它以一种感觉就像一个普通的 JavaScript 对象的方式集成到环境中,但规范没有在任何地方定义它.
它的内部[[Class]]属性是:
“节点列表”
这为实现设计人员提供了一些灵活性,可以使实现适应环境的特定需求。
在整个规范中定义了主机对象的要求。
【讨论】:
+1,我同意你的观点,bird
和 Bird
是 本机对象,它们是用户定义的函数 (Bird
),并且是对象 ( bird
) 使用函数作为构造函数创建的,所有语义都在规范中定义。关于宿主对象,不要太依赖[[Class]]
内部属性,例如window.alert
有"Function"
作为它的[[Class]]
属性的值几乎所有的实现,在IE上它有"Object"
,它仍然是一个宿主对象...
感谢@CMS。是的,我并不想过分强调使用内部[[Class]]
。而只是将其用作对实现者如何解释不同类型的对象的有形的一瞥。那么window.alert
的内部 [[Class]]
和 "Function"
似乎违反了 ES 5?
我正试图看到这个动作,但如果我得到那个 div 的类型,divs/NodeList
,我会得到一个object
。我猜我还不明白这一点,但这不会使它成为一个原生对象吗?
This is helpful。获取 window
中的所有内容会显示所有主机对象
Bird 不是原生对象,因为它的接口在 ECMASCript 标准中没有完全描述。真的就是这么简单。对象是原生的,字符串是原生的,但用户定义或主机定义的对象不是原生的。以上是关于本机对象和宿主对象有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章