javaScript数据存储, 对象和原型与原型链

一、JavaScript 数据类型大盘点

JavaScript 中的数据类型主要分为两大阵营,就像我们生活中 "基本生活用品" 和 "组合家具" 的区别:

1. 原始类型(基本类型)

这些是 JavaScript 中最基础的数据单元,就像搭建积木的最小块:

  • string(字符串) :用单引号、双引号或反引号包裹的文本,比如 "你好"'hello'JavaScript
  • number(数字) :包括整数和小数,例如 663.1415,特别的是,NaN(不是数字)也属于 number 类型
  • boolean(布尔值) :只有两个可能的值:true(真)和 false(假)
  • undefined(未定义) :变量声明了但没赋值时的状态,比如 let a; 此时 a 就是 undefined
  • null(空值) :表示 "故意为空",通常用来主动清空变量的值
  • symbol(符号) :ES6 新增,能创建独一无二的值,即使描述相同也不相等,比如 Symbol('id') !== Symbol('id')
  • bigint(大整数) :处理极大的整数,在数字后面加 n 表示,比如 9007199254740993n,解决了普通数字的精度限制问题

2. 引用类型(复杂类型)

这些类型可以包含多个值,就像能装东西的容器:

  • object(对象) :用键值对存储数据的集合,比如 { name: "小明", age: 18 }
  • array(数组) :按顺序排列的值的集合,比如 [1, 2, 3, "苹果"]
  • function(函数) :可执行的代码块,比如 function add(a, b) { return a + b; }
  • Date(日期对象) :专门处理时间的对象,比如 new Date() 能获取当前时间

二、JavaScript 语言的独特个性

JavaScript 是一种动态的、弱类型的脚本语言,这让它和其他语言有明显区别:

  • 静态语言 vs 动态语言

    • 静态语言(如 C、Java)在写代码时就要规定变量的类型,比如 int age = 18;,而且不能随便改类型
    • 动态语言(如 JavaScript)不需要提前声明类型,变量的类型在运行时才确定,比如 let x = 10; x = "hello";
  • 强类型 vs 弱类型

    • 强类型语言(如 Python)不允许不同类型随便运算,比如 "1" + 2 会报错
    • 弱类型语言(如 JavaScript)支持隐式类型转换,比如 "1" + 2 会自动变成 "12""5" - 3 会变成 2

三、内存空间:数据存哪里?

JavaScript 引擎(比如 V8)会管理三个主要的内存空间,就像我们家里的不同储物区域:

  1. 代码空间:存放要执行的代码,相当于书架,专门放说明书

  2. 栈空间:存放原始类型的值和引用类型的 "地址",特点是存取快,空间小,就像抽屉,放常用的小物件

  3. 堆空间:存放引用类型的实际数据,空间大,但存取稍慢,就像仓库,放体积大的东西

举个例子:let name = "张三"; let user = { age: 20 }; 中,"张三" 存在栈里,而 { age: 20 } 存在堆里,栈里只存了指向这个堆数据的地址。

javascript 复制代码
   function foo(c) {
    c.age = 20
    c = {
        name:'11'
    }
    return c
    }
    let p1 = {
        name:'22',
        age:33
    }
    let p2 = foo(p1)

    console.log(p1);  //{ name: '22', age: 20 }
    console.log(p2);  //{ name: '11' }

对象是 JavaScript 中最常用的数据结构,就像现实中的 "档案袋",可以装各种信息。

1. 创建对象的三种方式

ini 复制代码
// 1. 字面量方式(最常用)
let obj1 = { name: "张三", age: 20 };

// 2. new Object() 方式
let obj2 = new Object();
obj2.name = "李四"; // 给对象添加属性
obj2.age = 22;

// 3. 构造函数方式(适合创建多个相似对象)
function Person(name, age) {
  this.name = name; // this 指向新创建的对象
  this.age = age;
}
// 用 new 关键字创建实例
let obj3 = new Person("王五", 25);

2. new 关键字的工作原理

当用 new 调用函数时,背后发生了一系列操作,就像工厂生产产品的流程:

  1. 先创建一个空对象({}),相当于准备一个空盒子
  2. 把构造函数里的 this 指向这个新对象,相当于给盒子贴标签,说明 "这个盒子归它管"
  3. 执行构造函数里的代码,给新对象添加属性和方法,相当于往盒子里装东西
  4. 让新对象的 __proto__ 指向构造函数的 prototype(原型),相当于给盒子配一把钥匙,能打开公共仓库
  5. 返回这个新对象,相当于把装好的盒子送出来

五、原型与原型链:对象的 "继承" 机制

JavaScript 中的对象通过原型链实现继承,就像家族传承一样。

1. 原型系统的两个核心概念

  • prototype(显式原型) :只有函数才有这个属性,它是一个对象,相当于 "公共仓库",里面的属性和方法可以被所有实例共享
  • *proto(隐式原型) *:每个对象都有这个属性,它指向创建自己的构造函数的 prototype,相当于每个对象都有一把钥匙,能打开对应的公共仓库

2. 原型链的查找规则

当访问对象的某个属性时,查找过程就像找家谱:

  1. 先在对象自身查找,如果找到就直接使用(比如找自己口袋里的东西)

  2. 如果没找到,就通过 __proto__ 去它的原型对象里找(比如问爸爸要)

  3. 还没找到就继续往上找,直到找到 Object.prototype(比如问爷爷、太爷爷)

  4. 如果最后到了 null 还没找到,就返回 undefined(比如追溯到祖宗十八代也没找到)

举个例子:

javascript 复制代码
function Animal() {}
// 往原型里添加方法,所有实例都能用上
Animal.prototype.eat = function() {
  console.log("吃东西");
};

let dog = new Animal();
dog.eat(); // 自身没 eat 方法,就去 Animal.prototype 里找,输出"吃东西"

六、特殊对象的创建

1. 完全没有原型的对象

通常对象都有原型,但我们可以创建一个 "无父无母" 的对象:

javascript 复制代码
let obj = Object.create(null);
console.log(obj.__proto__); // undefined,它没有原型

这种对象不会继承任何东西,连 toString 这样的基本方法都没有。

2. 原型链的终点

所有对象的原型链最终都会指向 Object.prototype,而 Object.prototype.__proto__null,就像所有家族最终都能追溯到一个源头。 如图:

七、如何判断数据类型?

1. typeof 运算符

简单快速,但有一些局限性:

csharp 复制代码
typeof "hello"; // "string"(正确)
typeof 42;      // "number"(正确)
typeof true;    // "boolean"(正确)
typeof undefined; // "undefined"(正确)
typeof null;    // "object"(历史遗留问题)
typeof Symbol(); // "symbol"(正确)
typeof BigInt(1); // "bigint"(正确)
typeof {};      // "object"(正确,但分不清是普通对象还是数组)
typeof [];      // "object"(会把数组当成对象)
typeof function(){}; // "function"(正确)

2. instanceof 运算符

用于判断对象的具体类型,原理是检查构造函数的 prototype 是否在对象的原型链上:

javascript 复制代码
[] instanceof Array; // true(数组是 Array 的实例)
{} instanceof Object; // true(对象是 Object 的实例)
function(){} instanceof Function; // true(函数是 Function 的实例)

但它不能判断原始类型,比如 "hello" instanceof String 会返回 false

3. Object.prototype.toString

这是判断类型的 "万能钥匙",能精准识别所有类型:

javascript 复制代码
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call("hello"); // "[object String]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call({}); // "[object Object]"

通过这些核心概念的学习,你已经掌握了 JavaScript 的基础骨架。这些知识是理解更复杂概念(如闭包、异步、面向对象编程)的前提,打好基础才能在 JavaScript 的世界里游刃有余。

相关推荐
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
3Katrina7 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
coderlin_8 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
伍哥的传说8 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
我在北京coding8 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜8 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui
SevgiliD8 小时前
el-button传入icon用法可能会出现的问题
前端·javascript·vue.js
我在北京coding8 小时前
Element-Plus-全局自动引入图标组件,无需每次import
前端·javascript·vue.js
鱼 空8 小时前
解决el-table右下角被挡住部分
javascript·vue.js·elementui
小李飞飞砖9 小时前
React Native 组件间通信方式详解
javascript·react native·react.js