原型链
- 概念:每一个对象都有一个原型,原型还有它自己的原型,以此类推,形成了原型链
- 作用:共享属性和方法,当你查找一个属性/方法时,若当前对象不存在,就会在它的原型里找,没有找到就继续向上,直到Object.protoType.protp===null,此时会返回undefined
- 构造函数、原型、实例对象的关系
- 每个构造函数都有一个prototype原型对象
- prototype原型对象里的constructor指向构造函数本身
- new一个构造函数会形成它的实例对象
- 每个实例对象都有__proto__属性,并且指向它的原型对象
- 原型对象中存在__proto__属性指向它自己的原型
- 完整的关系图
- 代码参考
function Person() {
}
var p = new Person()
console.log(p.constructor); //function Person(){}
console.log(p.__proto__)//Person {}
console.log(p.__proto__ === Person.prototype) //true
console.log(p.prototype); // undifined
//p.prototype==undefined的原因
console.log(p.__proto__.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__)//null
//原型链的闭环
//每个函数都是通过Function()生成的,Object也是一个函数
console.log(Person.constructor===Object.constructor);//true---function Function(){}
//每个对象都是通过new Object()构造的
console.log({}.constructor); // function Object(){}
//正常情况下
console.log(Person.prototype === Person.__proto__)//false
//但是将Function也当成是一个对象,存在
console.log(Function.__proto__ === Function.prototype)//true
console.log(Object.__proto__ === Function.__proto__) //true
console.log(Function.prototype.__proto__ === Object.prototype)//true
//原型链顶点
console.log(Object.prototype.__proto__)//null
原型链继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.getName = function () {
console.log(this.name)
}
let person = new Person('Jack', 20)
console.log(person) //Person { name: 'Jack', age: 20 }
- 属性继承
在类里执行另一个类的构造函数
function Teacher(name, age, subject) {
Person.call(this, name, age)
this.subject = subject
}
let teacher = new Teacher('Ann', 21, '数学')
console.log(teacher) //Teacher { name: 'Ann', age: 21, subject: '数学' }
- 方法继承
将另一个对象赋值给它的原型
Teacher.prototype = Object.create(Person.prototype)
//此时Teacher.protoType.constructor===Person,需要修改它的构造函数指向
Teacher.prototype.constructor = Teacher
teacher.getName() //Ann
new关键字
创建实例的过程
- 创建一个空对象{}
- 将空对象的__proto__指向构造函数的protoType
- 将空对象作为构造函数中this的上下文,执行构造函数
- 返回新对象
代码实现new关键字
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.getName = function () {
console.log(`I'm ${this.name}`)
}
function _new(fn, ...args) {
let obj = {}
obj.__proto__ = fn.prototype
fn.apply(obj, args)
return obj
}
let p = _new(Person, 'Nana', 20)
p.getName() //I'm Nana