一、基础定义与本质区别
1. 原生对象(Native Objects)
- 定义:由 ECMAScript 规范直接定义的对象,与宿主环境(如浏览器、Node.js)无关。
- 特点:
- 跨环境一致性:在所有 JavaScript 环境中行为相同(如
Array、Promise)。 - 全局可用:无需额外引入,直接通过全局作用域访问(如
window.Array)。
- 跨环境一致性:在所有 JavaScript 环境中行为相同(如
- 示例:
String、Object、Function、Date、Map。
2. 宿主对象(Host Objects)
- 定义:由宿主环境提供的对象,用于连接 JavaScript 与外部系统。
- 特点:
- 环境依赖性:不同宿主环境差异大(如浏览器的
window与 Node.js 的global)。 - 动态扩展:可能随宿主环境升级新增 API(如浏览器的
fetch)。
- 环境依赖性:不同宿主环境差异大(如浏览器的
- 示例:
- 浏览器:
window、document、XMLHttpRequest、localStorage。 - Node.js:
process、fs、module。
- 浏览器:
二、核心差异对比表
| 维度 | 原生对象 | 宿主对象 |
|---|---|---|
| 定义来源 | ECMAScript 规范 | 宿主环境(如浏览器、Node.js) |
| 是否可模拟 | 可通过 polyfill 模拟(如旧浏览器) | 部分可模拟(如 jsdom 模拟 DOM) |
| 类型标签 | [object 类型名](如 [object Array]) | 自定义标签(如 [object HTMLDocument]) |
| 典型用途 | 实现语言核心功能(如数据结构、异步) | 操作外部资源(如 DOM、文件系统) |
三、问题
1. 问:window 是原生对象吗?为什么?
- 答:
- 不是。
window是浏览器宿主环境提供的全局对象,用于封装浏览器功能(如 DOM 操作、BOM 接口)。 - 虽然
window包含部分原生对象(如window.Array),但其本身由宿主环境创建,而非 ECMAScript 规范直接定义。
- 不是。
2. 问:如何判断一个对象是原生对象还是宿主对象?
- 答:
- 方法1:检查类型标签(部分情况有效):
Object.prototype.toString.call([]); // "[object Array]"(原生) Object.prototype.toString.call(document); // "[object HTMLDocument]"(宿主) - 方法2:验证是否存在于所有 JavaScript 环境:
- 若在浏览器和 Node.js 中均存在(如
Promise),则为原生对象。 - 若仅在特定环境存在(如
document),则为宿主对象。
- 若在浏览器和 Node.js 中均存在(如
- 方法1:检查类型标签(部分情况有效):
3. 问:宿主对象与原生对象如何交互?
- 答:
- 继承关系:部分宿主对象继承原生对象(如 DOM 元素继承
Object)。 - 方法调用:宿主对象可调用原生对象的方法(如
document.toString())。 - 数据传递:原生对象可作为参数或返回值传递给宿主对象(如
Array作为fetch的响应数据)。
- 继承关系:部分宿主对象继承原生对象(如 DOM 元素继承
4. 问:为什么 Node.js 中没有 window 和 document?
- 答:
window和document是浏览器特有的宿主对象,用于操作浏览器界面和网页内容。- Node.js 作为服务器端环境,无浏览器界面,因此提供替代宿主对象(如
fs、http)处理文件和网络请求。
四、开发中的应用场景
1. 兼容性处理
- 宿主对象(如 DOM API)可能存在浏览器兼容性问题,需用特性检测:
if ('fetch' in window) { // 使用原生fetch(现代浏览器) } else { // 引入polyfill或降级方案 }
2. 环境判断
- 通过宿主对象存在性判断当前环境:
function isBrowser() { return typeof window !== 'undefined'; }
3. 跨端开发注意事项
- 避免直接依赖特定宿主对象(如
window),需封装环境无关的接口:const storage = typeof localStorage !== 'undefined' ? localStorage : null;