二十五、JS的几种继承

一、JS中this的四种使用情况

在函数执行时,this总是指向调用该函数的对象;判断this的指向,即判断this所在的函数属于谁

1.当函数有所属对象时,指向所属对象:

例如  var object=document.getElementById("object");

  object.onclick=function(){

console.log(this);  //这里this指向object 事件执行对象

}

 

2.当函数没有所属对象:指向window

例如 function fn(){

        console.log(this.value);  //未定义undefined

        console.log(this); //输出window

    }

    fn();

与直接在<script></script>内写console.log(this)都会输出window;

 

3.构造函数中的this:指向新对象  

Js中通过new关键字调用构造函数,this会绑定在该新对象上;

例如  

function animal(){

         this.value=100; //this代表当前实例化的对象 cat

    }

    var cat=new animal();//实例化一个对象  实例化即new...

    console.log(cat.value);  //100

 

   var fn=function(){

       this.value=100;

   }

   var fun=new fn();

   console.log(fun.value); //100

 

4.apply和call调用以及bind绑定:指向绑定的对象

  apply()方法:两个参数 函数运行作用域 参数数组

  call()方法:两个参数 函数运行作用域 参数列举

二者用法一致都是替换对象, 不同的是第二个参数apply需传递array形式的数组给它,二者可以互相转换,call方法更接近一般调用函数;

  bind()方法会返回一个新方法,新方法的this会绑定传入对象;

例如

   var object={value:1};

   var fn=function(){

       console.log(this);//this指fn

   };

   fn(); //window

   fn.apply(object);//object={value:1}

   fn.call(object);  //object={value:1}

//apply()与call()都是将object对象复制到fn()中

   var newfn=fn.bind(object);

   console.log(newfn);//输出函数

   newfn();//object={value:1}

//bind返回的是新方法 调用需要添加()

 

二、JS几种继承  继承简单来说即子类继承父类的方法/属性

添加类的方法有两种方法:实例方法 原型方法

首先定义一个父类:

function animal(name){

//添加类的属性

this.name=name;

this.sex=;

//添加类的方法一 实例方法

this.eat=function(){

Return this.name+正在吃饭;

}

}

//添加类的方法二 原型方法

animal.prototype.snidelcolor=function(){

return this.name+的毛色是白色;

}

 

1.原型链继承:将父类的实例作为子类的原型

  优点:纯粹的继承关系,实例是子类的实例,也是父类的实例,父类新增原型方法、属性,子类都可以调用(访问);

  缺点:为子类新增属性和方法,需在实例化(new 方法()语句)之后执行,不能放到构造器中无法实现继承;?

  创建子类实例时,无法向父类构造函数传参;

 

例如

//创建一个子类

function cat(){

         this.weight="20kg";

         this.sleep=function(){

             return this.name+"正在睡觉";

         }

 

     }

    //原型继承  cat继承animal方法属性

    cat.prototype=new animal("猫");

    

//子类新增属性和方法需在实例化之后

    cat.prototype.type=function(){

        return this.name+"是猫科动物";

    };

 

     var Cat=new cat();

    //访问继承的父类的属性 方法

    console.log(Cat.name);

    console.log(Cat.sex);

    console.log(Cat.eat());

    console.log(Cat.snidelcolor());

    //访问子类本身的属性 方法

    console.log(Cat.type());

    console.log(Cat.sleep());

    console.log(Cat.weight);

    //验证  实例是子类的实例,也是父类的实例

    console.log(Cat instanceof animal); //true

    console.log(Cat instanceof cat); //true

 

2.构造继承:在子类构造函数内部调用父类,通过使用call()和apply()方法在新创建的对象上执行构造函数;即可以理解为使用父类的构造函数增强子类实例,复制父类的实例属性方法给子类(未用到原型)

  优点:创建子类实例时,可向父类传递参数,可实现多继承(call多个父类对象)

  缺点:实例只是子类的实例,不是父类的实例;只能继承父类的实例属性和方法,不能继承原型方法的属性/方法;无法实现函数复用,每个子类都有父类实例函数的副本,影响性能;

例如

//创建子类

function dog(name){

animal.call(this);//复制父类属性给子类

this.name=name;

}

var Dog=new dog("狗");

//访问继承的父类的属性和方法

console.log(Dog.eat());

console.log(Dog.name);

console.log(Dog.sex);

/* console.log(Dog.snidelcolor());//报错 构造函数无法调用到原型方法*/

//构造函数只能继承父类的实例属性和方法,不能继承原型属性/方法

//实例只是子类的实例,不是父类的实例

 console.log(Dog instanceof dog); //true

 console.log(Dog instanceof animal);//false

 

3.实例继承:

优点:不限制调用方式,不管是new子类()还是子类(),返回的对象都具有相同的效果

缺点:实例是父类的实例,不是子类的实例;

 

例如

function cat(name){

var newcat=new animal();//子类中实例化父类

newcat.name=name;

Return newcat;

}

var Cat=new cat("tom");//实例化 子类

console.log(Cat.name);//tom  name实参传给子类输出 父类undefinded

console.log(Cat.sex);//

console.log(Cat.eat());

console.log(Cat.snidelcolor());

console.log(Cat instanceof cat); //false

console.log(Cat instanceof animal);//true

//实例继承中 实例只是父类的实例不是子类的实例

 

4.组合继承:将原型链和构造继承组合一起,弥补构造继承不能访问原型方法的缺点;

实例即使子类的实例也是父类的实例;

缺点:生成两个实例,消耗内存;

例如

 function dog(name){

         animal.call(this);//构造继承

        this.name=name;

    }

    dog.prototype=new animal();//原型链继承

    var Dog=new dog("tom");//实例化子类 传参只能传给子类

    console.log(Dog.name);

    console.log(Dog.sex);

    console.log(Dog.eat());

    console.log(Dog.snidelcolor());

    console.log(Dog instanceof animal);//true

console.log(Dog instanceof dog);//true

 

5.原型式继承:通过原型可基于已有对象创建新对象,同时 还不必须因此创建自定义的类型;

例如

var cat={

     name:"tom",friend:["jery"]

   };

var anothercat=Object(cat);//原型式继承

    anothercat.name="john";

    anothercat.friend.push("Bob");

    console.log(cat.friend);// ["jery", "Bob"]

 

ECMscript5通过新增Object.create()方法规范了原型式继承,两个参数 用作新对象原型的对象和作为新对象定义额外属性的对象;

例如

var cat={

     name:"tom",friend:["jery"]

   };

   var anothercat=Object.create(cat);//原型式继承

   anothercat.name="john";

   anothercat.friend.push("Bob");

   console.log(cat.friend);// ["jery", "Bob"]

 

6.寄生式继承:创建一个仅用于封装继承过程的函数,该函数内部以某种方法增强对象,最后返回对象;

例如

 function creat(res) {

   var a=Object(res);

   a.say = function () { //构造方法

       alert("hi");

   };

   return a;

   }

   var cat={

       name:"tom",friend:["jery"]

   };

   var anthor=creat(cat);//将cat对象作为参数传递给create()

   anthor.say();//弹出hi

 

7.寄生组合式继承:组合式指构造函数属性的继承和建立子类和父类原型的链接两部分。

通过借用构造函数来继承属性;通过原型链来继承方法。

实例即使子类的实例 也是父类的实例;

constructor 属性返回对创建此对象的数组函数的引用;

语法:object.constructor

  例如

   function addPrototype(son, father){

        var protoType = Object.create(father.prototype); //创建对象

        //Object.create()方法参数 用作新对象原型的对象

        protoType.constructor = son;     //增强对象

        //constructor 属性返回对创建此对象的数组函数的引用;

        son.prototype = protoType;      //指定对象

    }

 

    /*定义一个父类*/

    function father(name){

        this.name = name;

        this.colors = ["red", "blue", "green"];

    }

    father.prototype.sayName = function(){  //父类添加原型方法

        return this.name;

    };

    /*定义一个子类*/

    function son(name, age){

        father.call(this, name); //构造继承

        this.age = age;

    }

    addPrototype( son, father); //调用addPrototype函数

    son.prototype.sayAge = function(){ //添加子类原型方法

        return this.age;

    };

    var newson = new son("Bob", 18); //实例化子类

    console.log( newson.sayName());

    console.log( newson.sayAge());

    console.log(newson instanceof son); //true

    console.log(newson instanceof father);//true

猜你喜欢

转载自blog.csdn.net/weixin_40976555/article/details/80501283