原型与原型链,一个非常常见且重要的js知识点。关于这个知识点在网络上相关的教程有很多不错的文章。但个人认为,真正掌握一个知识点在于可以组织自己的语言并清楚描述,是什么,为什么和怎么用。

原型是什么

先以一个构造函数Person和它的实例jack来举例说明

 function Person(name, gender) {
     this.name = name;
     this.gender = gender;
 }
 Person.prototype.getName = function() {
     console.log('my name is' + this.name);
 }
 let boy = new Person('jack', 'male');
 boy.getName(); // my name is jack;

通过打印控制台可以看到
图片1.png
每创建一个函数会自带有prototype属性,指向该函数的原型对象。该属性的作用在于保存它自身的方法和constructor属性,例如Person.prototype包含了getName,constrctor和__proto__;(每一个对象都会有__proto__属性,null除外,所以原型对象也会拥有)。调用了这个构造函数构造的实例(例如jack),都可以调用它构造函数的原型对象里的属性和方法。

图中的箭头数:
1) jack.__proto__.指向了Person.prototype(它的构造函数原型的原型)
2) Person.prototype(构造函数的原型对象)有constructor属性,指向它的Person (构造函数)
个人理解,constructor就相当于连接jack(实例)和Person(构造函数)的桥梁
3) Person.__proto__指向了Function.prototype,因为Person是Function的实例
4) Function.prototype.constructor指向了Function
5) Function也包含了prototype原型对象
6) Function.prototype的原型属性指向了Object.prototype

当我查找到了对象的顶层Object.prototype时,不禁思考一个问题,本身对象可以通过new Object创造,那么Object的构造函数又是谁。于是我根据控制台逐级向下打开
图片.png

原型总结
1.Object是所有对象的爸爸,所有的对象都继承自Object
2.Function是所有函数的爸爸,所有的函数都继承自Fucntion
3.实例和原型对象通过constructor来连接的
4.Object.proto.constructor指向了Function
5.Function.prototype.proto 指向了Object.prototype

什么是原型链
引用js高级程序设计的一段话
ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原 型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每 个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的 原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数 的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实 例与原型的链条。

个人大白话翻译,通过上文已经知道实例有一个内部指针指向原型对象,原型对象有一个constructor属性指向构造函数,那么当引用类型A想要使用引用类型B的属性和方法时,是不是让A的内部指针指向B的原型对象就可以了呢?
look代码!

function Person() {}
Person.prototype.getNum = function() {
    return 99;
}
function Student() {}
Student.prototype = new Person();
Student.prototype.constructor = Student;
let stu = new Student();
stu.getNum(); // 99

// 原型链
stu.__proto__ === Student.prototype //true
Student.prototype.__proto__ === Person.prototype //true
stu.__proto__.__proto__ === Person.prototype //true
stu.__proto__.__proto__.getNum === Person.prototype.getNum //true

将原型方法改写一下,当涉及到对引用类型的操作时

function Person() { this.favoriteNum = [1,2,3];}
Person.prototype.getFavoriteNum = function() {
    console.log(this.favoriteNum);
}
function Student() { Person.call(this);}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
let stu = new Student();
stu.favoriteNum.push(4);
stu.getFavoriteNum(); // [1,2,3,4]
let stu1 = new Student();
stu1.getFavoriteNum(); // [1,2,3]
总结原型链继承
1.子类构造函数调用call或apply方法继承父类构造函数;
2.通过Object.create()创建一个新对象并传入参数父类的原型对象,将新对象赋值给子类的原型对象
3.由于子类的prototype被重写,需要将constructor重新指向它自身的构造函数

someone
218 声望7 粉丝

前端工程师


« 上一篇
随手记