function Person() {//被继承的函数叫做超类型(父类,基类)this.name="mumu";this.age="18";}Person.prototype.name="susu";//当属性名相同时需就近原则,先在实例里面查找,没找到再到原型里找 function Worker(){ //继承的函数叫做子类型(子类,派生类)this.job="student";}Worker.prototype=new Person();//通过原型链继承,超类型实例化后的对象实例,赋值给子类的原型属性var p2=new Worker(); console.log(p2.name);console.log(p2 instanceof Object);//ture 所有的构造函数都继承自Object以上实现继承关键在于:Worker.prototype=new Person(); 将Worker的原型成为Person的一个实例,通过原型链继承。function Person() {this.bodys=["eye","foot"];}function Worker(){ }Worker.prototype=new Person();var p1=new Worker();p1.bodys.push("hand");var p2=new Worker(); console.log(p1.bodys);console.log(p2.bodys);
2.在创建子类型的实例时,不能像超类型的构造函数中传递参数。
那么如何解决原型链的两个问题呢?那就继续看下面的继承方式吧~
二. 借用构造函数继承(也叫对象冒充,伪造对象或经典继承)
function Person(name,age){this.name=name;this.age=age;this.bodys=["eye","foot"];}Person.prototype.showName=function(){console.log(this.name);}function Worker(name,age,job){Person.call(this,name,age);this.job=job;//子类添加属性}var p1=new Worker("mumu","18","学生"); p1.bodys.push("hand") ;var p2=new Worker();console.log(p1.name);console.log(p2.bodys);console.log(p1.showName());
简单分析下以上使用借用构造函数的原理:Person.call(this,name,age);这句代码调用父级构造函数,继承父级属性,使用call方法调用Person构造函数改变函数执行时候的this, 这里的this-> new出来的一个Worker对象 构造函数伪装方法:把Worker传给上面的Person。
当引用类型放在构造函数里面的时候就不会被共享,所以p2不受影响。
这里借用构造函数继承方式就解决了原型链不能传递参数以及引用类型共享的问题。
小知识:call()和apply()方法可以改变函数执行的作用域, 简言之就是改变函数中this指向的内容。
call()和apply()都接受两个参数:第一个是在其中运行函数的作用域,另一个是传递的参数。
call和apply的区别就是参数的不同.
call中的参数必须是一个个枚举出来的.
apply中的参数必须是数组或者是arguments对象
那么问题来了:为什么p1.showName()结果是错误的呢?----因为借用构造函数继承方式只能继承构造函数里的属性和方法。这里也就发现了借用构造函数的一个问题。
注意:由于把方法都放在构造函数里,每次我们实例化就会分配内存空间给它造成资源的浪费,所以一般我们都是把方法放在原型里,属性放在构造函数里。
借用构造函数继承问题:
因为借用构造函数只能继承构造函数里的属性和方法,在超类型的原型中定义的方法对子类而言是不可见的,所以就相当于没有了原型。结果所有的方法都只能在构造函数里定义,因此就没有函数复用了。
那么如何解决借用构造函数所产生的问题呢?那就要看下面这种继承方式了
三. 组合继承(伪经典继承)
function Person(name,age){this.name=name;this.age=age;}Person.prototype.showName=function(){console.log(this.name);}function Worker(name,age,job){Person.call(this,name,age);//借用构造函数this.job=job;}Worker.prototype=new Person();//原型链继承var p1=new Worker("mumu","18","学生"); console.log(p1.age);p1.showName();组合继承:将原型链与借用构造函数结合。function object(proto) {function F() {}F.prototype = proto;return new F();}var person = {name: "mumu",friends: ["xiaxia", "susu"]};var anotherPerson = object(person);anotherPerson.friends.push("wen");var yetAnotherPerson = object(person);anotherPerson.friends.push("tian");console.log(person.friends);//["xiaxia", "susu", "wen", "tian"]console.log(anotherPerson.__proto__)//Object {name: "mumu", friends: Array[4]}简单分析下:function object(proto)是一个临时中转函数,里面的参数proto表示将要传递进入的一个对象,F()构造函数是临时新建的对象,用来存储传递过来的对象,F.prototype = proto;将对象实例赋值给F构造函数的原型对象,最后返回传递过来的对象的对象实例。原型式继承还是会共享引用类型的属性。//临时中转函数function object(proto) {function F() {}F.prototype = proto;return new F();}//寄生函数function create(proto){var f=object(proto);f.love=function(){return this.name;}return f;}var person = {name: "mumu",friends: ["xiaxia", "susu"]};var anotherPerson = create(person);console.log(anotherPerson.love());寄生组合式继承六. 寄生组合式继承function object(proto) {function F() {}F.prototype = proto;return new F();}//寄生函数function create(Person,Worker){var f=object(Person.prototype);//创建对象f.constructor=Worker;//调整原型构造指针,增强对象Worker.prototype=f;//指定对象}function Person(name,age){this.name=name;this.age=age;}Person.prototype.showName=function(){console.log(this.name);}function Worker(name,age,job){Person.call(this,name,age);this.job=job;}create(Person,Worker);//寄生组合式继承var p1=new Person("mumu","18","学生");p1.showName();这种方法也是现在实现继承方法中最完美的,也是最理想的。