主要摘自《Javascript高级程序设计》es6
var person = function(name,age){
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name)
}
return o;
}
var person1 = person('li', 20);
var person2 = person('xiao', 18);
person1.sayName(); //li
person2.sayName(); //xiao
复制代码
工厂模式虽然解决了建立多个类似对象的问题,可是却没有解决对象识别的问题,即怎样知道一个对象的类型。数组
var Person = function(name,age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name)
}
}
var person1 = new Person('li',20)
var person2 = new Person('xiao',18)
person1.sayName() //li
person2.sayName() //xiao
复制代码
构造函数和工厂函数不一样之处在于:bash
** 调用构造函数会经历下面4个步骤(即new干了什么)**:app
上面的person1和person2分别保存Person的一个不一样实例,这两个对象都有一个constructor(构造函数)属性,该属性执行Person函数
person1.constructor == person2.constructor == Person
ui
能够用constructor来识别对象类型,可是用instanceof 更可靠this
person1和person2同时也是object的实例,由于全部的对象都继承自Objectes5
若是构造函数里面有方法,那方法都会在每一个实例上都建立一遍,所以不一样实例上的函数是不相等的spa
person1.sayName == person2.sayName // false
prototype
虽然能够把方法移到构造函数外部,设置成全局函数,可是若是对象须要定义不少方法,就要定义不少个全局函数,
function Person(){};
Person.prototype.name = "li";
Person.prototype.age = 20;
Person.prototype.sayName = function(){
console.log(this.name)
};
var person1 = new Person()
var person2 = new Person()
person1.sayName() //li
person2.sayName() //li
person2.name = 'xiao' //person2这个实例加了一个name属性,重写name属性,但不会改变原型的值
person1.sayName() //li
person2.sayName() //xiao //若是实例上有name属性,取的是实例上的
复制代码
可让全部对象实例共享它所包含的属性和方法。
person1.sayName !== person2.sayName //true
只要建立了一个函数,就会为该函数建立一个prototype属性,这个属性指向函数的原型对象。在默认状况下,全部原型对象都会自动得到一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针(妈呀,很拗口,看代码和图比较直观)
建立了自定义的构造函数后,其原型对象默认只会取得constructor属性,至于其余方法,都是从object继承而来。当调用构造函数建立一个实例,该实例内部将包含一个指针,指向构造函数的原型对象,能够用_proto_属性访问。这个连接存在与实例与构造函数的原型对象之间,而不存在于实例与构造函数之间。
Person.prototype.constructor = Person
person1._proto_ == Person.prototype
Person.prototype.isPrototypeOf(person1) // true
Object.getPrototypeOf(person1) == Person.prototype // true
Object.getPrototypeOf(person1).name //li
person1.hasOwnProperty('name') // false
person2.hasOwnProperty('name') //true
复制代码
'name' in Person // true
hasOwnProperty和in一块儿能够判断属性是否是在原型中
!object.hasOwnProperty(name) && ('name' in object)
咱们将Person.prototype 设置为等于一个以对象字面量形式建立的新对象,最终结果相同,可是constructor属性再也不指向Person。这里的语法,本质上完成重写了默认的portotype对象,所以它的原型是Object,constructor是指向Object的构造函数。可是用instanceof 操做符还能返回正确结果
function Person(){};
Person.prototype = {
name: 'li',
age: 20,
sayName: function(){
console.log(this.name)
}
};
var person1 = new Person()
console.log(Person.prototype.constructor == Person) //false
console.log(Person.prototype.constructor == Object) //true
console.log(person1 instanceof Person) // true
复制代码
function Person(){};
var person1 = new Person()
Person.prototype = {
name: 'li',
age: 20,
sayName: function(){
console.log(this.name)
}
};
person1.sayName() //person1.sayName is not a function
复制代码
先建立实例,在重写其原型对象,会切断现有原型与以前任何已经存在的对象实例之间的联系。person1引用的仍是原来的原型。能够用下面这种写法
function Person(){};
var person1 = new Person()
Person.prototype.sayName = function(name){
console.log(name)
}
person1.sayName('li') //li
复制代码
var Person = function(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name)
};
var person1 = new Person('li',20)
var person2 = new Person('xiao',18)
person1.sayName() //li
person2.sayName() //xiao
复制代码
function Person(name, age){
this.name = name;
this.age = age
if(typeof this.sayName != function) {
Person.prototype.sayName = function(name){
console.log(this.name)
}
}
};
复制代码
判断这个代码只会在初次调用构造函数时执行
js只支持实现继承 主要是依靠 原型链 来实现的.
利用原型让一个引用类型继承另外一个引用类型的属性和方法
方法:
每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针。那么,若是咱们让原型对象等于另外一个类型的实例,此时的原型对象将包含一个指向另外一个原型的指针,相应的,另外一个原型中也包含着一个指向另外一个构造函数的指针,假如另外一个原型又是另外一个类型的实例。。。如此层层递进,就构成了实例和原型的链条
若是引用对象(实例instance)的某个属性,会如今这个对象内找,若是找不到,就会到这个对象的原型上去找,原型上找不到,就到原型的原型上去找,直到找到这个属性或者返回null为止
function Parent(name) {
this.name = name
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Children(age) {
this.age = age
}
Children.prototype = new Parent('Amy') //子类的原型是父类的实例
let instance = new Children(10)
instance.sayName()
复制代码
在子类型构造函数的内部调用超类型构造函数
没法复用函数,全部类型只能使用构造函数模式
原型链和借用构造函数组合,使用原型链实现对原型属性和方法的继承,经过借用构造函数来实现对实例属性的继承
function Parent(name) {
this.name = name
this.colors = ['red']
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Children(name,age) {
Parent.call(this,name);
this.age = age
}
Children.prototype = new Parent()
let instance1 = new Children('Amy',10)
instance1.sayName()
instance1.colors.push('green')
console.log(instance1.colors)
let instance2 = new Children('Mike',20)
instance2.sayName()
instance2.colors.push('blue')
console.log(instance2.colors)
复制代码
调用两次超类型构造函数,
function object(o) {
function F(){};
F.prototype = o; //F的原型指向传入的对象o
return new F()
}
复制代码
Object.create(),这个方法接收两个参数,一个是用做新对象原型的对象和(可选)一个为新对象定义额外属性的对象,只有一个参数时,Object.create()与Objec()同样
包含引用类型值的属性始终都会共享相应的值
建立一个仅用于封装继承过程的函数。不能作到函数复用
经过借用构造函数来实现对实例属性的继承,经过原型链的混成模式来继承方法。仅调用一次超类型构造函数,避免建立没必要要的多余的属性
function Parent(name) {
this.name = name;
this.colors = ['yellow']
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Children(name,age) {
Parent.call(this,name);
this.age = age
}
function inheritPrototype(parent,children) {
var prototype = Object(parent.prototype)
prototype.constructor = children;
children.prototype = prototype
}
inheritPrototype(Parent, Children);
var instance1 = new Children('li', 20)
instance1.sayName()
复制代码
ES5 的继承,实质是先创造子类的实例对象this,而后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制彻底不一样,实质是先将父类实例对象的属性和方法,加到this上面(因此必须先调用super方法),而后再用子类的构造函数修改this。
若是子类没有定义constructor方法,这个方法会被默认添加,在子类的构造函数中,只有调用super以后,才可使用this关键字,不然会报错。这是由于子类实例的构建,基于父类实例,只有super方法才能调用父类实例。