您的位置:首页 > Web前端 > JavaScript

传统方法过渡到ES6去优雅地实现JavaScript的继承

2017-05-31 00:38 627 查看
众所周知,面向对象编程有三个重要的概念: 封装、继承、多态。而JS作为面向对象的弱类型语言,应该说是基于对象的语言,正如常说的,JS的世界里,万物皆对象。虽然JS本身不是面向对象的语言,我们可以通过模拟的方法,来实现类似JAVA式的类继承,之后使用Es6语法,使我们更加简单方便的实现类的继承。

1、创建一个自定义对象

//构造函数
function People(name,age){
this.name = name;
this.age = age;
}
//定义原型对象
People.peototype={
getName : function(){
return this.name;
},
getAge : function(){
return this.age;
}
}

var p1 = new People('leaf',10);
console.log(p1.getName())  //leaf


2、当执行 var p1 = new People('leaf',10);内部主要做了这几件事

1. 创建新的空对象(new Object());

2. 设置新对象的__proto__继承构造函数的prototype (p1.__proto__===People.prototype );   

3. 将这个对象通过this关键字传递到构造函数中并执行构造函数。

4. 将这个对象赋值给p1.

3、简单的继承,看看

创建student类,它从People继承了原型prototype中所有的属性。

function Student(name, age, score) {
this.name = name;
this.age = age;
this.score = score;
}
将Studen原型指向Person的一个实例(其实就是Student.prototype里的__proto__指向了People的实例中的__proto__,
而People的实例中的__proto__又指向了People.prototype)。
因为People的实例可以调用People原型中的方法, 所以Studen的实例也可以调用Person原型中的所有属性。

Studen.prototype = new Person();
Student.prototype.constructor = Student;  //避免实例的constructor属性指向Object函数
Studen.prototype.getScore= function() { return this.score; };

var p1 = new Employee("leaf", "12", "100");
console.log(p1.getName()); // "leaf  


  

4、3中的方法存在的问题

1、在创建Student构造函数和原型时,就对Pelple进行了实例化,这是不合适的。
2、Student的构造函数没法调用父类Person的构造函数,导致在People构造函数中对name和age属性的重复赋值。
3、Student中的函数会覆盖Pelple中的同名函数,没有重载的机制.

5、修复之后更加优雅地继承

//构造函数
function People(name,age){
this.name = name;
this.age = age;
}
//定义原型对象
People.prototype={
constructor : People,
getName : function(){
return this.name;
},
getAge : function(){
return this.age;
}
}

//定义一个Student类
function Student(name,age,score){
//调用Peopel构造函数,this指向了People
People.apply(this,arguments);
this.score=score;
}

Student.prototype = {
constructor :Student,
getScore:function(){
return this.score;
}
}

让Student的原型对象继承People的原型对象
Object.setPrototypeOf(
Student.prototype, People.prototype
);

var p2 = new Student('kafu',10,99);
console.log(p2.getScore());//99
console.log(p2.getName()); //kafu
console.log(Student.prototype.constructor==Student); //true


 

setPrototypeOf的polyfill


Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
obj.__proto__ = proto;
return obj;
}


  

 

6、传统方法小结

主要利用两点

1、在子类型构造函数中调用父类型构造函数,改变this的指向。

注意:可以使用call(this,参数属性)、apply(this,[参数数组])

2、利用Object.setPrototypeOf()
注意:该方法的Polyfill

Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
obj.__proto__ = proto;
return obj;
}


  

7、ES6实现类的继承

//定义People类
class People{
//构造函数
constructor(name,age){
this.name = name;
this.age = age;
}

//原型上的方法
getName(){ //没有function哦
return this.name;
}

getAge(){
return this.age;
}
}
//创建Student类并去继承People类
class Student extends People{
constructor(name, age, score){
super(name, age); //调用父类型的构造方法
this.score = score;
}

getScore(){
return this.name+'的成绩是:'+this.score;
}

}

//usage
var p3 = new Student('kafu',10, 99);
console.log(p3.getScore());


  

8、es6方法的总结

1、es6中的extends其实就像传统方法中的

Object.setPrototypeOf(
Student.prototype, People.prototype
);

让子元素的原型继承父元素的原型

2、es6中的super()其实就像传统方法中 People.apply(this,arguments);借用父类中的构造函数。

3、可见深刻理解传统方法之后,对掌握好es6的新语法是有很大的帮助的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: