当前位置: 首页 > news >正文

JS构造函数与原型链详解

一、构造函数(完整代码示例)

构造函数就是一个普通函数,创建方式和普通函数没有区别,不同的是首字母习惯上大写。构造函数和普通函数的区别就是调用方式不同 普通函数直接调用fun(),构造函数需要使用new关键字来调用(var per=new Person();)

1. 构造函数与普通函数的区别(调用方式)
// 1. 普通函数(首字母小写,直接调用) function sayHello() { console.log("普通函数调用"); this.name = "普通函数"; // 非严格模式下this指向window } // 普通调用 sayHello(); // 输出:普通函数调用 console.log(window.name); // 输出:普通函数(验证this指向) // 2. 构造函数(首字母大写,new调用) function Person(name, age) { // 执行流程: // 1. 隐式创建新对象;2. this指向新对象;3. 执行代码;4. 返回新对象 this.name = name; this.age = age; this.sayHi = function() { console.log(`我是${this.name},今年${this.age}岁`); }; } // 构造函数调用(创建实例) const per1 = new Person("张三", 20); const per2 = new Person("李四", 22); console.log(per1); // 输出:Person { name: '张三', age: 20, sayHi: [Function] } per1.sayHi(); // 输出:我是张三,今年20岁 per2.sayHi(); // 输出:我是李四,今年22岁 // 3. instanceof检查实例归属 console.log(per1 instanceof Person); // 输出:true(per1是Person的实例) console.log(per1 instanceof Object); // 输出:true(所有对象都是Object的后代) console.log(per1 instanceof Array); // 输出:false(验证非Array实例)

构造函数的执行流程:

1、立刻创建一个新的对象

2、将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象

3、逐行执行构造函数中的代码

4、将新创建的对象作为返回值返回

使用同一个构造函数创建的对象属于同一类对象,我们也将一个构造函数称为一个类。通过一个构造函数创建的对象,称为该类的实例,也称为该构造函数的实例。

使用instanceof可以检查一个对象是否是一个类的实例

所有对象都是Object的后代

二、原型(prototype)(完整代码示例)

我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,叫原型对象,每个函数都有,都指向一个不同的原型对象。

如果函数作为普通函数调用,prototype没有任何作用;如果函数以构造函数形式调用时,它所创建的对象中都会有一个隐含的属性__proto__,指向该构造函数的原型对象,我们可以通过__proto__访问该属性。

原型对象就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象。我们可以将对象中共有的内容,统一设置到原型对象中。这样不用分别为每一个实例对象添加,也不会影响到全局作用域,就可以使每个对象中都有这些属性和方法。

1. 原型对象的基本使用(公共属性 / 方法)
// 构造函数 function Student(name, score) { this.name = name; // 实例自身属性 this.score = score; } // 原型对象添加公共方法(所有实例共享) Student.prototype.sayScore = function() { console.log(`${this.name}的成绩是${this.score}分`); }; // 原型对象添加公共属性 Student.prototype.school = "第一中学"; // 创建实例 const stu1 = new Student("小明", 90); const stu2 = new Student("小红", 85); // 访问实例自身属性 console.log(stu1.name); // 输出:小明(自身属性) // 访问原型对象的属性/方法 console.log(stu1.school); // 输出:第一中学(原型属性) stu2.sayScore(); // 输出:小红的成绩是85分(原型方法) // 验证:所有实例共享原型方法(内存复用) console.log(stu1.sayScore === stu2.sayScore); // 输出:true
2. 属性查找规则(自身 → 原型 → 原型的原型)

当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,有直接使用,如果没有会去原型对象中找,如果找到则直接使用

// 接上面的Student构造函数 // 1. 自身有属性,优先使用自身 stu1.score = 95; console.log(stu1.score); // 输出:95(自身覆盖原型) // 2. 自身无,找原型;原型无,找原型的原型;直到Object原型(null) console.log(stu1.toString()); // 输出:[object Object](来自Object.prototype) console.log(stu1.abc); // 输出:undefined(最终未找到)
3. in 与 hasOwnProperty 区别

使用in检查对象中是否含有某个属性时,如果对象中没有但是原型对象中有,也会返回true;

使用对象的hasOwnProperty("name"),检查对象自身中是否含有该属性,只有对象自身中有时才会返回true。

// 接上面的stu1实例 // 1. in:自身或原型有则返回true console.log("name" in stu1); // 输出:true(自身有) console.log("school" in stu1); // 输出:true(原型有) console.log("toString" in stu1); // 输出:true(Object原型有) // 2. hasOwnProperty:仅自身有则返回true console.log(stu1.hasOwnProperty("name")); // 输出:true(自身有) console.log(stu1.hasOwnProperty("school")); // 输出:false(原型有) console.log(stu1.hasOwnProperty("toString")); // 输出:false(Object原型有)
4. 原型链示例(多层原型查找)
// 自定义构造函数 function Animal(type) { this.type = type; } // Animal原型添加方法 Animal.prototype.eat = function() { console.log(`${this.type}会吃东西`); }; // Dog继承Animal(简化版,仅演示原型链) function Dog(name) { this.name = name; } // 将Dog的原型指向Animal的实例(形成原型链) Dog.prototype = new Animal("狗"); // 创建Dog实例 const dog1 = new Dog("旺财"); // 原型链查找: // dog1自身 → Dog.prototype(Animal实例) → Animal.prototype → Object.prototype → null console.log(dog1.name); // 自身:旺财 dog1.eat(); // Animal.prototype:狗会吃东西 console.log(dog1.toString()); // Object.prototype:[object Object] console.log(dog1.xxx); // 输出:undefined(最终未找到)

三、完整整合示例(构造函数 + 原型 + 原型链)

原型对象也是对象,所以它也有原型。当我们使用一个对象的属性或方法时,会先在自身中寻找。自身中如果有,直接使用;如果没有则去原型对象中找,如果原型对象中有,则直接使用;如果没有则去原型对象中的原型去找,直到找到Object对象的原型。Object对象的原型没有原型(对应的值为null),如果还没有找到则返回undefined。

// 1. 定义构造函数 function Car(brand, color) { // 实例自身属性 this.brand = brand; this.color = color; } // 2. 原型添加公共方法(所有Car实例共享) Car.prototype.run = function() { console.log(`${this.color}的${this.brand}正在行驶`); }; // 原型添加公共属性 Car.prototype.wheels = 4; // 3. 创建实例 const car1 = new Car("宝马", "白色"); const car2 = new Car("奔驰", "黑色"); // 4. 访问属性/方法 console.log(car1.brand); // 自身:白色 console.log(car1.wheels); // 原型:4 car2.run(); // 原型方法:黑色的奔驰正在行驶 // 5. 检查属性归属 console.log("wheels" in car1); // true(原型有) console.log(car1.hasOwnProperty("wheels")); // false(自身无) console.log(car1.hasOwnProperty("brand")); // true(自身有) // 6. 原型链验证 console.log(car1.__proto__ === Car.prototype); // true(实例的__proto__指向构造函数原型) console.log(Car.prototype.__proto__ === Object.prototype); // true(原型的原型指向Object原型) console.log(Object.prototype.__proto__); // null(Object原型无原型)

四、核心总结

  1. 构造函数通过new调用,自动创建 / 返回对象,this指向实例;
  2. 原型(prototype)是构造函数的属性,存储实例共享的属性 / 方法,减少内存占用;
  3. 属性查找遵循「自身 → 原型 → 原型链」规则,直到Object.prototype.__proto__(null);
  4. in检查整个原型链,hasOwnProperty仅检查实例自身。




http://www.cnnetsun.cn/news/93087.html

相关文章:

  • FreeMove终极指南:Windows文件迁移的革命性解决方案
  • FeHelper全能工具箱:前端开发效率提升终极指南
  • QQ空间历史说说完整备份指南:永久珍藏你的数字记忆
  • 十大MCP Server方案,让DevOps步入智能新时代
  • VUE3:深入浅出探究pinia、provide\inject在多层组件页面是怎么使用的
  • Molecular Operating Environment (MOE) 完整安装与配置指南
  • LobeChat能否用于生成直播话术?电商主播提词器
  • 终极C++网络编程:构建高性能HTTP服务的完整指南
  • 显卡驱动终极清理指南:一键彻底解决兼容性问题
  • Zotero GPT:用AI重新定义文献管理效率
  • LobeChat与LangChain结合应用:打造复杂AI工作流
  • 突破60帧束缚:原神性能优化工具深度解析
  • 云计算作业—-V L AN实验
  • 当连锁巡检“听懂人话”:VLM技术下的智能运营新场景
  • 责任链模式(Chain of Responsibility):实现事件或请求的逐级处理与传递
  • SMUDebugTool深度探索:解锁AMD Ryzen系统的隐藏性能
  • JavaScript 中的单例模式:利用闭包、IIFE 或 ES Modules 实现线程安全的单例
  • CORS 机制中的预检请求(Preflight Request):为什么 OPTIONS 请求总是先于复杂请求发送?
  • Google Drive文件下载终极指南:简单快速解决下载难题
  • 面对一个新领域,如何快速摸清门道?试试“一键生成”研究地图
  • 终极指南:5步实现全球付费内容免费阅读
  • GBase 8s数据库SYSTIMESTAMP表达式介绍(上)
  • 从“秒级”到“毫秒级”:金仓如何让InfluxDB的“时序神话”黯然失色?
  • zotero-style插件深度解析:从零打造高效文献管理生态
  • 5倍推理加速:Axolotl缓存策略如何终结重复计算瓶颈
  • LobeChat能否部署在华为云弹性云服务器?国产化替代实践
  • LobeChat备份与恢复策略:防止重要对话丢失
  • Access Token 生命周期管理:详细设计 Token 的获取、缓存、续期和过期处理机制
  • 客户群 ID 与业务 ID 映射:设计高性能数据库表结构,实现 ChatID 与内部业务标签的快速关联
  • 代码随想录算法训练营Day48 | 108.冗余连接、109.冗余连接II