0


彻底理解原型和原型链

目录

JavaScript中是支持面向对象编程的,那么我们知道
面向对象有三大特性

  • 封装:将属性和方法封装到一个类中,称为封装的过程
  • 继承:它是非常重要的,不仅可以减少重复代码,也是多态前提(纯面向对象中),它帮助我们将重复的代码和逻辑抽取到父类中,子类只需要直接继承过来使用即可
  • 多态:不同的对象在执行时表现出不同的形态

**原型和原型链构成了

JavaScript

的继承机制,使得对象能够共享属性和方法,我们必须理解原型和原型链才能明白继承的实现,继承实现具体学习这篇文章:https://juejin.cn/post/7399986979735781391**

原型

1. 对象原型

JavaScript

当中每个对象都有一个特殊的内置属性

[[prototype]]

这个特殊的对象可以指向另外一个对象,这就是对象的原型,也称隐式原型

  • JavaScript 中,任何对象的原型最终都会指向 Object.prototype,除非你明确地指定了另一个原型

作用

不管如何创建只要是对象都会有这样的一个内置属性,那么这个对象有什么用呢?

  • 当我们通过引用对象的属性key来获取一个value时,它会触发 [[Get]]的操作
  • 首先检查该对象是否有对应的属性,如果有的话就使用它
  • 如果对象中没有该属性,那么会访问对象[[prototype]]内置属性指向的对象里的属性

在这里插入图片描述

特殊

函数也是对象,它们也有

__proto__

属性,在

JavaScript

中,所有的函数都是

Function

构造函数的实例,这意味着**每个函数的

__proto__

属性都指向

Function.prototype

**

functionfoo(){}
console.log(foo.__proto__);
console.log(foo.__proto__ ===Function.prototype);// true

获取

  • 方式一:通过对象的 __proto__ 属性可以获取到(但是这个是早期浏览器自己添加的,虽然大多数现代浏览器都支持 __proto__,但它不是标准属性,应该尽量避免直接使用)
  • 方式二通过 Object.getPrototypeOf(obj) 方法获取
var obj ={name:"obj",age:18,};
console.log(obj, obj.__proto__);
console.log(Object.getPrototypeOf(obj));

2. 函数原型

请先理解构造函数相关知识点,具体学习这篇文章https://juejin.cn/post/7399179026801868863
**所有的函数都有一个

prototype

的属性**(注意:不是

__proto__

),也称显式原型

定义

prototype

是一个对象,该对象在使用构造函数创建新的实例对象时会被赋值给实例对象的

__proto__

属性(具体学习

new

操作符这篇文章:https://juejin.cn/post/7397399723601215488

  • 当定义一个函数时,**JavaScript 引擎会自动为该函数创建一个 prototype 属性**
  • 会将其初始化为一个包含 constructor 属性的对象constructor 属性指向函数本身
functionfoo(){}
console.log(foo.prototype);

在这里插入图片描述

作用

**使用

prototype

实现方法共享**:当使用构造函数创建实例时,可以通过

prototype

属性为所有实例共享方法,这避免了在每个实例上都创建相同的方法,从而节省内存,参考学习总结练习代码

获取

functionfoo(){}
console.log(
  foo.prototype,
  foo["prototype"],
  foo["prototype"]=== foo.prototype
);

constructor

属性

  • 每个函数的 prototype 对象默认都有一个 constructor 属性,指向这个函数自身,这意味着你可以通过实例对象的原型找到它们的构造函数functionPerson(name, age){this.name = name;this.age = age;}// 默认情况下,Person.prototype.constructor 指向 Personconsole.log(Person.prototype.constructor === Person);// 输出: trueconst john =newPerson('John',30);// john.__proto__ 是 Person.prototypeconsole.log(john.__proto__ ===Person.prototype);// 输出: true// john.constructor 指向 Personconsole.log(john.constructor === Person);// 输出: true
  • 如果你重写prototype或者修改了构造函数的 prototype 对象时,你需要手动修正 constructor 属性,否则它会指向错误的构造函数
  • 作用: - 使用 constructor 确定对象的类型functionCar(make, model){this.make = make;this.model = model;}const myCar =newCar('Toyota','Corolla');// 使用 constructor 属性确定对象的类型console.log(Car.prototype.constructor === Car);// 指向本身console.log(myCar.constructor === Car);// 输出: true- constructor 用在运行时动态创建对象functionPerson(name){this.name = name;}const person1 =newPerson('Alice');const person2 =newperson1.constructor('Bob');console.log(person2.name);// 输出: Bobconsole.log(person2 instanceofPerson);// 输出: true

重写

prototype
functionPerson(){}Person.prototype ={// constructor: Person, // 手动修正 `constructor` 属性, 但这样指向constructor会被枚举到message:"hello",info:{},running:function(){this.name +'在running'},eating:function(){this.name +'在eating'},};
Object.defineProperty(Person.prototype,"constructor",{enumerable:false,configurable:true,writable:true,
  value,});

Object

Object

是一个函数,是所有对象的构造函数

  • Object.prototype- 当你创建对象时,例如通过 {}new Object(),你实际上是在使用 Object 这个构造函数- Object 作为一个函数,有自己的 prototype 属性(这是一个对象),所有通过 Object 构造的实例都共享这个原型对象,任何对象的原型最终都会指向 Object.prototype- 可以修改 Object.prototype 来为所有对象添加新的方法或属性,但这种做法不推荐,因为它会影响所有对象,可能导致意外的行为和兼容性问题
  • Object.__proto__- Object 是一个函数,函数也是对象,因此它有 __proto__ 属性- Object.__proto__ 实际上指向 Function.prototype,因为在 JavaScript 中,所有函数都是由 Function 构造的
  • 原型链的末端是Object构造函数的原型对象的原型(**Object.prototype.__proto__**)即是null
// Object和Foo是一个函数也是对象,所以它有 __proto__ 属性,函数的__proto__都指向Function.prototypefunctionFoo(){}
console.log(Foo.__proto__ ===Function.prototype)
console.log(Object.__proto__ ===Function.prototype);// 输出: true
console.log(Function.prototype.__proto__ ===Object.prototype);// 输出: true// 字面量创建一个普通对象相当于const obj = new Object()const obj ={};
console.log(obj.__proto__ ===Object.prototype);// 输出: true// 最顶层的 Object.prototype.__proto__ 为 null
console.log(Object.prototype.__proto__ ===null);// 输出: true// 可以修改,但不建议修改Object.prototype.newMethod=function(){ console.log('This is a new method');};

原型链

原型链是指**对象通过其原型属性(

[[Prototype]]

__proto__

)形成的链条**

  • 当访问对象的属性时,如果该属性在对象自身不存在,**JavaScript 引擎会沿着原型链向上查找**
  • 原型链的末端是Object构造函数的原型对象的原型(**Object.prototype.__proto__**)即为null

总结练习

functionPerson(name, age, height){this.name = name;this.age = age;this.height = height;}Person.prototype.running=function(){
  console.log(this.name +"在running");};Person.prototype.jumping=function(){
  console.log(this.name +"在jumping");};var p1 =newPerson("ablice",20,188);var p2 =newPerson("bob",18,180);
p1.running();
p2.jumping();// 练习 打印什么 记得__proto__不是标准,不是练习用时要判断Person.prototype.address ="中国";
p1.__proto__.info ="中国很大";
p1.height =190;
p1.address ="深圳";
p2.isAdmin =true;

console.log(p1.address);
console.log(p2.address);
console.log(p1.isAdmin);
console.log(p2.isAdmin);
console.log(p2.info);

这个原型链图将整篇文章的知识点串联了起来,看图答案就呼之欲出了,图示如下:
在这里插入图片描述

  • 14行打印:ablicerunning
  • 15行打印:bobjumping
  • 24行打印:深圳
  • 25行打印:中国 - 寻找过程:**p2 --> p2.__proto__(Person.prototype) --> 中国**
  • 26行打印:undefined - 寻找过程:**p1 --> p1.__proto__(Person.prototype) --> p1.__proto.__proto__(Object.prototype) --> p1.__proto.__proto__.__proto__ --> null(没找到)**
  • 27行打印:true
  • 28行打印:中国很大 - 寻找过程:**p2 --> p2.__proto__(Person.prototype) --> 中国很大**

原型关系图

在这里插入图片描述

标签: 前端 javascript

本文转载自: https://blog.csdn.net/qq_45730399/article/details/141104727
版权归原作者 你会发光哎u 所有, 如有侵权,请联系我们删除。

“彻底理解原型和原型链”的评论:

还没有评论