JS必须过的槛--原型链,看完直接懂了!!

大家好呀,这是我的第一篇文章用于总结我的所学,可能有不对的地方,请大佬们多多见谅!!!

引言

原型链是JavaScript独特的核心继承机制,不依赖类的定义,而是通过对象间的原型关联,贯穿对象创建、属性查找、继承实现的全流程,是JS面向对象编程的底层逻辑支撑。

理解原型链是我们在JS的里程碑,不仅是其能帮助我们突破"面向对象编程"的认知瓶颈,掌握对象复用、继承对象复用、继承设计的核心思路,还能精准规避开发中原型污染。继承属性冲突等常见漏洞。所以接下来我会聊一下它的原理以及深入的一些东西。

原型链的底层认识

原型链的核心是js中对象与构造函数、原型对象之间的关联机制,这是js中面向对象特性的基石,所以我会从概念、形成、特性、示例四个维度去剖析:

基础认知

以下是一些基础的定义:

  • 原型对象(prototype) :仅构造函数(如 Function、自定义构造函数)自带的属性,本质是一个普通对象。用于存储该构造函数所有实例共享的方法和属性,减少内存占用(无需每个实例重复创建相同方法)。
  • 实例的隐式原型(proto :所有对象(包括实例、原型对象、构造函数)天生自带的属性,指向其 "创建者"(构造函数)的 prototype。ES6 推荐用 Object.getPrototypeOf(实例) 替代 __proto__(后者是非标准属性,存在兼容性风险)。
  • 构造函数(constructor) :原型对象(prototype)上的默认属性,指向该原型对象对应的构造函数。用于标识对象的 "创建来源",可通过 实例.constructor 追溯其构造函数。

三者的关系:实例通过 __proto__ 关联构造函数的 prototype,原型对象通过 constructor 反向关联构造函数,形成 "实例→原型对象→构造函数" 的三角闭环,即:实例.__proto__ === 构造函数.prototype构造函数.prototype.constructor === 构造函数

AI绘图:

原型链的出生以及找它的规则

原型链的本质是 "对象原型的链式关联",其形成逻辑与属性查找规则直接决定了 JS 的继承行为:

形成逻辑

  1. 实例的 __proto__ 指向其构造函数的 prototype(如 const obj = new Fn(),则 obj.__proto__ = Fn.prototype);
  2. 构造函数的 prototype 本身是对象,它也有 __proto__,指向其父构造函数的 prototype(如 Fn.prototype.__proto__ = Object.prototype,因 Fn.prototypeObject 的实例);
  3. 以此类推,层层向上追溯,直到 Object.prototype__proto__ 指向 null(无更高层级原型),最终形成 "实例→子原型→父原型→...→Object.prototype→null" 的链状结构,即原型链。 小见解:可以把他具象化为梯子,逐级向上;

查找规则(委托机制)

当访问对象的某个属性 / 方法时,JS 会遵循 "就近原则" 的委托查找逻辑:

  1. 优先查找对象自身属性 (通过对象字面量定义、this.xxx 赋值的属性);
  2. 若自身不存在,沿 __proto__ 向上遍历原型链,依次查找各层级原型对象上的属性;
  3. 找到匹配属性 / 方法则立即返回,若遍历至 null 仍未找到,返回 undefined

原型链的 "终点与特性"

终点:Object.prototype.__proto__ = null

  • Object 是 JavaScript 中所有对象的 "顶层构造函数",其原型对象 Object.prototype 是原型链的最顶层节点;
  • 为避免无限循环查找,Object.prototype.__proto__ 被设计为 null,表示 "无更高层级原型",是原型链的最终终点。

核心特性

  • 继承性 :所有实例可共享其原型链上所有原型对象的属性和方法,无需重复定义,是 JS 实现继承的核心原理(如数组实例可调用 Array.prototype.push(),也可调用 Object.prototype.toString())。
  • 委托机制 :属性查找是 "委托查找" 而非 "复制",原型链上的属性 / 方法仅存储在原型对象中,实例通过 __proto__ 委托访问,修改原型会影响所有关联实例(如修改 Array.prototype 的方法,所有数组实例都会受影响)。
  • 单向性:原型链仅支持 "向上查找",无法向下查找(如父原型无法访问子原型或实例的属性)。

下面是一些示例,可以直接运行去控制台看看:

js 复制代码
// 1. 定义构造函数
function Animal(type) {
  this.type = type; // 实例自身属性
}
// 2. 给构造函数的原型添加方法(共享方法)
Animal.prototype.sayType = function() {
  console.log(`类型:${this.type}`);
};
// 3. 创建实例
const dog = new Animal("犬科");

// 4. 打印原型链关系
console.log("dog.__proto__ === Animal.prototype:", dog.__proto__ === Animal.prototype); // true
console.log("Animal.prototype.__proto__ === Object.prototype:", Animal.prototype.__proto__ === Object.prototype); // true
console.log("Object.prototype.__proto__:", Object.prototype.__proto__); // null
console.log("dog.constructor === Animal:", dog.constructor === Animal); // true(原型对象的constructor指向构造函数)

// 5. 验证属性查找
dog.sayType(); // 输出"类型:犬科"(委托原型链查找方法)
console.log(dog.toString()); // 输出"[object Object]"(委托Object.prototype的方法)

深入应用:原型链的 "实战场景"

原型链并非抽象概念,而是 JavaScript 开发中实现继承、优化性能、封装逻辑的核心工具。以下从继承实现、实际场景、避坑技巧三个维度,拆解其落地应用:


原型链与继承实现(开发核心)

JavaScript 无原生 "类继承",所有继承行为均基于原型链实现。以下是四种核心继承方案的原理、代码示例与优劣分析:

原型链继承(最基础)

核心逻辑:直接让子类原型指向父类实例,使子类实例通过原型链访问父类的属性和方法。

js 复制代码
// 父类
function Animal(name) {
  this.name = name;
  this.features = ["呼吸", "进食"]; // 引用类型属性
}
Animal.prototype.sayName = function() {
  console.log(`我是 ${this.name}`);
};

// 子类
function Dog() {}
Dog.prototype = new Animal(); // 子类原型指向父类实例(核心)
Dog.prototype.constructor = Dog; // 修复 constructor 指向

// 测试
const dog1 = new Dog();
dog1.name = "旺财";
dog1.features.push("汪汪叫");
const dog2 = new Dog();
console.log(dog2.features); // 输出 ["呼吸", "进食", "汪汪叫"](共享属性被污染)

优点 :实现简单,直接继承父类原型的方法。缺点:1. 父类引用类型属性被所有子类实例共享,易污染;2. 子类实例创建时无法向父类构造函数传参。

组合继承(最常用)

核心逻辑:结合 "构造函数继承"(传参、独立属性)和 "原型链继承"(共享方法),互补优缺点。

js 复制代码
// 父类
function Animal(name) {
  this.name = name;
  this.features = ["呼吸", "进食"];
}
Animal.prototype.sayName = function() {
  console.log(`我是 ${this.name}`);
};

// 子类
function Dog(name, breed) {
  Animal.call(this, name); // 构造函数继承:传参+独立属性(第一次调用父类构造)
  this.breed = breed;
}
Dog.prototype = new Animal(); // 原型链继承:共享方法(第二次调用父类构造)
Dog.prototype.constructor = Dog;
Dog.prototype.sayBreed = function() {
  console.log(`品种:${this.breed}`);
};

// 测试
const dog1 = new Dog("旺财", "柯基");
dog1.features.push("汪汪叫");
const dog2 = new Dog("小白", "柴犬");
console.log(dog2.features); // 输出 ["呼吸", "进食"](属性独立)
dog2.sayName(); // 输出 "我是 小白"(方法共享)

优点 :解决传参和属性污染问题,方法共享高效。缺点 :父类构造函数被执行两次,子类原型上存在冗余的父类属性(如 namefeatures)。

寄生组合继承(最优方案)

核心逻辑 :通过 Object.create 创建父类原型的副本,替代 "子类原型指向父类实例",避免父类构造函数重复执行。

js 复制代码
// 父类
function Animal(name) {
  this.name = name;
  this.features = ["呼吸", "进食"];
}
Animal.prototype.sayName = function() {
  console.log(`我是 ${this.name}`);
};

// 子类
function Dog(name, breed) {
  Animal.call(this, name); // 仅调用一次父类构造
  this.breed = breed;
}
// 关键:创建父类原型的空副本,作为子类原型(避免执行父类构造)
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.sayBreed = function() {
  console.log(`品种:${this.breed}`);
};

// 测试
const dog = new Dog("旺财", "柯基");
dog.sayName(); // 输出 "我是 旺财"
console.log(dog.__proto__.__proto__ === Animal.prototype); // true(原型链正常)

优点 :继承逻辑完整,无冗余属性,性能最优,是 ES6 前推荐方案。缺点 :实现稍复杂(需手动修复 constructor)。

ES6 Class 与原型链的关系

核心结论class 是原型链继承的语法糖,底层仍依赖原型链机制,仅简化写法。

ES6 Class 语法 对应的原型链逻辑
class Child extends Parent Child.prototype.__proto__ = Parent.prototype
constructor() { super() } Parent.call(this, ...args)(调用父类构造)
class 原型方法 挂载到 Child.prototype 上(共享方法)

代码对应示例

js 复制代码
// ES6 Class 写法
class Animal {
  constructor(name) {
    this.name = name;
  }
  sayName() { // 挂载到 Animal.prototype
    console.log(`我是 ${this.name}`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 对应 Animal.call(this, name)
    this.breed = breed;
  }
  sayBreed() { // 挂载到 Dog.prototype
    console.log(`品种:${this.breed}`);
  }
}

// 底层原型链验证
const dog = new Dog("旺财", "柯基");
console.log(dog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true(extends 对应原型链指向)

实际开发中的原型链应用

原型链在开发中无处不在,以下是高频场景的落地实践:

场景 1:对象复用与优化(减少内存占用)

核心思路:将公共方法存入构造函数原型,而非实例自身,所有实例共享同一方法,降低内存消耗。

js 复制代码
// 反例:每个实例都创建独立方法(内存浪费)
function Person(name) {
  this.name = name;
  this.sayHi = function() { // 每个实例都有独立的 sayHi 方法
    console.log(`Hi, ${this.name}`);
  };
}

// 正例:原型共享方法(所有实例复用同一方法)
function Person(name) {
  this.name = name;
}
Person.prototype.sayHi = function() { // 仅存储在 Person.prototype 中
  console.log(`Hi, ${this.name}`);
};

const p1 = new Person("张三");
const p2 = new Person("李四");
console.log(p1.sayHi === p2.sayHi); // true(方法复用)

场景 2:原生对象的原型扩展(谨慎使用)

核心思路 :可给原生对象(如 ArrayObject)原型添加工具方法,但严禁修改原生方法,避免全局污染。

js 复制代码
// 安全扩展:添加自定义工具方法(不覆盖原生)
Array.prototype.myFilter = function(callback) {
  const result = [];
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) result.push(this[i]);
  }
  return result;
};

const arr = [1, 2, 3];
console.log(arr.myFilter(item => item > 1)); // 输出 [2, 3]

// 危险操作:修改原生方法(导致全局异常)
Array.prototype.push = function() {
  console.log("被篡改了");
};
arr.push(4); // 输出 "被篡改了",无法正常添加元素

替代方案 :封装独立工具函数(如 arrayUtil.filter),而非扩展原生原型。

场景 3:原型链与闭包的结合(封装私有属性)

核心思路:利用闭包隐藏私有属性,通过原型暴露公有方法,兼顾封装性和复用性。

js 复制代码
function Person(name, age) {
  // 闭包私有属性(外部无法直接访问)
  const _privateProp = "私有值";
  
  this.name = name;
  this.age = age;
  
  // 闭包私有方法
  function _privateMethod() {
    return _privateProp;
  }
  
  // 公有方法(通过原型暴露,可访问闭包属性)
  Person.prototype.getPrivate = function() {
    return _privateMethod();
  };
}

const p = new Person("张三", 20);
console.log(p._privateProp); // undefined(无法访问私有属性)
console.log(p.getPrivate()); // 输出 "私有值"(通过公有方法访问)

场景 4:框架中的原型链应用

  • Vue 组件的原型继承 :Vue 实例的方法(如 $emit$watch)均挂载在 Vue.prototype 上,所有组件实例通过原型链继承这些方法。

    js 复制代码
    // 全局挂载工具方法(所有组件可访问)
    Vue.prototype.$utils = {
      formatTime: (time) => new Date(time).toLocaleString()
    };
    // 组件中使用(通过原型链查找)
    export default {
      mounted() {
        console.log(this.$utils.formatTime(Date.now()));
      }
    };
  • jQuery 的链式调用 :jQuery 实例的方法(如 findcss)执行后返回 this(实例本身),而这些方法均存储在 jQuery.prototype 上,通过原型链实现链式调用。

    js 复制代码
    // jQuery 核心逻辑简化
    function jQuery(selector) {
      this.elements = document.querySelectorAll(selector);
    }
    jQuery.prototype.css = function(key, value) {
      this.elements.forEach(el => el.style[key] = value);
      return this; // 返回实例,支持链式调用
    };
    jQuery.prototype.find = function(selector) {
      // 逻辑实现...
      return this;
    };
    // 链式调用(基于原型链的方法复用)
    new jQuery("div").css("color", "red").find("span").css("font-size", "16px");

##开发避坑:原型链的 "常见问题"

原型污染(最危险)

定义 :修改原生对象(如 ObjectArray)的原型,导致所有继承自该原型的对象受影响,引发全局异常。污染案例

js 复制代码
// 恶意修改 Object 原型
Object.prototype.toString = function() {
  return "被污染了";
};

// 正常业务代码受影响
const obj = { name: "张三" };
console.log(obj.toString()); // 输出 "被污染了"(预期输出 "[object Object]")

解决方案

  1. 禁止直接修改原生对象原型,使用 Object.create(null) 创建无原型的纯净对象;
  2. 冻结原生原型:Object.freeze(Object.prototype),禁止修改;
  3. 使用命名空间隔离自定义方法(如 myUtil.toString 而非 Object.prototype.toString)。

属性查找陷阱

陷阱 1:自身属性与原型属性重名

  • 规则:自身属性优先级高于原型属性,修改自身属性不影响原型。
js 复制代码
function Person() {}
Person.prototype.name = "默认名";
const p = new Person();
p.name = "张三"; // 自身属性
console.log(p.name); // 输出 "张三"(优先自身)
delete p.name; // 删除自身属性
console.log(p.name); // 输出 "默认名"(原型属性)

陷阱 2:delete 无法删除原型上的属性

  • 规则:delete 仅能删除对象自身属性,无法删除原型链上的属性。
js 复制代码
function Person() {}
Person.prototype.name = "默认名";
const p = new Person();
delete p.name; // 无效果(name 是原型属性)
console.log(p.name); // 输出 "默认名"

继承漏洞(共享属性污染)

问题:子类原型若直接引用父类原型对象,修改子类原型会同步修改父类原型,影响所有父类实例。

javascript 复制代码
// 问题代码
function Parent() {}
Parent.prototype.info = { age: 20 };
function Child() {}
Child.prototype = Parent.prototype; // 直接引用(共享同一对象)

Child.prototype.info.age = 30; // 修改子类原型的属性
const parent = new Parent();
console.log(parent.info.age); // 输出 30(父类实例受影响)

解决方案

  1. 使用 Object.create 创建父类原型的副本(浅拷贝);
  2. 若原型上有引用类型属性,使用深拷贝隔离:Child.prototype = JSON.parse(JSON.stringify(Parent.prototype))

面试拷打:原型链高频考点与实战

原型链是前端面试 "必考题",以下从概念、代码、编程三个维度,拆解考点与答题思路:


面试题分类解析(带思路 + 答案)

概念理解题(基础必问)

问题 1:请解释原型链的定义,以及 prototype__proto__constructor 的关系。

答题思路 :先定义原型链,再分别解释三个概念,最后总结三角关系。答案

  • 原型链:JavaScript 中对象通过 __proto__ 关联原型对象,原型对象再通过 __proto__ 关联父原型,层层向上直到 Object.prototype.__proto__ = null,形成的链状结构,是继承的核心机制。
  • 关系:① prototype 是构造函数的属性,存储实例共享的方法 / 属性;② __proto__ 是所有对象的隐式原型,指向其构造函数的 prototype;③ constructor 是原型对象的属性,指向对应的构造函数。
  • 核心等式:实例.__proto__ === 构造函数.prototype构造函数.prototype.constructor === 构造函数
问题 2:ES6 的 class 和 ES5 的原型链继承有什么区别?class 本质是什么?

答题思路 :先说明 "语法糖" 本质,再对比写法差异,最后强调底层一致。答案

  • 区别:① 写法不同:classclassextendssuper 等关键字,更简洁;ES5 需手动操作原型和构造函数。② 特性差异:class 构造函数必须用 new 调用,ES5 构造函数可直接调用(易出错);class 方法不可枚举,ES5 原型方法默认可枚举。
  • 本质:class 是原型链继承的语法糖,底层仍依赖 prototype__proto__ 实现继承,extends 对应原型链指向,super 对应父类构造函数调用。
问题 3:Object.prototypeFunction.prototype 的关系是什么?

答题思路 :明确两者的原型链关联,结合 "所有构造函数都是 Function 实例" 分析。答案

  • Function.prototype.__proto__ === Object.prototypeFunction.prototype 是对象,其隐式原型指向顶层对象原型 Object.prototype
  • 特殊点:Function 既是构造函数也是对象,Function.__proto__ === Function.prototype(自引用),而 Object 作为构造函数,Object.__proto__ === Function.prototype(所有构造函数都是 Function 的实例)。

代码分析题(考察查找逻辑)

示例 1:分析以下代码输出结果,并说明原因。
js 复制代码
function Fn() {
  this.a = 1;
  this.b = function() {
    console.log("自身方法");
  };
}
Fn.prototype.b = function() {
  console.log("原型方法");
};
Fn.prototype.c = function() {
  console.log("原型方法 c");
};

const f = new Fn();
console.log(f.a); // 输出?
f.b(); // 输出?
f.c(); // 输出?
delete f.b;
f.b(); // 输出?

答题思路 :按 "自身属性→原型属性" 的查找规则分析,逐步拆解。答案

  1. console.log(f.a):输出 1a 是实例自身属性);
  2. f.b():输出 自身方法(自身 b 方法优先级高于原型 b 方法);
  3. f.c():输出 原型方法 cc 是原型属性,自身无);
  4. delete f.b 后调用 f.b():输出 原型方法(删除自身 b 方法,沿原型链查找)。
以下代码是否存在原型污染?若有,会导致什么问题?
js 复制代码
function merge(target, source) {
  for (let key in source) {
    if (typeof source[key] === "object") {
      merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}

merge({}, { __proto__: { toString: () => "污染" } });
console.log({}.toString()); // 输出?

答题思路 :判断是否修改原生对象原型,分析影响范围。答案

  • 存在原型污染。merge 函数遍历 source 的键时,会遍历到 __proto__(原型属性),并修改 target__proto__,即 Object.prototype
  • 后果:所有对象的 toString 方法被篡改,{}.toString() 输出 污染,导致全局代码异常。

编程题(考察实战能力)

题目 1:用原型链实现 "动物→狗→柯基" 的三层继承,要求柯基实例能调用狗和动物的方法,且可传参初始化属性。

答题思路 :用寄生组合继承实现三层继承,确保每层构造函数可传参,方法共享。答案

js 复制代码
// 1. 顶层父类:动物
function Animal(type) {
  this.type = type; // 动物类型
}
Animal.prototype.sayType = function() {
  console.log(`动物类型:${this.type}`);
};

// 2. 子类:狗(继承动物)
function Dog(type, breed) {
  Animal.call(this, type); // 传参给父类
  this.breed = breed; // 狗的品种
}
// 寄生组合继承:继承动物的原型方法
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.sayBreed = function() {
  console.log(`狗的品种:${this.breed}`);
};

// 3. 孙类:柯基(继承狗)
function Corgi(type, breed, name) {
  Dog.call(this, type, breed); // 传参给父类(狗)
  this.name = name; // 柯基名字
}
// 寄生组合继承:继承狗的原型方法
Corgi.prototype = Object.create(Dog.prototype);
Corgi.prototype.constructor = Corgi;
Corgi.prototype.sayName = function() {
  console.log(`柯基名字:${this.name}`);
};

// 测试
const corgi = new Corgi("哺乳动物", "柯基", "旺财");
corgi.sayType(); // 输出 "动物类型:哺乳动物"(继承动物)
corgi.sayBreed(); // 输出 "狗的品种:柯基"(继承狗)
corgi.sayName(); // 输出 "柯基名字:旺财"(自身方法)
题目 2:封装一个工具函数,判断一个对象的属性是 "自身属性" 还是 "原型链上的属性"。

答题思路 :用 hasOwnProperty 判断自身属性,结合 in 运算符判断原型链属性。答案

js 复制代码
/**
 * 判断对象属性的来源
 * @param {Object} obj - 目标对象
 * @param {string} key - 属性名
 * @returns {string} - "自身属性"、"原型链属性"、"不存在"
 */
function judgePropertySource(obj, key) {
  // 先判断属性是否存在
  if (!(key in obj)) {
    return "不存在";
  }
  // 判断是否为自身属性(hasOwnProperty 不遍历原型链)
  if (obj.hasOwnProperty(key)) {
    return "自身属性";
  }
  // 存在且非自身,即为原型链属性
  return "原型链属性";
}

// 测试
function Person() {}
Person.prototype.name = "默认名";
const p = new Person();
p.age = 20;

console.log(judgePropertySource(p, "age")); // 自身属性
console.log(judgePropertySource(p, "name")); // 原型链属性
console.log(judgePropertySource(p, "gender")); // 不存在
题目 3:基于原型链实现单例模式(确保一个构造函数只能创建一个实例)。

答题思路:利用原型对象存储唯一实例,在构造函数中判断,若已存在则返回该实例。

答案

js 复制代码
function Singleton(name) {
  // 判断原型上是否已存在实例
  if (Singleton.prototype.instance) {
    return Singleton.prototype.instance; // 直接返回已有实例
  }
  this.name = name;
  // 将实例存储在原型上(唯一)
  Singleton.prototype.instance = this;
}

// 测试
const instance1 = new Singleton("实例1");
const instance2 = new Singleton("实例2");
console.log(instance1 === instance2); // true(仅创建一个实例)
console.log(instance2.name); // 输出 "实例1"(第二个参数无效)

面试易错点与答题技巧

高频易错点

  1. 混淆 __proto__prototype

    • 记忆口诀:"实例用 __proto__,构造函数用 prototype",所有对象都有 __proto__,只有构造函数有 prototype
  2. 认为 "ES6 class 无原型链"

    • 误区:class 是语法糖,底层仍依赖 prototype__proto__extends 本质是原型链指向。
  3. nullundefined 的原型链

    • null 无原型(__proto__ 不存在),undefined 不是对象,无 __proto__,访问会报错。
  4. FunctionObject 的原型关系

    • 易错点:Function.prototype 是对象,其 __proto__ 指向 Object.prototypeObject 是构造函数,其 __proto__ 指向 Function.prototype

答题技巧

  1. 概念题:先画 "三角图"

    • 遇到 prototype__proto__constructor 相关问题,先在草稿纸上画 "实例→原型对象→构造函数" 的三角关系图,再推导结论。
  2. 代码分析题:分步拆解查找流程

    • 步骤:① 确定对象的自身属性;② 沿 __proto__ 梳理原型链层级;③ 按 "自身→原型→父原型" 的顺序分析属性查找结果。
  3. 编程题:先搭框架,再补细节

    • 如继承题:先写父类→子类构造函数(call 传参)→ 原型关联(Object.create)→ 修复 constructor→ 扩展方法,最后测试边界情况(如传参、属性污染)。

总结与拓展

核心知识点回顾

  • 原型链本质 :对象通过 __proto__ 形成的链式关联,终点是 Object.prototype.__proto__ = null,是 JS 继承的底层支撑。
  • 核心规则:属性查找遵循 "自身优先→向上委托",继承实现的最优方案是寄生组合继承。
  • 开发原则:原型存储共享方法,实例存储私有属性;禁止修改原生原型,避免污染。

开发实战口诀

"原型共享方法,自身存私有属性;避免修改原生原型,寄生组合继承最优;属性查找看层级,delete 只删自身属。"

拓展方向

原型链与 ES6 Proxy、Reflect

  • Proxy 可拦截原型链查找:通过 get 陷阱,自定义属性查找逻辑(如拦截原型链上的属性访问)。

    js 复制代码
    const obj = { a: 1 };
    const proxy = new Proxy(obj, {
      get(target, key) {
        if (!(key in target)) {
          return "属性不存在";
        }
        return Reflect.get(target, key); // 反射获取属性
      }
    });
    console.log(proxy.b); // 输出 "属性不存在"(拦截原型链查找)

TypeScript 中对原型链的类型约束

  • TypeScript 通过接口和泛型,为原型链继承添加类型校验,避免类型错误。

    ts 复制代码
    // 父类接口
    interface Animal {
      type: string;
      sayType(): void;
    }
    // 子类实现
    class Dog implements Animal {
      type: string;
      constructor(type: string) {
        this.type = type;
      }
      sayType(): void {
        console.log(this.type);
      }
    }
    const dog: Animal = new Dog("哺乳动物"); // 类型约束生效

参考文章

《js 原型与原型链详解 (万文总结,一文搞懂原型链!)》 blog.csdn.net/Yi_qian1000...

《寄生组合继承:JavaScript 继承模式的优化方案》 blog.csdn.net/weixin_4255...

《JavaScript 核心概念 - 原型、原型链》 blog.csdn.net/weixin_3999...

《js 基础之阮一峰的面向对象编程》 www.cnblogs.com/lxq3280/p/1...

《MDN Web Docs - 继承与原型链》 developer.mozilla.org/zh-CN/docs/...

以上就是本文的所有内容了,如果你感觉有用的话,给主播点点赞和关注呗。

相关推荐
JohnYan7 小时前
Bun技术评估 - 26 Abort
javascript·后端·bun
inBuilder低代码平台8 小时前
Electron应用优化与性能调优策略
javascript·性能优化·electron
前端开发爱好者8 小时前
Electron 淘汰!新的跨端框架来了!性能飙升!
前端·javascript
狮子座的男孩8 小时前
js基础:08、构造函数(共享方法)、原型(prototype)、原型对象、(修改原型)toString方法、垃圾回收
前端·javascript·经验分享·prototype·垃圾回收·构造函数·原型对象
前端开发爱好者8 小时前
Vue 团队成员又搞了个 "新玩具"!
前端·javascript·vue.js
musenh8 小时前
javascript学习
开发语言·javascript·学习
一 乐8 小时前
农产品销售系统|农产品电商|基于SprinBoot+vue的农产品销售系统(源码+数据库+文档)
java·javascript·数据库·vue.js·spring boot·后端·农产品销售系统
咖啡の猫9 小时前
Vue过度与动画
前端·javascript·vue.js
蒜香拿铁9 小时前
Angular【起步】
前端·javascript·angular.js