JS 面向對象(一)封裝(抽象)

1、基本概念和背景

面向對象程序設計(OOP:Object-oriented programming)是一種程序設計範型,同時也是一種程序開發的方法。對象指的是類的實例。
面向對象(Object Oriented,OO)是一種對現實世界理解和抽象的方法,是計算機編程技術[1] 發展到必定階段後的產物。編程

面向對象的三大特色(封裝,繼承,多態)缺一不可。一般「基於對象」是使用對象,可是沒法利用現有的對象模板產生新的對象類型,繼而產生新的對象,也就是說「基於對象」沒有繼承的特色。而「多態」表示爲運行時類型肯定(父類類型的子類對象實例),動態綁定執行對象,沒有了繼承的概念也就無從談論「多態」。
示例:繪製一個圖形,圖形已有爲三角形、圓;
Java 示例安全

// 父類:抽象、封裝
public class  Graph {
 void draw() {
  System.out.println("draw a Graph");
 }
}
// 繼承:子類type1
public class Triangle extends Graph {
 @Override
 void draw() {
  System.out.println("draw a Triangle");
 }
}
 
// 繼承:子類type2
public class Circle extends Graph {
 @Override
 void draw() {
  System.out.println("draw a Circle");
 }
}
// 多態:運行時類型肯定
public class Drawer {
 static void draw(Graph a) {
  a.draw();
}

// 運行調用
public static void main(String args[]) {
  Graph p = new Triangle();
  Drawer.draw(p); // "draw a Triangle"
  p = new Circle();
  Drawer.draw(p); //"draw a Circle"
}

Javascript ES5示例閉包

// 封裝
function Graph(){}
Graph.prototype.draw = function (){
  console.log("draw a Graph");
}
// 原型鏈引用
function Trianggle(){}
Trianggle.prototype = new Graph();
Trianggle.prototype.draw =  function (){
  console.log("draw a Trianggle");
}
// 原型鏈引用
function Circle(){}
Circle.prototype = new Graph();
Circle.prototype.draw =  function (){
  console.log("draw a Circle");
}
// 相對多態:無顯示對象類型
function Drawer(obj){
  obj.draw();
}
// 運行時類型肯定
var p = new Trianggle();
Drawer(p);
p = new Circle();
Drawer(p);

大多面向對象語言中,面向對象通常基於面向’類‘的設計。類是代碼抽象的模式之一:實例化(instantiation)、繼承(inheritance)、和 (相對)多態(polymorphism)。類和實例的關係比如房屋建造。建築師會繪製建築藍圖,建築工人根據藍圖落地成實際建築,建築就是藍圖的複製(概念和物理上的複製)。類就是建築的抽象,含有一個建築的全部特性。實例就是實際的建築,包含了門、窗以及實際材料、地理位置。類經過複製操做被實例化爲對象形式,實例間無直接關係。但這沒法直接對應到 JavaScript 的實現機制,由於 Javascript 沒有實質類的概念,ES6的 class也是一種語法糖1ide

2、JavaScript 封裝方法

面向對象編程強調的是數據和操做數據行爲的的相互關聯,所以最好的設計就是把數據和它相關的行爲打包(封裝)起來。
封裝(Encapsulation)是指一種將抽象性函數式接口的實現細節部份包裝、隱藏起來的方法模塊化

2.1 好處

(1) 良好的封裝能下降耦合度
(2) 方面數據統一管理、對象內部結構靈活修改
(3) 對其成員有更精確的控制,易於擴展
(4) 隱藏實現信息、細節,只暴露須要的 API函數

2.2 封裝模式(建立對象模式) 構造函數2 & 原型鏈

(1)工廠模式 - 函數 【內部對象建立屬性方法並返回對象,使用this】this

function createPerson(name, age, job){
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function(){
            alert(this.name);
        }
        return o;
 }
var person1 = createPerson(「John」, 18, 「Teacher");
var person2 = createPerson(「Greg」, 30, 「Doctor」);

(2) 構造函數模式【內部 this建立屬性、方法;無 return; 經過改變 this指向建立實例】prototype

**原生構造函數**:隱式建立對象,屬性、方法賦值給 this對象,無 return;
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}
var person1 = new Person(「John」, 18, 「Teacher");
var person2 = new Person(「Greg」, 30, 「Doctor」);

構造函數: new 顯示建立 對象設計

步驟1: 建立一個新對象
步驟2:講構造函數的做用是賦值給新對象 (this 只向新對象 詞法做用域發生改變)
步驟3:執行構造函數的代碼 (爲新對象 添加屬性 )
步驟4:返回新對象code

function Person(name, age, job){
   this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}

構造函數做爲函數; 問題:做用域改變,每一個傳入的對象重建一遍;)
var person1 = new Object();

Person.call( person1, 「John」, 18, 「Teacher");

var person2 = new Person(「Greg」, 30, 「Doctor」);

(3) 原型模式 【原型對象建立屬性、方法】

構造函數無傳參, 共享原型對象的屬性,其中一個實例對原型對象的引用類型屬性作修改,影響全部其餘實例對該屬性的使用;
 (* 引用類型屬性受影響  內存分配機制不一樣引發)
function Person(){}

Person.prototype.name =  'Nicholas';
Person.prototype.age = 27;
Person.prototype.job = 'Doctor';
Person.prototype.friends =  ['Lily', 'John', 'Alex']
Person.prototype.sayName = function() {
     console.log(this.name);
}
Person.prototype.getFriends = function() {
     console.log(this.friends);
}
var person1 = new Person();
 person1.name = "person1";

 var person2 = new Person();
 person2.name = "person2";
 person2.sayName();  //「person2"
 person2.getFriends(); // ["Lily", "John", "Alex"]
 person1.friends.push(「Van");
 person1.sayName(); //「person1"
 person2.getFriends();  //["Lily", "John", "Alex", "Van"]

(4) 構造函數 & 原型模式結合 【構造函數獨立屬性方法,原型對象建立公用屬性、方法】
好處:構造函數模式 定義實例個性化屬性;原型模式定義方法和共享屬性;功能模塊化 職責單一

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = [‘Lily', 'John', 'Alex'];
}

Person.prototype ={
    constructor: Person,
      sayName: function(){
         alert(this.name);
     }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
person1.friends.push('Van');
var person2 = new Person(「Greg", 27, "Doctor");

(5) 動態原型模式 (使用:功能模塊化)【構造函數獨立屬性方法,原型對象按需建立公用屬性、方法】

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = [‘Lily’, 'John', 'Alex'];
    
    if(typeof this.sayName != ‘function’){
            Person.prototype.sayName = function(){
                    alert(this.name);
            };
    }
}

(6) 寄生構造函數模式 -【 已有對象擴展 - 原型鏈 】 (使用:第三方庫擴展 )

1.寫法上和工廠模式同樣 調用時多加 new  
   2.此模式建立的對象 與構造函數無關係, instanceof操做符無心義
function  Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    }
    return o;
}
 // 工廠模式
// var person1 =  Person(「John」, 18, 「Teacher」);
// 寄生模式
 var friend  =  new Person(「John」, 18, 「Teacher」); // 返回新對象的實例

(7) 穩妥模式 【 內部建對象不用 this 閉包 - 詞法做用域 】(穩妥對象-無公共屬性,方法不引用 this)(使用:適用於安全環境 - 禁用 this 和 new)

1.寫法上和寄生模式相似 , 除方法不使用 this  
 2.此模式建立的對象 與構造函數無關係, instanceof操做符無心義
function  Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(name); //無 this
    }
    return o;
}
var friend = Person(「John」, 18, 「Teacher」); //無 new

  1. 類實質是對象複製的概念,JavaScript 則是一種對象委託引用的概念,對引用類型變量變動其[prototype]依然擁有共享功能。
  2. 構造函數 ,是一種特殊的方法。主要用來在建立對象時初始化對象, 即爲對象成員變量賦初始值,總與new運算符一塊兒使用在建立對象的語句中。特別的一個類能夠有多個構造函數 ,可根據其參數個數的不一樣或參數類型的不一樣來區分它們 即構造函數的重載。
相關文章
相關標籤/搜索