JavaScript 中的原型与继承 一、从对象说起, 一切皆对象在 JS 中, 几乎所有的东西都是对象, 或者说最终都会指向某个对象. 比如:let arr [1,2,3];console.log(typeof arr);//objectfunctionfoo() {}console.log(typeof foo);//function (但本质上也是对象)简单的对象创建:let person {name:张三,age:25,sayHi:function() {console.log(你好我是 this.name);}};person.sayHi();// 你好, 我是张三但这样有个问题——每次创建新对象都要写一遍所有属性和方法, 太麻烦了! 于是我们有了后面的构造函数. 二、构造函数对象的工厂functionPerson(name, age) {this.name name;this.age age;this.sayHi function() {console.log(你好, 我是 this.name);};}let person1 newPerson(张三,25);let person2 newPerson(李四,30);person1.sayHi();// 你好, 我是张三person2.sayHi();// 你好, 我是李四这里有几个关键点:1. 函数名通常大写开头这是约定俗成的构造函数命名方式2. 使用new关键字调用3. 函数内部使用this来指代新创建的对象当你使用new调用函数时背后发生了这些事:1. 创建一个全新的空对象2. 将这个空对象的__proto__指向构造函数的prototype属性3. 将构造函数中的this绑定到这个新对象4. 执行构造函数中的代码5. 如果构造函数没有显式返回对象则返回这个新对象三、原型登场上面的构造函数方式有个问题——每个实例都会创建自己的方法副本, 浪费内存, 这时候原型(prototype)就派上用场了!什么是原型?每个函数都有一个prototype属性, 它指向一个对象. 当使用这个函数作为构造函数创建实例时, 所有实例都会共享这个原型对象上的属性和方法.改进版的 Person:functionPerson(name, age) {this.name name;this.age age;}// 将方法放在原型上Person.prototype.sayHi function() {console.log(你好我是 this.name);};let person1 newPerson(张三,25);let person2 newPerson(李四,30);console.log(person1.sayHi person2.sayHi);// true - 现在方法是共享的了什么是原型链?当我们访问一个对象的属性时, JavaScript 会:1. 先在对象自身属性中查找2. 如果没找到, 就去对象的__proto__(即构造函数的prototype) 中查找3. 如果还没找到, 就继续往__proto__.__proto__中查找4. 直到找到Object.prototype(最顶层的原型它的__proto__是null)这就是原型链, JavaScript的继承机制.functionPerson() {}Person.prototype.species 人类;let p newPerson();console.log(p.species);//人类 - 从原型上找到的console.log(p.__proto__ Person.prototype);// trueconsole.log(Person.prototype.__proto__ Object.prototype);// trueconsole.log(Object.prototype.__proto__);// null如果对象自身有属性, 就不会去原型上找了:p.species 地球人;console.log(p.species);//地球人 - 自身的属性console.log(Person.prototype.species);//人类 - 原型上的没变delete p.species;console.log(p.species);//人类 - 删除自身属性后又从原型上找到了四、几种继承的方式1)原型链继承:functionParent() {this.parentProp 父类属性;}Parent.prototype.parentMethod function() {console.log(父类方法);};functionChild() {this.childProp 子类属性;}// 关键点: 子类的原型指向父类的实例Child.prototype newParent();let child newChild();console.log(child.childProp);// 子类属性console.log(child.parentProp);// 父类属性-通过原型链找到的child.parentMethod();// 父类方法问题:所有子类实例共享同一个父类实例的属性(如果是引用类型就麻烦了)创建子类实例时无法向父类构造函数传参2)构造函数继承:functionParent(name) {this.name name;this.colors [red,blue];}functionChild(name, age) {Parent.call(this, name);//关键点:在子类构造函数中调用父类构造函数this.age age;}let child1 newChild(张三,25);child1.colors.push(green);let child2 newChild(李四,30);console.log(child2.colors);//[red, blue]-不受child1影响优点:1. 避免了引用类型属性被所有实例共享2. 可以在子类中向父类传参缺点:方法都在构造函数中定义每次创建实例都会创建一遍方法不能继承父类原型上的方法3)组合继承:结合原型链继承和构造函数继承的优点:functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);//第二次调用Parentthis.age age;}Child.prototype newParent();//第一次调用ParentChild.prototype.constructor Child;//修复constructor指向Child.prototype.sayAge function() {console.log(this.age);};let child1 newChild(张三,25);child1.colors.push(green);child1.sayName();//张三child1.sayAge();//25let child2 newChild(李四,30);console.log(child2.colors);//[red, blue]4)寄生组合继承:functioninheritPrototype(child, parent) {let prototype Object.create(parent.prototype);// 创建父类原型的副本//Object.create 是创建以指定对象为原型的新对象的方法prototype.constructor child;// 修复constructorchild.prototype prototype;// 将副本作为子类的原型}functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);this.age age;}// 关键: 使用我们封装的inheritPrototype函数inheritPrototype(Child,Parent);Child.prototype.sayAge function() {console.log(this.age);};let child newChild(张三,25);child.sayName();// 张三child.sayAge();// 25优点:1. 只调用一次父类构造函数2. 子类原型上不会有多余的父类属性3. 原型链保持不变五、ES6的classES6 引入了class语法, 让面向对象编程更加直观:classParent {constructor(name) {this.name name;this.colors [red,blue];}sayName() {console.log(this.name);}}classChildextendsParent {constructor(name, age) {super(name);// 必须在使用this之前调用superthis.age age;}sayAge() {console.log(this.age);}}let child newChild(张三,25);child.sayName();// 张三child.sayAge();// 25class本质上仍然是基于原型的语法糖. 上面的代码大致相当于:functionParent(name) {this.name name;this.colors [red,blue];}Parent.prototype.sayName function() {console.log(this.name);};functionChild(name, age) {Parent.call(this, name);this.age age;}Child.prototype Object.create(Parent.prototype);Child.prototype.constructor Child;Child.prototype.sayAge function() {console.log(this.age);};class还提供了静态方法和属性的简洁写法:classMyClass {staticstaticMethod() {console.log(我是静态方法);}static staticProperty 我是静态属性;}MyClass.staticMethod();//我是静态方法console.log(MyClass.staticProperty);//我是静态属性六、其他相关内容instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上.functionmyInstanceof(instance, constructor) {let proto Object.getPrototypeOf(instance);while (proto) {if (proto constructor.prototype) {returntrue;}proto Object.getPrototypeOf(proto);}returnfalse;}console.log([]instanceofArray);// trueconsole.log(myInstanceof([],Array));// true原型可以被修改, 这可能导致安全问题:// 不要这样做Object.prototype.hack function() {console.log(被黑了);};let obj {};obj.hack();// 被黑了

相关新闻

最新新闻

LangChain记忆系统实战:从短期对话到长期知识库的AI应用架构

LangChain记忆系统实战:从短期对话到长期知识库的AI应用架构

1. 项目概述:从“健忘”到“博闻强识”的AI应用进化最近在折腾LangChain,一个绕不开的核心议题就是“记忆”。你肯定遇到过这种情况:你跟一个AI助手聊得正嗨,问它“我刚才提到的项目截止日期是哪天?”,它却…

2026/7/18 1:59:34
DICOM到NIfTI转换终极指南:dcm2niix完整使用与优化技巧

DICOM到NIfTI转换终极指南:dcm2niix完整使用与优化技巧

DICOM到NIfTI转换终极指南:dcm2niix完整使用与优化技巧 【免费下载链接】dcm2niix dcm2nii DICOM to NIfTI converter: compiled versions available from NITRC 项目地址: https://gitcode.com/gh_mirrors/dc/dcm2niix 在神经影像和医学影像研究领域&#x…

2026/7/18 1:59:34
HTTP状态码详解:从基础概念到最佳实践

HTTP状态码详解:从基础概念到最佳实践

1. HTTP状态码基础概念HTTP状态码是服务器对客户端请求的响应标识,由三位数字组成,用于快速传达请求处理结果。这些代码遵循RFC 2616规范,并在RFC 7231中得到更新。状态码的第一个数字定义了响应类别,后两位提供具体细节。状态码的…

2026/7/18 1:59:34
5分钟快速指南:用OpCore-Simplify图形化工具轻松搞定黑苹果EFI配置

5分钟快速指南:用OpCore-Simplify图形化工具轻松搞定黑苹果EFI配置

5分钟快速指南:用OpCore-Simplify图形化工具轻松搞定黑苹果EFI配置 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的黑苹果配置…

2026/7/18 1:59:34
PowerToys 0.95.1自动主题切换功能解析与优化

PowerToys 0.95.1自动主题切换功能解析与优化

1. PowerToys 0.95.1 更新内容解析微软最新发布的 PowerToys 0.95.1 版本主要修复了"自动切换深/浅主题"功能的若干问题。这个看似简单的功能更新,实际上解决了不少用户在日常使用中的痛点。1.1 自动主题切换功能的核心改进本次更新重点修复了 Light Swit…

2026/7/18 1:59:34
从爬楼梯算法到Cassie机器人楼梯行走:动态规划的物理世界进阶

从爬楼梯算法到Cassie机器人楼梯行走:动态规划的物理世界进阶

1. 从“爬楼梯”到“Cassie下楼梯”:一个动态规划的经典与进阶如果你接触过算法,大概率听说过“爬楼梯”这道经典的动态规划入门题。题目很简单:假设你每次可以爬1级或2级台阶,爬到第n级台阶有多少种不同的方法?很多教…

2026/7/18 1:54:33

月新闻