神刀安全网

javaScript-原型、继承

原型链

首先回顾下实列、构造函数、原型对象之间的关系;

实列都包含指向原型对象的一个指针(_proto_);

构造函数都有prototype(原型属性)指向原型对象的指针;

原型是一个对象也存在一个内部属性(_proto_)指向父类(上一级)原型对象;

那么原型链就是:实例通过 _proto_ 递归往上查找就构成实例与原型的链条(object除外,它是基类);

 function Person(){      } 

链图: javaScript-原型、继承

总结:

1、所有引用类型默认都继承Object

2、所有函数的默认原型都是Object的实例,类似于:原型对象=new Object(),因此默认原型都会包含一个内部指针(_proto_),指向Object.Prototype;

3、所有引用类型对象都有_proto_属性指向原型对象,所有function 对象都有prototype 属性,指向原型对象;

原型链-继承

我所知道的继承有两种方式:

1、接口继承:只继承方法签名;

2、实现继承:继承实际的方法;

因为js中函数没有签名所以无法实现接口继承,只支持方法继承,并且是依靠原型链来实现的;

     function Person(name, age, sex) {         this.name = name;         this.age = age;         this.sex = sex;      }     Person.prototype.sayHello=function(){ console.log("hello word!")};     function Man(){     }     Man.prototype=new Person();     var instance=new Man();     console.log(instance.sayHello);// hello word! 

以上就是很简单的继承,把Man原型指针指向Person的一个实例,这样new Man()的实例就可以访问到Person中的sayHello方法,如图所示;

javaScript-原型、继承

原型链也是存在一些问题把上面代码改下:

     function Person(name, age, sex) {         this.name = name;         this.age = age;         this.sex = sex;         this.color=["red","blue","green"];      }     Person.prototype.sayHello=function(){ console.log("hello word!")};     function Man(){     }     Man.prototype=new Person();     var instance=new Man();     instance.color.push("black");     console.log(instance.color);//["red", "blue", "green", "black"]     var instance2=new Man();     console.log(instance2.color); //["red", "blue", "green", "black"] 

我们知道原型是所有实例共享属性、方法,当使用原型来实现继承时,原型实际上会变成另一个类型的实例,所以就会出现上面的问题;

组合继承

组合继承的原理很简单,在构造子类对象实例的时候通过改变this 指针让子类对象实例拥有父类属性以及自身构造的属性,这样可以达到实例之间有独立的属性副本,

方法的继承还是通过原型来实现,来看代码:

   function Person(name, age, sex) {         this.name = name;         this.age = age;         this.sex = sex;         this.color=["red","blue","green"];      }     Person.prototype.sayHello=function(){ console.log("hello word!")};      function Man(name,age,sex,job){         Person.call(this,name,age,sex);         this.job=job;     }     Man.prototype=new Person();     var instance=new Man("张三",20,"男","农民");     instance.color.push("black");     console.log(instance.color);//["red", "blue", "green", "black"]     console.log(instance.job);//农民     console.log(instance.sayHello);//hello word!      var instance2=new Man("张三",20,"男","地主");     console.log(instance2.color); //["red", "blue", "green"]     console.log(instance2.job);//地主     console.log(instance2.sayHello);//hello word! 

通过在构造函数中指向父类,这样实例对象存在父类的属性,前面说过搜索原理是从实例开始的,那么即使是原型对象是父类的实例对象,属性还是取的是实例对象中的属性;

组合模式是JavaScript中常用的继承方式;

call、apply、bind(绑定)

JavaScript中函数可以通过3种方法改变自己的this指向,它们是call、apply、bind。它们3个非常相似,但是也有区别。下面表格可以很直观看出三者的不同

方法 是否直接执行函数 传入的参数 调用方式
call

(context,arg1,arg2,arg3…)

第二个参数之后都是实参

function.call(context,arg1,arg2,arg3…)

apply

(context,[arg1,arg2,arg3…])

第二个参数必须是数组

function.apply(context,[arg1,arg2,arg3…])

bind

(context,arg1,arg2,arg3…)

第二个参数之后都是实参

var newFunction = function.bind(context);

newFunction(arg1,arg2,arg3…)

call和apply功能:使用指定的对象调用当前函数。call和apply的功能完全相同,只是在语法上略有不同。

call :

 var a = {x: 1};     var b = function (y, z) {         console.log(this.x + y + z)     };     b.call(a, 3, 4);//此时b的this(即b执行时的上下文)被改变为a,因此this.x为1,第二个参数之后都是传给b实参。 

apply:

  var a = {x: 1};     var b = function (arr) {         console.log(this.x + arr[0] + arr[1])     };     b.call(a, [3, 4]);//此时b的this(即b执行时的上下文)被改变为a,第二个参数是一个数组 

bind:

 var a = {x: 1};     var b = function (y, z) {         console.log(this.x + y + z)     };     var newB = b.bind(a);//此时b的this(即b执行时的上下文)被改变为a,由此生成一个新函数,函数不会立即执行。     newB(3, 4);//函数此时才执行 

call或apply是将执行上下文对象换了后,立即执行;而bind是将执行上下文对象换了后,创建一个新函数。

 function fun(){                console.log(this.name);            }            function obj1(){                this.name = 'call||apply';            }            function obj2(){                this.name = 'bind';            }            var o1 = new obj1();            var o2 = new obj2();            fun.call(o1);            //手动调用bind创建的新函数            fun.bind(o2)(); 

javaScript-原型、继承

在网上找了张比较完整原型链图: javaScript-原型、继承

总结

1、原型链的形成真正是靠 _proto_,指向原型对象;

2、引用类型默认都继承Object;

3、所有函数的默认原型都是Object 实例,即默认原型对象也有一个内部属性 _proto_指向 Object prototype 对象;

4、Function.prototype是函数类型的原型;

5、继承主要是基于原型链实现的,而原型链主要是基于实例与原型对象链条实现,引用类型任何对象都有内部属性 _proto_指向原型对象;

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » javaScript-原型、继承

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址