目录
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行打印:
ablice
在running
- 15行打印:
bob
在jumping
- 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) --> 中国很大
**
原型关系图
版权归原作者 你会发光哎u 所有, 如有侵权,请联系我们删除。