JavaScript 继承体式格局的观点
js 中完成继承有两种经常运用体式格局:
原型链继承(对象间的继承)
类式继承(组织函数间的继承)
JavaScript不是真正的面向对象的言语,想完成继承能够用JS的原型prototype
机制或许call
和apply
要领
在面向对象的言语中,能够运用类来建立一个自定义对象,固然ES6
中也引入了class
来建立类。在这之前,我们须要运用js
的原型来建立自定义对象。
原型继承与类继承
类继承
是在子范例组织函数的内部挪用父范例的组织函数
function Super (){
this.colors = ["blue","red"];
}
function Sub () {
Super.call(this);
}
原型式继承
是借助已有的对象建立新的对象,将子类的原型指向父类。
function Super (id) {
this.id = id;
}
Super.prototype.toString = function () {
return 'Super' + this.id;
}
function Sub (id) {
this.id = id;
}
Sub.prototype = new Super(); // 这句即原型式继承的中心代码
原型链继承
为了让子类继承父类的属性和要领,起首须要定义一个组织函数,然后将父类的实例赋值给组织函数的原型。
function Parent () {
this.name = 'Parent';
}
function Child () {
this.age = 10;
}
Chid.prototype = new Parent(); // Chid继承Parent,构成原型链
var test = new Child();
console.log(test.name) // Parent
console.log(test.age) // 10 获得被继承的属性
// 继承原型链继承
function Brother () {
this.weight = 60;
}
Brother.prototype = new Child();
var peter = new Brother();
console.log(peter.name) //继承了Child和Parent,输出Parent
console.log(peter.age) // 输出10
一切的组织函数都继承自Object
,它是自动完成继承的并不须要我们手动继承,那末接着看它们的从属关联
肯定原型和实例的关联
能够经由历程两种体式格局肯定原型和实例的关联,经由历程操作符instanceof
和isPrototypeof()
要领
console.log(peter instanceof Object); //true
console.log(test instanceof Brother) //false,test是brother的父类
console.log(peter instanceof Child) //true
console.log(peter instanceof Parent) //true
只如果原型链中涌现过的原型,都能够说是改原型链派生的实例的原型。因而,isProtptypeof()
要领也会返回true
在JS中,被继承的函数成为父类(或许 基类、超类),继承的函数成为子类(派生类)。运用原型继承主要有两个题目,一是字面量重写原型会中缀关联,运用援用范例的原型,而且子范例没法给父范例通报参数。
伪类处理援用同享和超范例没法传参的题目,我们能够采纳’类式继承’的体式格局
类式继承(借用组织函数)
function Parent (age) {
this.colors = ["blue","red","green"];
this.age = age;
}
function Child (age) {
Parent.call(this,age);
}
var peter = new Child(20);
console.log(peter.age) //20
console.log(peter.colors) //blue,red,green
peter.colors.push("white");
console.log(peter.colors) //blue,red,green,white
借用组织函数虽然处理了上面两张题目,但没有原型,所以我们须要原型链+借用组织函数
的形式,这类形式成为组合继承
组合继承
function Parent (age) {
this.colors = ["blue","red","green"];
this.age = age;
}
Parent.prototype.run = function () {
return this.colors + ' is ' +this.age;
}
function Child (age) {
Parent.call(this,age); //对象假装,给父范例传参
}
Child.prototype = new Parent(); //原型链继承
var peter = new Child(20);
console.log(peter.run()); //blue,red,green is 20
组合继承是一种比较经常运用的要领,思绪是运用原型链完成对原型属性和要领的继承,借用组织函数来完成对实例属性的继承。如许,既完成了原型上定义要领的函数复用,又保证每一个实例都有本身的属性。
call()与apply()
的用法:挪用一个对象的一个要领,用另一个对象替代当前对象。
call(thisObj,Object); // call吸收一个对象
apply(thisObj,[argArray]) //apply吸收一个数组
原型式继承
这类继承借助原型并基于已有的对象建立新的对象,同时还不必建立自定义范例的体式格局成为原型式继承
function obj(o) {
function F() {}
F.prototype = o;
return new F();
}
var box = {
name : 'peter',
arr : ['blue','red','green']
};
var b1 = obj(box);
console.log(b1.name) // peter
b1.name = 'jack';
console.log(b1.name) //jack
console.log(b1.arr) //blue,red,green
b1.arr.push('white') //blue,red,green,white
var b2 = obj(box);
console.log(b2.name) // peter
console.log(b1.arr) //blue,red,green
原型式继承起首在obj()
函数内部建立一个暂时性的组织函数,然后将传入的对象作为这个组织函数的原型,末了返回这个暂时范例的新实例。
寄生式继承
这类继承体式格局是把原型式+工场形式
结合起来,目标是为了封装建立的历程。
function create(o){
var f = obj(o);
f.run = function () {
return this.arr;//一样,会同享援用
};
return f;
}
组合式继承的题目
组合式继承是JS
最经常运用的继承形式,但组合继承的父范例会在运用历程中被挪用两次,一次是建立子范例的时刻,另一次是在子范例组织函数的内部
function Parent(name){
this.name = name;
this.arr = ['哥哥','mm','父母'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,age);//第二次挪用
this.age = age;
}
Child.prototype = new Parent();//第一次挪用
以上代码是组合继承,那末寄生组合继承
处理了两次挪用的题目
寄生组合继承
function obj() {
function F() {}
F.prototype = o;
return new F();
}
function create(parent,test) {
var f = obj(parent.prototype); //建立对象
f.constructor = test; //加强对象
}
function Parent(name){
this.name = name;
this.arr = ['brother','sister','parents'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,name);
this.age =age;
}
inheritPrototype(Parent,Child); //经由历程这里完成继承
var test = new Child('peter',20);
test.arr.push('new');
console.log(test.arr); //brother,sister,parents,new
console.log(test.run()); //只同享了要领
var test2 = new Child('jack',22);
console.log(test2.arr); //援用题目处理
call和apply
call和apply能够用来转变函数中this
的指向:
// 定义一个全局函数
function f () {
console.log(this.name);
}
// 定义一个全局变量
var name = 'peter';
var obj = {
name: 'jack';
};
f.apply(window); //apple, 此时this 即是window 相当于window.f()
f.apply(obj); //jack, 此时this === obj 相当于obj.f()