原型对象prototype
为什么会有原型对象
js在设计之初,并不打算像java一样作为面向对象的编程语言,他想更简单更轻量一些,只要能满足当时简单的需求就可以了,所以js最初没有‘类’,‘继承’等概念,一个实例对象通过函数来new出来。但是对于同一类的实例对象来说,共性的属性不应该是每次创建的时候都去创建一次。所以引入了原型对象prototype,并将这些共性的属性放在原型对象prototype上。举个例子:
function Dog(name){
this.name = name;
this.species = "犬"
}
let dog1 = new Dog("小黑")
let dog2 = new Dog("小黄")
dog1.species = "大型犬"
console.log(dog2.species) // 犬
function Dog(name){
this.name = name;
}
DOG.prototype.species = '犬';
let dog1 = new Dog("小黑")
let dog2 = new Dog("小黄")
dog1.species = "大型犬"
console.log(dog2.species) // 大型犬
在上面的第一个例子中species是每个实力对象维护的,并不是一个Dog实例公用的属性,修改其中一个不会影响到另一个。而使用prototype后更符合“共性属性”的概念
介绍原型对象prototype
他是构成函数存放共性属性的地方,是一个对象,通过函数创建的对象也将拥有这个原型对象 有以下这些特点:
- 如果对象本身不存在属性或方法将到原型上查找
function Person(){}
Person.prototype.name = "yangchen"
let p = new Person()
console.log(p.name) // yangchen
- 所有函数的原型默认是
Object的实例,所以可以使用toString等方法的原因
let obj = {
name: "yangchen"
}
console.log(obj.toString) // '[object Object]'
console.log(Object.prototype.toString === obj.toString) // true 同一个函数
- 原型包含
constructor属性,指向构造函数
function Person(){}
console.log(Person.prototype) // {constructor: ƒ}
console.log(Person.prototype.constructor === Person) // true 构成函数详细说
- 实例对象的
__proto__指向他的原型对象
function Person(){}
Person.prototype.name = "yangchen"
let p = new Person()
console.log(p.__proto__) // {name: 'yangchen', constructor: ƒ}
console.log(p.__proto__ === Person.prototype) // true
介绍原型链__proto__(两个_)
原型链:就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构.称为原型链
属性__proto__存在实例对象上,指向构成函数的原型对象prototype,构成函数是没有__proto__属性
查找实例对象的某个属性,会先实例对象是否拥有,如果不存在,则通过__proto__找到它的原型对象并判断是否拥有,如果还是不存在,继续通过__proto__往上层原型对象找。
function Person(){}
Person.prototype.name = "yangchen"
let p = new Person()
console.log(p.name) // yangchen
console.log(p.__proto__) // {name: 'yangchen', constructor: ƒ}
console.log(p.__proto__ === Person.prototype) // true
原型关系分析
构成函数,实例对象,原型对象prototype,属性__proto__之间关系
function Person(){}
Person.prototype.name = "yangchen"
let p = new Person()
// 实例对象p的__proto__指向构成函数Person的原型对象prototype
console.log(p.__proto__ === Person.prototype) // true
// 构成函数也是对象(因为函数也是对象),它也具有__proto__,指向他的父级prototype,这里的Person.__proto__指向的Function.prototype
console.log(Person.__proto__ === Function.prototype)
// 最顶级的父级原型是Object.prototype,且Object.__proto__为null,也就是查找属性的时候查找到这里结束了
console.log(Object.prototype.__proto__) // null
// 原型对象prototype的constructor属性指向构成函数自身
console.log(Person.prototype.constructor === Person) // true
构造函数通过prototype指向原型对象,原型对象通过constructor指向构成函数
相关的api
- instanceof
object instanceof constructor
检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function Person() {}
let p = new Person()
console.log(p instanceof Person) // true
- setPrototypeOf
Object.setPrototypeOf(obj, prototype)
设置一个指定的对象的原型
let a = {age: 18}
let b = {}
Object.setPrototypeOf(b, a)
console.log(b instanceof a) // true
- getPrototypeOf
Object.getPrototypeOf(object)
返回其原型的对象
let a = {age: 18}
let b = {}
Object.setPrototypeOf(b, a)
console.log(Object.getPrototypeOf(b) === a) // true
- Object.create
Object.create()
使用现有的对象来作为原型来创建新对象
let a = {age: 18}
let b = Object.create(a)
console.log(Object.getPrototypeOf(b) === a) // true