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

js原型、原型链和继承

文章目录

  • 一、原型
    • 1、prototype
    • 2、constructor
  • 二、原型链
    • 1、字面量原型链
    • 2、字面量继承
    • 3、构造函数的原型链
    • 4、Object.create
    • 5、Object.setPrototypeOf
  • 三、继承
    • 1、构造函数继承
    • 2、原型链继承
    • 3、组合继承
  • 四、常见链条
    • 1、Function
    • 2、Object.prototype

继承是指将特性从父代传递给子代,以便新代码可以重用并基于现有代码的特性进行构建。JavaScript 使用对象实现继承。每个对象都有一条链接到另一个称作原型的对象的内部链。该原型对象有自己的原型,依此类推,直到原型是 null 的对象。

一、原型

1、prototype

  • 构造函数自带原型对象prototype,可以在prototype增加属性和方法,这样构造函数产生的实例可以共享这些属性和方法(如果实例上没有的话)
  • 实例__proto__属性指向最近的上级prototype(如果有继承),如果没有继承那么指向构造函数的prototype;__proto__在浏览器上显示的是[[Prototype]]
  • 注意原型对象prototype也是对象,他是被Object创建出来的
const ParentFun = function () {
  this.name = "张三";
};
ParentFun.prototype.getName = function () {
  return this.name;
};
const parentObj = new ParentFun();
parentObj.__proto__ === ParentFun.prototype // true

2、constructor

  • constructor其实依赖于prototype,只是prototype上的一个属性,指向构造函数本身(函数对象,函数也可以被认为是一个对象,可以挂载属性和方法)
  • 在原型链继承的时候,错误操作可能只顾着继承prototype,而丢失constructor属性
  • instanceof: a instanceof b会在链条往上查找prototype.constructor,看a的原型链上有没有b;逐级上查
const ParentFun = function () {
  this.name = "张三";
};
ParentFun.prototype.constructor === ParentFun // true
// 等同于;因为ParentFunObj默认往上查找一层就是ParentFun.prototype
ParentFunObj.constructor === ParentFun // true

const ParentFunObj = new ParentFun();
ParentFunObj instanceof ParentFun // true
ParentFunObj instanceof Object // true

二、原型链

1、字面量原型链

  • 注意对象中设置字面量{ proto: … },是被允许的、合理的;不合理是设置隐式原型obj.proto = …
const obj = {
  a: 1,
  // __proto__ 设置了 [[Prototype]]。在这里它被指定为另一个对象字面量。
  __proto__: {
    b: 2,
    __proto__: {
	   c: 3,
	},
  },
};
obj.a // 1
obj.b // 2
obj.c // 3

2、字面量继承

const parent = {
  value: 2,
  method() {
    return this.value + 1;
  }
};

// child 是一个继承了 parent 的对象
const child = {
  __proto__: parent
};

console.log(child.method()); // 3

// child ---> parent ---> Object.prototype ---> null

3、构造函数的原型链

function Constructor() {}

const obj = new Constructor();

// obj ---> Constructor.prototype ---> Object.prototype ---> null

4、Object.create

const a = { a: 1 };
// a ---> Object.prototype ---> null

const b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1(继承的)

5、Object.setPrototypeOf

const obj = { a: 1 };
const anotherObj = { b: 2 };
Object.setPrototypeOf(obj, anotherObj);
// obj ---> anotherObj ---> Object.prototype ---> null

三、继承

1、构造函数继承

  • call、apply都可以
  • 也可以使用class,本文案例未举例
const ParentFun = function () {
  this.name = "张三";
};
const ChildFun = function () {
  // 继承父类的属性和方法;构造函数继承;
  // 注意调用的时机,会决定实例的属性顺序;比如这里的name属性在age前面
  ParentFun.call(this);
  // 运行时this指向childFunc实例对象(的内存空间);
  this.age = 20;
};

2、原型链继承

  • Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype):给目标设置原型链的上一级;
  • Object.setPrototypeOf(ChildFun.prototype):获取该目标的原型链的上一级
  • Object.create(ParentFun.prototype):创建和返回新对象,设置该对象的原型链上一级
  • 原型链扩充,每次扩充都会形成上级和下级的二元链;链条可以被设置成连续不断一直到顶层null,也可以设置成短链
const ParentFun = function () {
  this.name = "张三";
};
const ChildFun = function () {
  // 继承父类的属性和方法;构造函数继承;
  // 注意调用的时机,会决定实例的属性顺序;比如这里的name属性在age前面
  ParentFun.call(this);
  // 运行时this指向childFunc实例对象(的内存空间);
  this.age = 20;
};
ParentFun.prototype.getName = function () {
  return this.name;
};
ChildFun.prototype.getAge = function () {
  return this.age;
};

const transferTemp = (Parent, Child) => {
  // 空的对象作为临时原型链;
  const Temp = () => {};
  Temp.prototype = Parent.prototype;
  Child.prototype = new Temp();
  Child.prototype.constructor = Child;
};

const transferCreat = (Parent, Child) => {
  // Object.create本身就会返回一个空对象,该对象的__proto__指向Parent.prototype;
  Child.prototype = Object.create(Parent.prototype);
  // 覆盖prototype以后会丢失constructor,需要重新赋值;
  // constructor在一些判断中可能被用到
  // prototype在此之前设置的其他属性也会消失(比如getAge)
  Child.prototype.constructor = Child;
};

// 注意原型链继承方式的区别
// 1
// ChildFun.prototype = new ParentFun();
// 2 废弃但可用;__proto__ 赋值只会接受对象,其他值会被忽略
// ChildFun.prototype.__proto__ = ParentFun.prototype;
// 3 推荐 安全有效,没有中转对象
// Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype);
// 4 使用中转对象
// transferTemp(ParentFun, ChildFun);
// 5 使用中转对象
// transferCreat(ParentFun, ChildFun);

3、组合继承

const ParentFun = function () {
  this.name = "张三";
};
const ChildFun = function () {
  // 继承父类的属性和方法;构造函数继承;
  // 注意调用的时机,会决定实例的属性顺序;比如这里的name属性在age前面
  ParentFun.call(this);
  // 运行时this指向childFunc实例对象(的内存空间);
  this.age = 20;
};
ParentFun.prototype.getName = function () {
  return this.name;
};
ChildFun.prototype.getAge = function () {
  return this.age;
};

// 自定义Object.keys方法   用于获取对象所有属性名
Object.prototype.keysCustom = function (obj) {
  if (typeof obj !== "object" || obj === null) {
    return;
  }
  const result = []; // 用于存储结果
  for (let key in obj) {
    // hasOwnProperty表示自身的属性,不包括原型链上的属性
    if (obj.hasOwnProperty(key)) {
      // 相当于循环后存储key
      result.push(key);
    }
  }
  return result;
};

Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype);

const childObj = new ChildFun();

const keysAll = [];
const keysOwn = [];
for (let key in childObj) {
  // 自己的属性和原型链上的属性都会遍历出来;
  // 原型链继承的所有属性 + Object.prototype 挂载的自定义方法
  keysAll.push(key);
  if (childObj.hasOwnProperty(key)) {
    // 自己的属性才会遍历出来;
    keysOwn.push(key);
  }
}
// console.log("Object.keysCustom", keysAll, keysOwn, childObj); // TEST
// 结果:keysAll = ["name", "age", "getName", "keysCustom"];
// 结果: keysOwn = ["name", "age"];

// childObj ---> ChildFun.prototype ---> ParentFun.prototype ---> Object.prototype ---> null

四、常见链条

1、Function

  • Function是所有常见构造函数的源头,甚至他自己也被自己创造
  • 只要是构造函数都归Function管理,包括自定义的函数
// Function创造自己
Object.getPrototypeOf(Function) === Function.prototype // true
// 常规构造函数
Object.getPrototypeOf(Object) === Function.prototype // true
Object.getPrototypeOf(Array) === Function.prototype // true
// 自定义构造函数
const temp =() => {}
Object.getPrototypeOf(temp) === Function.prototype // true

2、Object.prototype

  • 只要是对象都归Object管理,包括prototype对象,当然有例外:Object.prototype
// 常规构造函数的prototype;上一级就是Object.prototype
Object.getPrototypeOf(Function.prototype) === Object.prototype // true
Object.getPrototypeOf(Array.prototype) === Object.prototype // true
// 链条顶层被null强制了
Object.getPrototypeOf(Object.prototype) === Object.prototype // false
Object.getPrototypeOf(Object.prototype) === null // true

http://www.kler.cn/a/418574.html

相关文章:

  • Git忽略文件
  • C++练级计划-> 《IO流》iostream fstream sstream详解
  • 基于Matlab实现三维点坐标生成点云(源码+数据)
  • RPM与YUM:Linux包管理工具的区别与常用命令
  • facebook欧洲户开户条件有哪些又有何优势?
  • 【机器学习】入门机器学习:从理论到代码实践
  • go语言的成神之路-筑基篇-gin框架渲染模板
  • 《datawhale2411组队学习 模型压缩技术7:NNI剪枝》
  • Angular v19 (三):增量水合特性详解 - 什么是水合过程?有哪些应用场景?与 Qwik 相比谁更胜一筹?- 哪个技术好我就学哪个,这就是吸心大法吧
  • 使用 client-go 实现 Kubernetes 节点 Drain:详解与实战教程
  • C_接口函数
  • 特性标记清理:GitHub Actions 来帮忙!
  • colorthief.js(图像中自动提取出主色调、调色板或者平均颜色)源码解析MMCQ算法
  • SnowFlake
  • 如何正确使用 GitHub API 获取特定版本信息:详解错误排查与解决方案
  • Word - 图片右键保存
  • Scala关于成绩的常规操作
  • 华为云云连接+squid进行正向代理上网冲浪
  • 【RabbitMQ 消息列队测试之:调试技巧】
  • 【Python数据分析五十个小案例】使用自然语言处理(NLP)技术分析 Twitter 情感
  • 初级数据结构——邻接表
  • 使用图结构增强RAG架构,一文详解LightRAG
  • docker安装clickhouse(单机版)
  • 解决Qt堆栈窗口内子窗口大小不一致的问题
  • HTML5+JavaScript实现消消乐游戏
  • Flask项目入门—request以及Response