面向?qū)ο?/h1>

2018-07-10 16:21 更新
Table of Contents generated with DocToc

面向?qū)ο?/h2>

程序設(shè)計(jì)方法

程序設(shè)計(jì)描述系統(tǒng)如何通過程序來實(shí)現(xiàn)的過程,其為一種設(shè)計(jì)方法與語言實(shí)現(xiàn)無關(guān)。常見的設(shè)計(jì)方法有面向流程與面向?qū)ο蟆?/p>

面向過程

以程序的過程為中心,采用自定而下逐步細(xì)化的方法來實(shí)現(xiàn)。常見的面向過程語言有 C、Fortran、Pascall。

面向?qū)ο?/h4>

將對象作為程序的基本單元,將程序分解為數(shù)據(jù)和操作的集合。常見的面向過程語言有 smalltalk(也是 Objective-C 的父親)、Java、C++。

概念
  • 類(Class)、對象(Object)
  • 屬性(Property)、方法(Method)
基本特點(diǎn)
  • 繼承(Inheritance)
  • 封裝(Encapsulation)
  • 多態(tài)(Polymorphism)

JavaScript 面向?qū)ο?/h2>

constructor

對象的構(gòu)造器,也可稱之為構(gòu)造類型。

// 使用 new 關(guān)鍵字創(chuàng)建
var o = new Object();
var a = new Array();
var d = new Date();
    |         |
 object    constructor

// 使用直接量創(chuàng)建
var o = {name: 'Xinyang'};
var a = [1, 2, 3];

自定義構(gòu)造器

// constructor
function Person(name, age, birthdate) {
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
}

// 創(chuàng)建對象
var X = new Person('Stupid', 13, new Date(2015, 01, 01));
var Q = new Person('Q', 12, new Date(2015, 01, 01));

X.changeName('X');
創(chuàng)建構(gòu)造器的方法(3 種)
  • function ClassName() {...}
  • var Class = function() {...}
  • var Class = new Function()

NOTE: 并不是所有函數(shù)都可以被當(dāng)成構(gòu)造器,例如 var o = new Math.min()。通常自定義的函數(shù)均可當(dāng)做構(gòu)造器來使用。內(nèi)置對象的構(gòu)造器也可被當(dāng)做構(gòu)造器。

NOTE+:如果構(gòu)造器有返還值并為對象類型,則對象將被直接返回。

function Person(name, age, birthdate) {
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
  // !!! 注意這里
  return {};
}

var X = new Person('X', 13, new Date());
console.log(X.name); // undefined;

this

this 在不同環(huán)境中指代的對象不同(this 指代的值可在函數(shù)運(yùn)行過程中發(fā)生改變)。

出現(xiàn)場景所指代值
全局環(huán)境全局對象(window 在瀏覽器環(huán)境中時)
constructor創(chuàng)建的新實(shí)例對象
函數(shù)調(diào)用函數(shù)的調(diào)用者
new Function()全局對象
eval()調(diào)用上下文中的 this

全局環(huán)境中

全局環(huán)境中 this 指代全局對象,既 window 在瀏覽器環(huán)境中。

// 以下的所有 this 均指代全局對象
var a = 10;
alert(this.a);

this.b = 20;
alert(b);

c = 30;
alert(this.c);

構(gòu)造器中

構(gòu)造器中的 this 指代的是即將被創(chuàng)建出的對象。

// constructor
function Person(name, age, birthdate) {
  // 下面的指代即將被創(chuàng)建的對象
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
}

// 創(chuàng)建對象
var X = new Person('Stupid', 13, new Date(2015, 01, 01));
var Q = new Person('Q', 12, new Date(2015, 01, 01));

X.changeName('X');

函數(shù)中

函數(shù)中的 this 指代函數(shù)的調(diào)用者。

// constructor
function Person(name, age, birthdate) {
  // 下面的指代即將被創(chuàng)建的對象
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
  this.gretting = function() {
    // !!! 下面這個 this 指代調(diào)用它的對象,既上面的
    // 上面的 gretting 左邊的 this,既為即將被創(chuàng)建的對象
    console.log('Hi, I am ' + this.name)
  }
}

// 創(chuàng)建對象
var X = new Person('Stupid', 13, new Date(2015, 01, 01));

X.changeName('X');
X.gretting();

NOTE: new Function('console.log(this)') 中的 this 均指代全局對象。eval('console.log(this) 則為調(diào)用上下文指代的 this

this 實(shí)例

下面的例子使用 apply 與 call。通過這兩個方法來將一個對象中 this 指代的目標(biāo)進(jìn)行改變。

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.move = function(x, y) {
    this.x += x;
    this.y += y;
  }
}

var point = new Point(0, 0);
point.move(1, 1);

var circle = {x: 0, y: 1, r: 1};

// 改變 point 中 move 方法 this 指代的對象至 circle
point.move.apply(circle, [1, 1]);
// 同樣可以用類似的 call 方法,區(qū)別為參數(shù)需依次傳入
point.move.call(circle, 1, 1);

原型繼承

使用原型(prototype)可以解決重復(fù)定義實(shí)例對象擁有的完全一致的屬性或方法(既共享原型中的屬性或方法)。

function Boss() {
  this.age = 0;
  this.birthdate = null;
  this.name = '';
  this.tasks = [];
  this.title = 'Boss';
  this.gretting = function() {console.log('I am a Boss!');};
}

var X = new Boss();
var Q = new Boss();

// X 與 Q 中具有完全一致(不必唯一的屬性或方法)
// 并耗用內(nèi)存的共享部分
// this.title 與 this.gretting

改造后的構(gòu)造器

function Boss() {
  this.age = 0;
  this.birthdate = null;
  this.name = '';
  this.tasks = [];
}
Boss.prototype = {
  title: 'Boss',
  gretting: function(){console.log('I am a Boss!');}
}

var X = new Boss();
var Q = new Boss();

// X 與 Q 中具有完全一致(不必唯一的屬性或方法)
// 并耗用內(nèi)存的共享部分
// this.title 與 this.gretting

var X = new Boss();
var Q = new Boss();

// X 與 Q 擁有相同的原型 Boss.prototype

原型鏈

使用原型繼承的方法會產(chǎn)生原型鏈。JavaScript 中對于對象的查找、修改和刪除都是通過原型鏈來完成的。

判斷屬性是否為對象本身

objectName.hasOwnProperty('propertyName');
// 返回布爾值 true 或 false

屬性查找

對象的屬性查找會更隨原型鏈依次查找,如果在當(dāng)前環(huán)境中無法找到需要的屬性則會繼續(xù)向下一層原型中繼續(xù)尋找。

屬性修改

在 JavaScript 中對于對象屬性的修改永遠(yuǎn)只修改對象自身的屬性(不論是來源于對象本身還是對象的原型)。當(dāng)創(chuàng)建當(dāng)前對象不存在屬性時(即便原型擁有此屬性),也會為此對象增加改屬性。

修改原型上的屬性

修改原型屬性會印象所有被創(chuàng)建出的對象現(xiàn)有的屬性和方法。

ClassName.prototype.propertyName = 'new value';
ClassName.prototype.methodName = function(){...};

屬性刪除

delete objectName.propertyName 只可刪除對象自身的屬性,無法刪除對象的原型屬性。

Object.create(proto[, propertiesObject])

其為ECMAScript 5 中提出的新建立對象的方式。在 X 中使用隱式的原型對象指向 boss 對象,并將其設(shè)為 X 對象的原型。

var boss = {
  title: 'Boss',
  gretting: function(){console.log('Hi, I am a Boss!');}
};

var X = Object.create(boss);
X.gretting(); // Hi, I am a Boss!

低版本中實(shí)現(xiàn) Object.create 功能

此種方式仍需使用 ClassName.prototype 的方式來實(shí)現(xiàn)。

var clone = (function(){
  var F = function(){};
  return function(proto) {
    F.prototype = proto;
    return new F();
  }
})();

面向?qū)ο蟮膽?yīng)用

全局變量

全局變量可在程序任意位置進(jìn)行訪問和修改的變量。濫用全局變量會導(dǎo)致,命名沖突,導(dǎo)致程序不穩(wěn)定。

全局標(biāo)量的三種定義方法:

  • var gloablVal = 'value'; 。
  • window.gloablVal = 'value'; 附加于 window 對象上
  • gloablVal = 'value'; 不使用 var 關(guān)鍵字,也附加于 windwo 對象

NOTE:delete 無法刪除在代碼最頂端定義的全局標(biāo)量 var globale

封裝

信息隱藏可以保證程序的穩(wěn)定,將內(nèi)部信息進(jìn)行隱藏。其他語言中可詞用訪問權(quán)限來實(shí)現(xiàn)封裝的概念,像 private、public。

JavaScript 中的封裝可使用函數(shù)的方法(閉包)。

// 模擬 private 的屬性
function ClassName(){
  var _property = '';
  this.getProperty = function(){
    return _property;
  };
}

// 模擬 protected 屬性,使用人為約束規(guī)則
var pro = ClassName.prototype;
pro._protectedMethod = function(){...};
pro.publicMethod = function(){...};

繼承

原型繼承

原型繼承的方式為 JavaScript 中固有的繼承方式。

var proto = {
  action1: function(){},
  action2: function(){}
}

var obj = Object.create(proto);

在不支持 EM5 中的實(shí)現(xiàn)方法:

var clone = (function(){
  var F = function(){};
  return function(proto) {
    F.prototype = proto;
    return new F();
  }
})();
類繼承

使用原型鏈繼承的方式模擬其他語言類繼承的特性。

function ClassA() {
  ClassA.classMethod = function(){};
  ClassA.prototype.api = function(){};

  function ClassB() {
    ClassA.apply(this, argument);
  }
  ClassB.prototype = new ClassA();
  ClassB.prototype.constructor = ClassB;
  ClassB.prototype.api = function(){
    ClassA.prototype.api.apply(this, arguments);
  }
}

// ClassA 為父類
// ClassB 為子類

var b = new ClassB();
b.api();


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號