一、说一说原型模式
每个构造函数都有一个 prototype 原型属性,这个属性它是一个指针,指向一个对象,而这个对象的用途是可以由特定类型的所有实例共享的属性和方法。则这个 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。
原型对象的好处就是让所有对象实例共享它所包含的属性和方法。
function Person(){
}
Person.prototype.name="掘金"
Person.prototype.age=18
Person.prototype.sayName=function (){
console.log(this.name)
}
var person1 = new Person()
person1.sayName() //掘金
var person2 = new Person()
person2.sayName() //掘金
console.log(person1.sayName === person2.sayName)由上述代码可知,构造函数为一个空函数,sayName()方法和所有属性直接添加到了Person的prototype属性中。
调用构造函数来创建新对象,这个新对象会具有相同的属性和方法。但是和构造函数不同的是,这个新对象的属性和方法是所有实例共享的。
就是,person1和person2访问的都是同一组属性和同一个sayName()函数。
二、什么是原型对象
只要创建一个新函数,其内部就会创建一个 prototype 属性,这个属性指向函数的原型对象。而所有原型对象都会自动获得一个 constructor
构造函数 属性,这个属性指向prototype属性所在函数的指针。

三、原型继承
所有JavaScript对象都从原型继承属性和方法。日期对象继承来自Date.prototype。数组对象继承来自Arrray.prototype。
Person对象继承来自Person.prototype。Object.prototype位于原型继承链的顶端。
日期对象,数组对象和 Person 对象都继承来自Object.prototype。
向对象添加属性和方法
需求一,当需要向所有给定类型的已有对象添加新属性,或者是方法。
需求二,当需要向对象构造器添加新属性,或者是是方法。
使用prototype属性
JavaScript 中的 prototype 属性允许你为对象构造器添加新属性,或者是方法。
function Person(firstName,lastName,age,eyecolor){
this.firstName=firstName;
this.lastName=lastName;
this.age=age;
this.eyecolor=eyecolor
}
Person.prototype.form='掘金';
function Person(firstName,lastName,age,eyecolor){
this.firstName=firstName;
this.lastName=lastName;
this.age=age;
this.eyecolor=eyecolor
}
Person.prototype.name=function () {
return this.firstName + " " + this.lastName
}创建了构造函数后,其原型对象会取得 constructor 属性,至于其他方法,都是从 Object 继承来的,当调用构造函数创建一个新实例后,该实例的内部包含一个指针,指向构造函数的原型对象。
这个指针就叫 prototype ,每个对象上都有一个属性叫 __proto__。注意的是这个指针存在于实例与构造函数的原型对象之间,不是存在于实例与构造函数之间。
你可以把Person构造函数,Person 的原型属性,和 Person 的两个实例之间的关系结构画出来分析分析。
一个Person构造函数有一个 prototype 。指向了原型对象,Person Prototype。
一个 Person Prototype 中有 constructor,name,age,job,sayName。而Person.prototype.constructor 又指回了 Person。
原型对象中除了包含一个constructor属性外,还有后来添加的其他属性。
Person的每个实例都有一个内部属性,该属性仅仅指向了Person.prototype,严格说,它们和构造函数没有直接关系。

重点之一,当调用构造函数创建一个新实例后,该实例的内部将包含一个指针,指向构造函数的原型对象,这个指针叫[[Prototype]]。在每个对象上都支持一个属性__proto__。
对象中的__proto__属性
对象中的__proto__属性在所有实现中都是无法访问到的,但是可以通过 isPrototypeOf()方法来确定对象之间是否存在这种关系。
let person1 = new Person()
let person2 = new Person()
console.log(Person.prototype.isPrototypeOf(person1))) //true
console.log(Person.prototype.isPrototypeOf(person2))) //true
person1和person2中内部有一个指向Person.prototype的指针,返回就是true了。
在ECMAScript5中增加了一个新的方法,叫
Object.getPrototypeOf(),在所有支持的实现中,这个方法返回[[Prototype]]的值。
代码
console.log(Object.getPrototypeOf(person1) === Object.getPrototypeOf(person2)) //true
console.log(Object.getPrototypeOf(person1).name) //掘金确认Object.getPrototypeOf()返回的对象实际是这对象的原型,使用Object.getPrototypeOf()可以方便地取得一个对象的原型。
代码调用过程,调用对象的某个属性时,会首先搜索从对象实例本身开始,如果找到了给定名字的属性,则返回该属性的值,如果没有找到。
会第二次搜索,从指针指向的原型对象开始,在原型对象中查找给定名字的属性,如果在原型对象中查找具有给定名字的属性,就返回该属性值。
如何判断一个属性是否存在于实例中呢,还是存在于原型中呢?
我们可以使用hasOwnProperty()方法来给指定属性判断是否存在于对象实例中,存在对象实例中时,返回值为true。
function Person(){
}
Person.prototype.name="掘金"
Person.prototype.age=18
let person1 = new Person()console.log(person1.hasOwnProperty('name')) //false
person1.name='hello'
console.log(person1.name) //hello --来自实例
console.log(person1.hasOwnProperty('name')) //true使用in操作符
in操作符用来判断在通过对象能够访问给定属性时,返回为true。无论是该属性是在实例中还是在原型中。
同时使用hasOwnProperty()方法和In操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。
function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in Object)
}上述代码用来判断属性存在于原型中。in操作符通过对象能够访问到属性就返回true,hasOwnProperty()只要属性存在于实例中时才返回true。
所以只要in操作符返回true而hasOwnProperty()返回false,就可以确定属性是原型中的属性。
要取得对象上所有可枚举的实例属性,可使用Object.keys()方法,这个方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
function Person(){
}
Person.prototype.name = 'juejin'
Person.prototype.age = 18
Person.prototype.job = 'web'
var Keys = Object.keys(Person.prototype)
console.log(keys) // ["name", "age", "job"]
var person1 = new Person()
person1.name ='data'
person1.age= 18
console.log(Object.keys(person1)) // ["name", "age"]
可以看出,Object.keys()方法保存的是一个数组,循环顺序的出现,如果有Person的实例调用,那么出现的实例中的属性。
如果要出现所有实例属性,无论它是否可以枚举,都可以使用
Object.getOwnPropertyNames()方法。
var keys = Object.getOwnPropertyNames(Person.prototype)
console.log(keys) // ["constructor", "name", "age", "job"]返回结果中包含不可枚举的constructor属性。
基于原型的常见的几种继承方式