原型
对象的结构
- 对象中存储属性的区域实际上有两个:
- 对象自身
- 直接通过对象所添加的属性,位于对象自身中 p1.address = "花果山"
- 在类中通过 x = y 的形式添加的属性,位于对象自身中 name = "孙悟空"
- 神秘位置
- 对象中还有一些内容,会存储到其他的对象里(原型对象)
- 在对象中会有一个属性用来存储原型对象,这个属性叫做
__proto__ - 原型对象也负责为对象存储属性
- 当我们访问对象中的属性时,会优先访问对象自身的属性,对象自身不包含该属性时,才会去原型对象中寻找
- 会添加到原型对象中的情况:
- 在类中通过xxx()方法添加的方法,位于原型中
- 主动向原型中添加的属性或方法
- 对象自身
class Person {
name = "孙悟空";
age = 18;
sayHello = "hello";
sayHello() {
console.log("hello");
}
}
const p1 = new Person();
console.log(p1.sayHello); // "hello"

原型对象
- 访问一个对象的原型对象
对象.__proto__- Object.getPrototypeOf(对象)
- 原型对象中的数据:
- 对象中的数据(属性、方法等)
- constructor(对象的构造函数)
- 注意:
- 原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同
- p对象的原型链:p对象 -> 原型 -> 原型 -> null
- obj对象的原型链:obj对象 -> 原型 -> null
- 原型链:
- 读取对象属性时,会优先读取对象自身属性,如果对象中有,则使用,没有则去对象的原型中寻找,如果原型中有,则使用,没有则去原型的原型中寻找,直到找到Object对象的原型(Object的原型没有原型(为null)),如果依然没有找到,则返回undefined
- 作用域链,是找变 量的链,找不到会报错
- 原型链,是找属性的链,找不到会返回undefined
- 原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同
class Person {
name = "孙悟空";
age = 18;
sayHello() {
console.log(this.name);
}
}
const p = new Person();
console.log(p); // Person {name: '孙悟空', age: 18}
console.log(p.__proto__); // {constructor: ƒ, sayHello: ƒ}
console.log(Object.getPrototypeOf(p) === p.__proto__); // true
console.log(p.__proto__.__proto__);
console.log(p.__proto__.__proto__.__proto__); // null
- 所有的同类型对象它们的原型对象都是同一个,也就意味着,同类型对象的原型链是一样的
- 原型的作用:
- 原型就相当于是一个公共的区域,可以被所有该类实例访问,可以将该类实例中,所有的公共属性(方法)统一存储到原型中,这样我们只需要创建一个属性,即可被所有实例访问
- JS中继承就是通过原型来实现的,当我们继承时,子类的原型就是父类的实例
- 在对象中有些值是对象独有的,像属性(name,age,gender)每个对象都应该有自己的值,但是有些值对于每个对象来说都是一样的,像各种方法,对于一样的值没必要重复创建
class Person {
name = "孙悟空"
sayHello() {
}
sayHello2 = () => {
}
}
const p1 = new Person();
const p2 = new Person();
console.log(p1.__proto__ === p2.__proto__); // true
console.log(p1.sayHello === p2.sayHello); // true
console.log(p1.sayHello2 === p2.sayHello2); // false
class Animal { }
class Cat extends Animal { }
const cat = new Cat();
// cat --> Animal实例 --> object --> Object原型 --> null

修改原型对象
- 大部分情况下,我们是不需要修改原型
- 注意:千万不要通过类的实例去修改原型
- 通过一个对象影响所有同类对象,这么做不合适
- 修改原型先创建实例,麻烦
- 危险
- 注意:千万不要通过类的实例去修改原型
- 处理通过
__proto__能访问对象的原型外,还可以通过类的prototype属性,来访问实例的原型,修改原型时,最好通过类去修改- 好处:
- 一修改就是修改所有实例的原型
- 无需创建实例即可完成对类的修改
- 原则:
- 原型尽量不要手动改
- 要改也不要通过实例对象去改
- 通过 类.prototype 属性去修改
- 最好不要直接给prototype去赋值
- 好处:
class Person {
}
const p = new Person();
console.log(Person.prototype === p.__proto__); // true
Person.prototype.fly = () => {
console.log("我在飞");
}
console.log(p.fly()); // 我在飞