ES5对象的创建和三种继承方法

对象

1.对象字面量

var obj={name:'moon',age:18}

2.构造函数

var obj1 = new Object();
obj1.name="moon";
obj1.age = 18;

3.工厂模式

因为使用普通的字面量创建多个对象时,会产生大量的重复代码,为了解决这个问题,我们引入工厂模式
       

function newDog(name,age,gender){
          var d = new Object();
          d.name = name;
          d.age = age;
          d.gender = gender;
          d.sayName = function(){
              console.log("汪汪的名字是"+this.name);
          }
          return d;
        }
        var d1 = newDog('二哈',2,'男');

目的:通过将创建对象的方法封装起来,避免重复代码产生
缺点:创建的所有对象类型都是Object对象,没有办法知道对象到底是Person还是Dog。

4.构造函数模式

        function Person(name,age,gender){
          this.name=name;
          this.age=age;
          this.gender=gender;
          this.sayName=function(){
          console.log(this.name);
        }
        }
       var p1 = new Person('平菇',5,'man');
       p1.sayName();//平菇
       console.log(p1);
/*p1 结果
Person {        
  name: '平菇', 
  age: 5,       
  gender: 'man',
  sayName: [Function (anonymous)]
}
*/
       console.log(typeof p1);//object

       构造函数的问题
       1.可以区分每个类
       2.每个方法都要在每个实例上重新创建一遍,没有必要
       3.虽然可以将方法提取出来,提取到全局范围内,然后将引用传递给对象中的函数属性,但是全局函数太多的话,体现不了类的封装性。

5.原型模式

function Person(){};
Person.prototype.name="moon";
Person.prototype.likes=['eat','run'];

var per1 = new Person();
console.log(per1.name);//moon
per1.likes.push('fly');//我们想要的是p1的likes加上一个fly
console.log(per1.likes)//这里fly加上了[ 'eat', 'run', 'fly' ]

var per2 = new Person();
console.log(per2.name);//moon
console.log(per2.likes);
//这里我们并不想让p2的likes改变,可是p2的likes也被改变了
//也是[ 'eat', 'run', 'fly' ],因为两个likes指向了同一地址值。

原型模式的特点
对于共享属性,共享函数使用这种方法是非常合适的,但是对于引用类型的数据就不太好了

6.构造函数模式和原型模式结合

                //在构造函数中放私有的属性
                function Person(name,age,gender){
                this.name=name;
                this.age=age;
                this.gender=gender;
                this.likes=['琵琶','笛子','卡卡']}
            
                //在原型中放实例属性和实例方法
                Person.prototype={
                 constructor:Person,
    //这里把Person的原型写成了一个对象,注意把constructor指针指回去
                 sayName:function(){
                 console.log(this.name);
                     }
                 }

                 var p1 = new Person('平菇',2,'男');
                 p1.likes.push('魔法');

                 var p2 = new Person('小马',22,'女');
                 p2.likes.push('吃饭');
                 console.log(p1);
                 console.log(p2);
                 p1.sayName();
                 p2.sayName();
                
                /* Person {
                    name: '平菇',
                    age: 2,
                    gender: '男',
                    likes: [ '琵琶', '笛子', '卡卡', '魔法' ]
                    }
                    Person {
                    name: '小马',
                    age: 22,
                    gender: '女',
                    likes: [ '琵琶', '笛子', '卡卡', '吃饭' ]
                    }
                    平菇
                    小马*/

这样就解决了构造函数模式和原型模式的问题。

继承

1.原型链继承


        每个构造函数都有一个原型对象,原型对象中都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。当原型对象等于另外一个类型的实例即继承。
        调用某个方法或者属性的步骤
            a.搜索实例
            b.搜索原型
            c.搜索父类原型

            //定义父类类型
            function Animal(){
                this.name = "animal"	
            }
            Animal.prototype = {
                constructor:Animal,
                sayName : function(){
                console.log(this.name);
                }
            }

            //定义子类类型
            function Dog(){
                this.color = "灰色"
            }
            //通过将子对象的原型对象指向父对象的一个实例来完成继承
            Dog.prototype = new Animal();
            //子对象的方法其实是定义在了父类对象的实例上。
            Dog.prototype.sayColor = function(){
                console.log(this.color);
            }
            var dog = new Dog();
            console.log(dog);//Animal { color: '灰色' }
            dog.sayColor();//灰色
            dog.sayName();//animal

 谨慎定义方法
        子类型覆盖超类型中的某个方法,或者是需要添加超类中不存在的方法,都需要将给原型添加方法的代码放在继承之后(即替换原型的语句之后)
原型链问题
        1)通过原型来实现继承时,原型实际上会变成另一个类型的实例,原来的构造函数内的属性也就变成了现在的原型属性
        2)在创建子类型的实例时,不能向超类型的构造函数传递参数。因此实践中很少会单独使用原型链

2.经典继承

            不仅可以继承方法,也可以继承属性
            也称 "伪造对象" 或 "经典继承",在子类型构造函数的内部调用超类型构造函数。函数不过是在特定环境中执行代码的对象,因此通过apply(),call()方法可以在(将来)新建对象上执行构造函数,即    在子类型对象上执行父类型函数中定义的所有对象初始化的代码。结果每个子类实例中都具有了父类型中的属性以及方法
     

function Animal(name){
  this.name = name;
  this.colors = ["red","gray"];
}
function Dog(name){
  //继承了Animal
  Animal.call(this,name);
  this.color = "gray";
}
Animal.prototype.sayName = function(){
  console.log(this.name);
}

var dog = new Dog("ling");
dog.colors.push("hhh");
console.log(dog);//Dog { name: 'ling', colors: [ 'red', 'gray', 'hhh' ], color: 'gray' }
  //如果将函数定义在构造函数中,函数复用无从谈起
// dog.sayName();	//报错
  //在超类型的原型中定义的方法,对于子类型而言是无法看到的

3.组合继承


原型链继承+经典继承组合起来继承构造函数的属性和方法,以及原型中的属性和方法
也称"伪经典继承",将原型链和借用构造函数的技术组合在一起。

原理是:使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对私有属性的继承。
               

                function Animal(name){
                this.name = name;
                this.colors = ["red","gray"];
                }
                function Dog(name){
                //继承了Animal(属性)
                Animal.call(this,name);
                this.color = "gray";
                }
                Animal.prototype.sayName = function(){
                console.log(this.name);
                }
                //继承方法
                Dog.prototype = new Animal();
                Dog.prototype.constructor = Dog;//指向Dog构造函数,

                var dog = new Dog();
                dog.colors.push("hhh");
                console.log(dog);
                var animal = new Animal();
                console.log(animal);
                dog.sayName();	//可以调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值