** 此文转载乐字节 ** 为什么存在原型、原型链
首先,我们先来看一个例子
function Person(name, age) {
this.name = name
this.age = age
this.eat = function() {
console.log(${age}岁的${name}正在吃饭)
}
}
let person1 = new Person('aki', 19) let person2 = new Person('aki', 19)
console.log(person1 === person2) // false 复制代码 为什么打印输出的结果是false呢? 因为对于同一个函数,我们通过 new 生成的实例,都会开辟出一个新的堆区,并且在每个实例上添加属性。所以在上述函数中,两个对象是不同的。 如果每生成一个对象都开辟一个新的堆区,很容易会造成内存不足的情况,而原型链&原型链就是来解决这个问题的,因为利用原型模式定义的属性和方法是有所有实例共享的,因此实例访问的都是相同的属性和函数。 我们不再需要在每个实例对象上添加属性,而是将属性添加在构造函数的原型对象上,这样一来,我们只需要通过原型链找到原型,实例对象就可以动态地获取构造函数的属性和方法。 如果上面那段话不是很好理解,那么接下来我将会通过例子理清各个概念以及它们之间的关系。 构造函数创建对象 先使用构造函数创建一个对象 function Person() {
} let person1 = new Person() person1.name = 'aki' console.log(person1) 复制代码 在这个例子中,Person 作为一个构造函数,创建了一个实例对象 person1,很好理解吧? prototype 首先我们来讲讲prototype。在《JavaScript高级程序》一书中是这么说的:
无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个prototype属性(指向原型对象)。
所以Person作为构造函数,也会有prototype属性指向实例原型,如下图所示。
那什么是原型呢?原型指的就是一个对象,实例“继承”那个对象的属性。在原型上定义的属性,通过“继承”,实例也拥有了这个属性。 “继承”这个行为是在 new 操作符内部实现的。 proto 每一个JavaScript对象(除了 null )都具有的一个隐式属性__proto__,proto 属性会指向该对象的原型 prototype 。 可以用代码来证明这一点: function Person() {
} let person = new Person() console.log(person.proto === Person.prototype) //true 复制代码 如下图所示:
constructor 从上图不难发现,构造函数(函数)以及实例对象(对象)分别有一个 prototype 属性和 proto 属性指向实例对象的原型。 那么,原型是否存在指向构造函数(函数)或者是实例对象(对象)的属性呢?答案是有的,不过原型只有乐字节指向构造函数的属性,毕竟一个构造函数能够生成很多实例对象。这个属性就是 constructor 。 依然用代码来证明这一点: function Person() {
} let person = new Person() console.log(Person.prototype.constructor === Person) //true 复制代码 我们对上图进行补充,可以得到:
注意这里的 constructor 是原型的一个属性,Constructor 指的才是真正的构造函数。两者名字不要弄混了
理解原型 至此,我们已经了解了 构造函数 、 实例对象 、 实例原型 三者之间的关系:
每个构造函数都有一个原型对象prototype,原型对象都包含一个指向构造函数的指针constructor,而实例(instance)都包含一个指向原型对象的内部指针_proto_
多说无益,上代码: /*
- 构造函数可以是函数表达式,也可以是函数声明。
- 所以下面两种形式都可以
- function Person() {}
- let Person = function() {}
- */ function Person() {}
/*
- 声明之后,构造函数就有一个与之关联的原型对象
- */ console.log(typeof Person.prototype) console.log(Person.prototype)
/*
- 原型对象有一个 constructor 属性可以引用构造函数
- */ console.log(Person.prototype.constructor === Person)
/*
- 正常的原型链都会终止于 Object 的原型对象
- Object 原型的原型是 null
- */ console.log(Person.prototype.proto === Object.prototype) console.log(Person.prototype.proto.constructor === Object) console.log(Person.prototype.proto.proto === null)
/*
- 同一个构造函数创建的两个实例
- 共享同一个原型对象
- */ let person1 = new Person(), person2 = new Person() console.log(person1.proto === person2.proto)
/*
- instanceof可以检查实例的原型链中是否包含指定构造函数的原型
- */ console.log(person1 instanceof Person) console.log(person1 instanceof Object) console.log(person1.prototype instanceof Object)
ps需自学视频B站讲的最好的零基础Python教程-----Python大神级教程- Python面向对象编程(完整版)****b站BV1Cg411G75N