JavaScript设计模式阅读随笔(一)——JavaScript面向对象

JavaScript中的面向对象其实就至关因而将需求抽象成一个对象,这个对象中包含属性和方法,能够用来描述或处理某一类实物,这个对象就叫作类。javascript

在Java中面向对象的三要素是:封装、继承、多态,在ES6之前虽然没有class、extend这样的关键字或方法,中一样能够实现这三要素。java

建立一个类安全

在ES6以前建立一个类通能够用:声明一个函数将其保存在变量中,内部经过对this来添加属性和方法;也能够在类的原型上添加属性和方法。闭包

能够看到当在控制台中建立一个Book的类,Book的实例化对象book包含两个属性 id 和 name,它的隐身原型__proto__中包含一个constructor属性,它又指向了Book这个原型对象。函数

若是在Book的原型上添加方法或属性:比如 Book。prototype.display = function (){ ... } 每一个实例化对象都会经过原型链继承到这个方法,但这并不是是她自有的方法,须要经过prototype访问。this

现在ES6引入Class能够这么建立类,constructor方法是类的默认方法,经过new命令生成对象实例时,自动调用该方法。spa

1 class Book {
2   constructor(id, name) {
3     this.id = id;
4     this.name = name;
5   }
6 }

 

封装prototype

利用javascript的函数做用域能够建立类的私有变量和私有方法,经过this建立类的共有属性和共有方法。一下代码是我理解中javascript封装的精髓code

 1 var Book = function (id,name) {
 2   // 安全检查 判断执行过程当中是不是当前这个对象
 3   // 避免误建立全局对象
 4   if (this instanceof Book) {
 5     this.name = name;
 6   } else {
 7     return new Book(id,name);
 8   }
 9   // 私有属性
10   var num = 1;
11   // 私有方法
12   function checkId() {
13     return num +'个'+ id;
14   }
15   // 公有属性和公有方法
16   this.id = id;
17   this.copy = function () {}
18   // 特权方法
19   this.setName = function (name){}
20   this.getName = function() {
21     // 能够访问公有方法和属性,也能够访问建立对象时的私有方法和属性
22   }
23   // 构造器
24   this.setName = function (name) {
25     // 在对象建立时,使用特权方法初始化实例对象
26   }
27   // 闭包
28   return checkId; 
29 }

 

继承对象

继承就是对原有对象的封装,从中建立私有属性、公有属性等,对于每种属性和方法特色都不同。能够被继承的方法属性无外乎两种,一种是在构造函数中,在对象实例化时复制一遍属性和方法;一种是在类的原型对象中,这类方法和属性能够被全部实例化对象共有。

类式继承:

类式继承能够理解为把父类的实力赋值给子类的原型,经过原型链来实现继承。

1 function SuperClass() {
2     this.books = ['父类book'];
3 }
4 function SubClass() {}
5 Sub.prototype = new SuperClass();
6 
7 var instance1= new SubClass();
8 console.log(instance1.books); //['父类book']

 

用这种方式新建立的对象不只能够访问父类原型上的属性和方法,还能访问父类构造函数中赋值的属性和方法,子类的原型还能够访问父类原型上的方法.

不足之处是,若是某一个实例化对象修改了books这个属性,那么全部实例化的对象books值都会被污染。

构造函数继承:

构造函数式继承能够很好的解决类式继承中所暴露的问题。它的精髓在于使用call() 这个函数

function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
function SubClass(id) {
  SuperClass.call(this,id);
}
var instance1 = new SubClass(10);
var instance2 = new SubClass(11);

instance1.books.push('sub');
console.log(instance1.books)    // ['super', 'sub']
console.log(instance2.books)    // ['super', 'sub']
console.log(instance1.id)       // 10
console.log(instance2.id)       // 11

 

能够看出 经过call()这个函数改变函数的做用环境,在子类中调用父类是将子类中的变量拿到父类中执行了一遍。这一类继承不涉及到原型,因此父类原型的方法就不能被子类继承。

组合继承:

 组合继承就是结合了类式继承中原型继承,以及构造函数式继承中在子类构造函数环境中执行一次父类 这两点来继承的

function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
SuperClass.prototype.getId = function () {
  console.log(this.id);
}
function SubClass(id,name) {
    // 构造函数中继承父类 id属性
   SuperClass.call(this,id);
   this.name = name;
}
// 类式继承原型继承父类
SubClass.prototype = new SuperClass();
// 新增子类原型方法
SubClass.prototype.getName = function () {
  console.log(this.name);
}
var instance1 = new SubClass(10,'sub1');
var instance2 = new SubClass(11,'sub2');
 
instance1.books.push('sub1-1');
console.log(instance1.books)    // ['super', 'sub1-1']
console.log(instance2.books)    // ['super']
instance1.getName()             // 10
instance1.getTime()             // sub2

 

 寄生组合继承 :

function inheritObject(o) {
  // 过渡对象
  function F() {}
  // 原型继承
  F.prototype = o;
  // 返回一个原型继承了父类对象的实例
  return new F();
}
function inheritPrototype(subClass, superClass) {
  // 复制一份父类的原型副本保存在变量中
  var p = inheritObject(superClass.prototype);
  //修正由于重写子类原型致使子类constructor属性被修改
  p.constructor = subClass;
  //设置子类的原型
  subClass.prototype = p;
}
function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
SuperClass.prototype.getId = function () {
  console.log(this.id);
}
function SubClass(id,name) {
  // 构造函数中继承父类 id属性
  SuperClass.call(this,id);
  this.name = name;
}
inheritPrototype(SubClass, SuperClass)
SubClass.prototype.getName = function () {
  console.log(this.name);
}
var instance1 = new SubClass(12,'sub12');
var instance2 = new SubClass(13,'sub13');

 

最大的改变就是子类的原型被赋予了父类的原型的一个引用,此时子类想要添加原型方法必须经过prototype添加。

以上是ES6以前,在使用javascript继承时大多采用的方法,那么在ES6当中,咱们能够采用关键字 简洁明了的达到继承的目的

 1 class ColorPoint extends Point {
 2  constructor(x, y, color) { 3 super(x, y); // 调用父类的constructor(x, y) 4 this.color = color; 5  } 6 7  toString() { 8 return this.color + ' ' + super.toString(); // 调用父类的toString() 9  } 10 }

在子类的构造函数中必须使用 super()来调用父类的构造函数,这是由于子类本身的this对象,必须先经过父类的构造函数构造,获得与父类一样的实例属性和方法,而后再对其进行加工,加上子类本身的实例属性和方法。若是不调用super方法,子类就得不到this对象。所以只有在调用super之后,子类的this才能正常使用。

多态

多态能够理解为,在调用方法时,更具传递参数的数量、类型不一样时,具备多种实现方式。 能够说根据接口不一样,呈现不同的结果。 

 

对于ES6之前实现继承,多态,封装的原理,主要围绕原型、原型链调用来实现,虽然说目前ES6能够很好的实现这些灵魂玩法,包括目前大势的TypeSScript更是把JS 引向了强类型语言的圈子,但万变不离其宗,了解原理,才能更好的运用。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

相关文章
相关标签/搜索