揭秘JavaScript中“一切皆对象”:包装对象机制和原型链继承

前言

在 JavaScript 中,我们经常能听到"一切皆对象" 这一句看起来有点绝对甚至细想是错误的话,因为我们之间明明介绍了存在原始数据类型和对象两种数据类型。这是因为尽管严格来说存在其它数据类型,但 JS 通过包装对象原型链继承函数的对象特性,让几乎所有数据都表现出对象的行为。以下从多个维度深入解析这一特性。

一、包装对象机制

1. 原始类型(Primitive Values)

JavaScript 包含 6 种原始类型(ES6 + 新增SymbolBigInt):

  • stringnumberbooleannullundefinedsymbolbigint

    特点:原始类型并非对象,存储在栈内存中,无法直接添加属性或方法。

2. 引用类型(Reference Types)

  • Object(普通对象)、ArrayFunctionDateRegExp

    特点:作为对象存储在堆内存中,可动态添加属性,通过引用地址访问。

3. 原始类型的 "对象化"------ 包装对象

当对原始类型调用方法时,引擎自动把字面量转换成对应的包装类对象,所以可以访问属性和方法。

所以按常理在原始类型中会报错的语句num.a='a'可以执行:

js 复制代码
var num = 10;
num.a='a';
console.log(num.a);

但为什么最后的输出结果是undefined呢?

这是因为js是弱类型语言,所以只有在赋值语句执行时才会判断值的类型,当值为原始类型时,就会自动将包装对象上的属性移除,所以实际执行为:

js 复制代码
var num = 10;;
num.a='a';//new Number(10)
//delete num.a;
console.log(num.a);//undefined
  • new做了什么(不完整):

    1. 创建一个this对象
    2. 执行构造函数,给this对象添加属性和方法
    3. 返回this对象
  • 包装对象类型StringNumberBooleanSymbolBigInt

  • 注意nullundefined没有包装对象,因此调用方法会报错(如null.toString())。


js 复制代码
var arr=[1,2,3];//new Array(1,2,3);
arr.length=1;
console.log(arr);//[1]

var string='abc';//
string.length=1;//new String('abc');自动装箱
//delete string.length;
console.log(string.length);//3
console.log(string);//abc

按我们之间的介绍string.length应该是undefined,但这里为什么能得到3呢,这是因为有原型的存在,让我继续学习下面知识

二、原型链继承

1.函数原型

函数是一种类型,同时也是 Function 对象的实例。每个函数都有两个与原型相关的重要属性:

  • prototype 属性:函数特有的属性,指向一个普通对象,用于实现原型链继承。
  • [[Prototype]] 内部属性 :指向 Function.prototype,即所有函数都继承自 Function.prototype
js 复制代码
function Person(name) {
    this.name = name;
}

// Person.prototype 是一个普通对象,默认包含 constructor 属性
console.log(Person.prototype.constructor === Person); // true

const alice = new Person("Alice");
// alice 的 [[Prototype]] 指向 Person.prototype
console.log(Object.getPrototypeOf(alice) === Person.prototype); // true
意义

将构造函数的一些固定属性和方法挂载到原型上,在创建实例的时候不用重复执行

js 复制代码
function Car(color){
    this.color=color;
}
Car.prototype={
    price:1000000,
    year:2010,
    brand:"BMW",
}
const car1=new Car("green");
const car2=new Car("red");//每次创建车时只重新赋值可变的颜色属性
console.log(car1.brand);// BMW
注意
  • 实例对象可以访问原型上的属性和方法。
  • 实例对象无法修改原型上的属性和方法。
  • 实例对象无法删除原型上的属性和方法。

2.对象原型

每一个对象都有一个属性_proto_,该属性值也是一个对象

js 复制代码
let obj = {
    name: '张三',
    age: 18,

}
function Car(){
    this.color = 'red';
}
console.log(obj.__proto__);//[Object: null prototype] {}
console.log(obj.__proto__ === Object.prototype);//true
obj=new Car();//obj.__proto__=Car.prototype;
console.log(obj.__proto__ === Car.prototype);//true
  • 实例对象的隐式原型===构造函数的显示原型
  • 在new过程中完成(完整)
    1. 创建一个空对象
    2. 让构造函数的this指向这个空对象
    3. 执行构造函数中的代码
    4. 将这个空对象的_proto_指向构造函数的原型对象
    5. 返回这个空对象

3.原型链

对象的原型继承关系

  • 所有对象(包括数组、函数、正则等)都继承自Object.prototype
js 复制代码
const arr = \[1, 2, 3];
console.log(arr.toString());       // 输出 "1,2,3"(继承自Object.prototype)
function Person() {}
console.log(Person.prototype);     // 输出 Person.prototype 对象
console.log(Person.prototype instanceof Object);  // 输出 true

原型链示意图

css 复制代码
\[自定义对象] → \[构造函数的prototype] → \[Object.prototype] → \[null]
  • 例如:Array的原型链为 Array.prototype → Object.prototype → null

三、"一切皆对象" 的实践意义

动态特性与灵活性

  • 可随时为对象添加 / 删除属性:
js 复制代码
const user = {};
user.name = "Alice";         // 动态添加属性
user.sayHi = function() {};  // 动态添加方法

统一的编程接口

  • 所有对象共享Object.prototype的方法(如toString()hasOwnProperty()),降低学习成本。

函数式编程与面向对象的融合

  • 函数作为对象,既可以作为 "行为"(函数调用),也可以作为 "数据"(存储属性、作为参数传递)。

总结:JS "一切皆对象" 的本质

JavaScript 通过包装对象机制原型链继承,让原始类型在使用时表现出对象的行为,同时函数、数组等引用类型本身就是对象。这种设计模糊了 "数据" 与 "对象" 的界限,形成了高度动态灵活的编程范式。

相关推荐
我叫张小白。1 小时前
Vue3监视系统全解析
前端·javascript·vue.js·前端框架·vue3
WYiQIU5 小时前
11月面了7.8家前端岗,兄弟们12月我先躺为敬...
前端·vue.js·react.js·面试·前端框架·飞书
娃哈哈哈哈呀6 小时前
formData 传参 如何传数组
前端·javascript·vue.js
2503_928411568 小时前
11.24 Vue-组件2
前端·javascript·vue.js
g***B7389 小时前
JavaScript在Node.js中的模块系统
开发语言·javascript·node.js
Z***25809 小时前
JavaScript在Node.js中的Deno
开发语言·javascript·node.js
cypking10 小时前
Vue 3 + Vite + Router + Pinia + Element Plus + Monorepo + qiankun 构建企业级中后台前端框架
前端·javascript·vue.js
San30.10 小时前
ES6+ 新特性解析:让 JavaScript 开发更优雅高效
开发语言·javascript·es6
Dream it possible!10 小时前
LeetCode 面试经典 150_二叉搜索树_二叉搜索树中第 K 小的元素(86_230_C++_中等)
c++·leetcode·面试
u***276111 小时前
TypeScript 与后端开发Node.js
javascript·typescript·node.js