今天听了学长的分享会,感觉加深了自己对原型的理解,所以写个小作文记录一下。
原型基础知识:
1.prototype 属性
function Person(name,age){
this.name = name;
this.age = age;
this.sayname = function(){
alert(this.name);
}
}
var person1 = new Person('kang','90');
1.解析:
这里的person1为Person的一个实例,每个实例都有一个constructor属性,该属性
是一个指针指向Person
console.log(person1.constructor == Person); //true
事实上每个函数对象都会有一个prototype属性,这个属性指向函数的原型对象。
实际上换一种写法或许更加明白
Person.prototype = {
name:"kang",
age:29,
sayname:function(){
console.log("...");
}
}
所以原型对象就是Person.peorototype而原型对象回又一个constructor属性,该属性指向构造函数
//console.log(Person.prototype.constructor == Person); //true
2.proto 属性
JS 在创建对象(不论是普通对象还是函数对象)的时候,
都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。
以上述例子为例
function Person(name,age){
this.name = name;
this.age = age;
this.sayname = function(){
alert(this.name);
}
}
var person1 = new Person('kang','90');
解析1: 实例person1有一个__proto__属性,创建它的构造函数时Person,
构造函数的原型对象是Person.prototype,所以有
console.log(person1.__proto__ == Person.prototype) //true
而继承就是以原型链为基础进行引申,废话不多说开始继承
/第一种继承方式:原型式继承/
Father.prototype.qq = "861918672";
function Father(name,age){
this.name = "kang"|| name;
this.age = "100" || age;
this.car = ["bmw","lanbo","masha"];
}
Son.prototype = new Father();
function Son(){
}
var son1 = new Son();
var son2 = new Son();
console.log(son1.name) // kang
console.log(son1.age) //100
console.log(son1.car) //["bmw", "lanbo", "masha"]
console.log(son1.qq);//861918672
//第一个缺点: 不能传参
// var son3 = new Father("tom","29");
// console.log(son3.name); //kang
// console.log(son3.age); //100
//解析:可以看出虽然添加了参数,但是做了无用功
//第二个缺点:引用值共享
// son1.car.push("dazhong");
// console.log(son1.car); //["bmw", "lanbo", "masha", "dazhong"]
// console.log(son2.car); //["bmw", "lanbo", "masha", "dazhong"]
//解析:可以看出实例son1和son2都可以共享car属性
** 第二种继承方式:借用构造函数实现继承 (伪造对象或者经典继承)**
Father.prototype.qq = "861918672";
function Father(name,age,car){
this.name = name;
this.age = age;
this.car = car;
}
function Son(name,age,car){
Father.call(this,name,age,car);
}
var grandson1 = new Son("kang","99",["baoma"]);
var grandson2 = new Son("jiahao","98",["benchi"]);
console.log(grandson1.name); //kang
console.log(grandson1.age); //99
console.log(grandson1.car); //["baoma"]
优点:解决了引用值共享和传参的问题
缺点:不能继承父亲原型链上的属性:
console.log(grandson1.qq); //undefined
** 3.组合继承 通过上面两种继承方式,我们可以发现,原型链式继承不能传递参数,
而经典继承不能继承父类原型链上的方法,所以组合继承就时由这两种继承方式组成。**
Father.prototype.qq = "861918672";
function Father(name,age,car){
this.name = name;
this.age = age;
this.car = car;
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
function Son(name,age,car){
Father.call(this,name,age,car);
}
var son1 = new Son("kang","29","baoma");
console.log(son1.name) // kang
console.log(son1.age) //29
console.log(son1.car) //baoma
console.log(son1.qq);//861918672
可以看见,组合继承完美弥补了上面两种继承方式的缺点,也是用的最多的一种继承方式。先使用原型继承方式,使得子类可以继承到父类原型上的方法,之后使用经典继承使得子类可以继承父亲身上的方法。为保证 son和 son2 拥有各自的父类属性副本,我们在 Son 构造函数中,还是使用了 Person.call ( this ) 方法,这样他们可以有属于自己的属性,也可以使用相同的方法了。如此,结合原型链继承和借用构造函数继承,就完美地解决了之前这二者各自表现出来的缺点。
缺点:两次调用构造函数,效率低。
改变了子类的construcotr指向
** //第四种继承:4.原型式继承**
function Object(o){
function F(){}
F.prototype = o;
return new F();
}
var obj = {
name:'kang',
sex:'man',
saymymessage:function(){
return this.name + this.sex;
},
skills:['唱','跳','rap']
}
var obj2 = Object(obj);
var obj3 = Object(obj);
console.log(obj2.name) //"kang"
console.log(obj2.sex) //"man"
console.log(obj2.saymymessage()) //"kangman"
console.log(obj2.skills); //(3) ["唱", "跳", "rap"]
//缺点和原型链继承一样:不能传参,并且引用值共享
obj2.skills.push("篮球");
console.log(obj2.skills); //(4) ["唱", "跳", "rap", "篮球"]
console.log(obj3.skills); //(4) ["唱", "跳", "rap", "篮球"]
** /第五种继承:.寄生式继承。寄生式继承就是把原型式继承再次封装,
然后在对象上扩展新的方法,再把新对象返回
/
//寄生式继承
// function object(o){
// function F(){} //创建了一个对象
// F.prototype = o; //将这个对象原型指向传入的函数
// return new F(); //返回一个对象的新实例 其实就是 传入对象的一个实例
// }
// function createAnother(original){
// var clone = object(original); // clone是original的一个实例
// clone.sayHi = function(){ //增强这个对象
// alert("Hi");
// }
// return clone; //返回这个对象
// }
// var obj = {
// name:'kang',
// age:'19'
// }
// var obj2 = createAnother(obj);
//缺点:无法实现函数的复用
** /第六种继承:6.寄生组合式继承(目前最完美的继承方式)/**
Father.prototype.sayName = function (){
alert(this.name)
}
function Father(name,age){
this.name = name;
this.age = age;
}
function Son(name,age){
Father.call(this,name,age);
}
//继承函数
function inheritPrototype(Son,Father){
//中间实例化对象
var a = Object(Father.prototype);
//重写该对象的构造函数指针,指向Sub函数
a.constructor = Son;
//Sub的原型指向实例化对象a
Son.prototype = a;
}
//调用继承函数,实现原型链构造
inheritPrototype(Son,Father);
//测试代码
var son1 = new Son("lulu",20);
console.log(son1.name) //lulu
console.log(son1.age) //20