javascript继承

标签(空格分隔):javascript javascript基础


原型链

var Super = function(){
    this.name="Super";
    this.arr = ['a','b','c'];
}
Super.prototype.getName = function(){
    alert(this.name);
}

var Sub = function(){
    this.age=12;
}
Sub.prototype = new Super();    //看在这里的时候我常在想为什么不直接Sub.prototype=Super.prototype,要new一个出来,解释【2】

var sub1 = new Sub();
var sub2 = new Sub();

sub1.arr.push('d');
console.log(sub1.name);
console.log(sub2.name);
sub1.name = 'kealin';   //这里不是改的Super里的name,看下面的解释【1】
console.log(sub1.name,sub2.name);  //kealin Super
console.log(sub1.arr)   //[a,b,c,d]
console.log(sub2.arr);  //[a,b,c,d]

解释__[1]__

    sub1的结构
        Sub
            name:kealin
            age:12
            proto:Object
                name:Super
                arr:Array[3]
                proto:Super
                    constructor:Super
                    getName:function
    sub2的结构
        Sub
            age:12
            proto:Object
                name:Super
                ......
    //不是引用类型的,都直接在对象上声明

解释__[2]__

var Super = function(){
    this.name="Super";
    this.arr = ['a','b','c'];
}
Super.prototype.getName = function(){
    alert(this.name);
}

var Sub = function(){
    this.age=12;
}
Sub.prototype = Super.prototype;
//不要忘记了原型对象也是引用类型,后面改到的Sub.prototype也会反应到Super.prototype,
//他们俩的原型对象是一个对象,这里就根本不是继承了
Sub.prototype.getName = function(){ 
    console.log('haha');
}
Sub.prototype.getAge = function(){
    alert(1);
    return this.age;
}

var sub1 = new Sub();
var super1 = new Super();
super1.getName();   //haha   访问父类的getName是访问不到的,没有继承的概念在里面了。
super1.getAge();    
sub1 instanceof Super //true


缺点

  1. 引用类型的问题,在父类里声明的引用类型将都是共享的
  2. 不能在不影响所在实例的情况下(一改就都改了)向父类的构造函数里传递参数,多个实例肯定有属性是不同的。

借用构造函数

var Super = function(name){
	this.name=name
	this.arr = ['a','b','c'];
	this.getName = function(){
		return this.name
	}
}

var Sub = function(name){
    //构造函数也是方法,所以可以用call和apply来改变父类方法的执行环境,继承(我觉得这里不是继承)父类里的属性
    //而且传递了参数
	Super.call(this,name);
	this.age = 12;
}

var sub1 = new Sub('kelly');
var sub2 = new Sub('haha');
console.log(sub1.name);						//kelly
console.log(sub2.name);						//haha
sub1.arr.push('d');
console.log(sub2.arr);						//[a,b,c]
console.log(sub1.getName==sub2.getName);	//false

缺点

跟构造函数模式一样,公用的引用类型不能共用,sub1的数组改了,sub2没有改,而且getName方法也不一样


组合继承

function Super(name){
    this.name = name;
    this.arr = [1,2,3,4];
}
Super.prototype.getName = function(){
    return this.name;
}

function Sub = function(name,age){
    Super.call(this,name);        //第二次调用父类构造函数
    this.age = age;
}
Sub.prototype = new Super();     //第一次调用父类构造函数
Sub.prototype.getAge = function(){
    return this.age;
}

var sub1 = new Sub();
var Super1 = new Super();
console.log(sub1.constructor.name)  //''

优点

避免了原型链里引用类型公用的问题和借用构造函数造成的方法不能公用的问题,而且可以通过构造函数来向父类中传递参数。
所以一般是通过构造函数来继承属性,通过原型链的继承方法

缺点

调有两次构造函数,导致Sub在prototype创建了多余的属性[name,arr]
第一次调用Super的构造函数是设置Sub.prototype,这个时候Sub的原型上己经有name和arr两个属性了
第二次,实例Sub对象,调用Sub构造函数,在构造函数里调用的Super的构造函数。这个时候实例对象也有了name,arr。
通过sub1.name时候其实是覆盖了原型里的name,所以sub1.constructor.name的值为''

一个傻傻的问题

给Sub.prototype赋值时,为什么不直接Sub.prototype==Super.prototype,这样也不会有原型上产生两个多余的属性了,然后我做了试验
后面的寄生组合继承其实是Sub.prototype = Super.prototype模式,只是相似

var Super = function(name){
	this.name=name
	this.arr = ['a','b','c'];
}
Super.prototype.getName = function(){
	return this.name;
}

var Sub = function(name){
	Super.call(this,name);
	this.age = 12;
}

Sub.prototype = Super.prototype;    //赋值后Sub与Super的原型都是一样了
Sub.prototype.constructor = Sub;    //这个时候操作的也是Super的原型,这样就不是继承了,完全是Super的原型都改了
Sub.prototype.getAge = function(){  //傻傻我纠结了这么久
	return this.age;
}

Sub.prototype.getName = function(){
	console.log('haha');
}

var sub1 = new Sub('kelly');
var super1 = new Super('haha');

console.log(sub1.constructor === super1.constructor);	//true,
console.log(super1.constructor)							//Sub
console.log(super1 instanceof Super);					//true
console.log(super1 instanceof Sub);						//true
console.log(sub1 instanceof Super);						//true	
// a instanceof b a是否是b的实例  a原型链上其中一个__proto__===b.prototype
// Function instanceof Function  //true
// Number instanceof Function 	//true
// Number instanceof Number		//false,Number其实是个方法,都继承自Function
//      Number.__proto__ = Function.prototype!=Number.prototype,
//      Function.prototype.__proto__=Object.prototype!=Number.prototype,
//      Object.prototype.__proto__=null!=Number.prototype.
//      所以为false
console.log(sub1.__proto__===Super.prototype)			//true
console.log(super1.getAge);
super1.getName();

原型式继承

function object(o){
	var F = function(){};   //一个空的构造函数名得里面包含多余的属性
	F.prototype = o;        //需要提供一个原型对象
	return new F();
}


var person = {
	name:'kaleys',
	friends:['a','b']
}
var person1 = object(person);
person1.name = 'kelly';
person1.friends.push('d');

var person2 = object(person);
console.log(person2.name);
console.log(person2.friends);   //a,b,d

//Object.create是ECMAScript5提出来的,IE9+
var person3 = Object.create(person);    //Object.create与object方法一样的效果
console.log(person3);

用途

让一个对象与另一个对象保先类似的情况

缺点

引用类型会共享值

寄生式继承

寄生组合式继承

var Super = function(name){
    this.name = name;
    this.getName();
}
Super.prototype.getName = function(){
    return this.name;
}

var Sub = function(name,age){
    Super.call(this,name);  //只在这里调用一Super的构造函数
    this.age = age;
}

//寄生开始,所谓寄生就是在原有的对象上进行增强,比如说增加一个方法,改变一个属性行吗
function myInstance(o){
    var F = function(){}
    F.prototype = o;
    return new F();
}
Sub.prototype = myInstance(Super.prototype);
Sub.prototype.constructor = Sub;


//寄生结束


Sub.prototype.getAge = function(){
    return this.age;
}

var sub1 = new Sub('kelly','12');

sub1的结构

posted on 2016-05-20 16:02  萝卜正好  阅读(143)  评论(1)    收藏  举报