「JS」面向对象

  • 面向对象
    • 程序设计方法
      • 面向过程
      • 面向对象
        • 概念
        • 基本特点
  • JavaScript 面向对象
    • constructor
      • 自定义构造器
        • 创建构造器的方法(3 种)
    • this
      • 全局环境中
      • 构造器中
      • 函数中
    • this 实例
    • 原型继承
    • 原型链
      • 属性查找
      • 属性修改
      • 属性删除
      • Object.create(proto[, propertiesObject])
    • 面向对象的应用
      • 全局变量
      • 封装
      • 继承
        • 原型继承
        • 类继承

面向对象

程序设计方法

程序设计描述系统如何通过程序来实现的过程,其为一种设计方法与语言实现无关。常见的设计方法有面向流程与面向对象。

面向过程

以程序的过程为中心,采用自定而下逐步细化的方法来实现。常见的面向过程语言有 C、Fortran、Pascall。

procedure_programming.png

面向对象

将对象作为程序的基本单元,将程序分解为数据和操作的集合。常见的面向过程语言有 smalltalk(也是 Objective-C 的父亲)、Java、C++。

object-oriented-programming.png
概念
  • 类(Class)、对象(Object)
  • 属性(Property)、方法(Method)
基本特点
  • 继承(Inheritance)
  • 封装(Encapsulation)
  • 多态(Polymorphism)

JavaScript 面向对象

constructor

对象的构造器,也可称之为构造类型。

// 使用 new 关键字创建
var o = new Object();
var a = new Array();
var d = new Date();
    |         |
 object    constructor

// 使用直接量创建
var o = {name: 'Xinyang'};
var a = [1, 2, 3];

自定义构造器

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

// 创建对象
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');
创建构造器的方法(3 种)
  • function ClassName() {...}
  • var Class = function() {...}
  • var Class = new Function()

NOTE: 并不是所有函数都可以被当成构造器,例如 var o = new Math.min()。通常自定义的函数均可当做构造器来使用。内置对象的构造器也可被当做构造器。

NOTE+:如果构造器有返还值并为对象类型,则对象将被直接返回。

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 在不同环境中指代的对象不同(this 指代的值可在函数运行过程中发生改变)。

出现场景 所指代值
全局环境 全局对象(window 在浏览器环境中时)
constructor 创建的新实例对象
函数调用 函数的调用者
new Function() 全局对象
eval() 调用上下文中的 this

全局环境中

全局环境中 this 指代全局对象,既 window 在浏览器环境中。

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

this.b = 20;
alert(b);

c = 30;
alert(this.c);

构造器中

构造器中的 this 指代的是即将被创建出的对象。

// constructor
function Person(name, age, birthdate) {
  // 下面的指代即将被创建的对象
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
}

// 创建对象
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');

函数中

函数中的 this 指代函数的调用者。

// constructor
function Person(name, age, birthdate) {
  // 下面的指代即将被创建的对象
  this.name = name;
  this.age = age;
  this.birthdate = birthdate;
  this.changeName = function(newAge) {
    this.age = newAge;
  }
  this.gretting = function() {
    // !!! 下面这个 this 指代调用它的对象,既上面的
    // 上面的 gretting 左边的 this,既为即将被创建的对象
    console.log('Hi, I am ' + this.name)
  }
}

// 创建对象
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) 则为调用上下文指代的 this

this 实例

下面的例子使用 applycall。通过这两个方法来将一个对象中 this 指代的目标进行改变。

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 方法,区别为参数需依次传入
point.move.call(circle, 1, 1);
this-sample.jpg

原型继承

使用原型(prototype)可以解决重复定义实例对象拥有的完全一致的属性或方法(既共享原型中的属性或方法)。

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 中具有完全一致(不必唯一的属性或方法)
// 并耗用内存的共享部分
// this.title 与 this.gretting

改造后的构造器

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 中具有完全一致(不必唯一的属性或方法)
// 并耗用内存的共享部分
// this.title 与 this.gretting

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

// X 与 Q 拥有相同的原型 Boss.prototype

原型链

使用原型继承的方法会产生原型链。JavaScript 中对于对象的查找、修改和删除都是通过原型链来完成的。

判断属性是否为对象本身

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

属性查找

对象的属性查找会更随原型链依次查找,如果在当前环境中无法找到需要的属性则会继续向下一层原型中继续寻找。

属性修改

在 JavaScript 中对于对象属性的修改永远只修改对象自身的属性(不论是来源于对象本身还是对象的原型)。当创建当前对象不存在属性时(即便原型拥有此属性),也会为此对象增加改属性。

修改原型上的属性

修改原型属性会印象所有被创建出的对象现有的属性和方法。

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

属性删除

delete objectName.propertyName 只可删除对象自身的属性,无法删除对象的原型属性。

Object.create(proto[, propertiesObject])

其为ECMAScript 5 中提出的新建立对象的方式。在 X 中使用隐式的原型对象指向 boss 对象,并将其设为 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!

低版本中实现 Object.create 功能

此种方式仍需使用 ClassName.prototype 的方式来实现。

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

面向对象的应用

全局变量

全局变量可在程序任意位置进行访问和修改的变量。滥用全局变量会导致,命名冲突,导致程序不稳定。

全局标量的三种定义方法:

  • var gloablVal = 'value';
  • window.gloablVal = 'value'; 附加于 window 对象上
  • gloablVal = 'value'; 不使用 var 关键字,也附加于 windwo 对象

NOTE:delete 无法删除在代码最顶端定义的全局标量 var globale

封装

信息隐藏可以保证程序的稳定,将内部信息进行隐藏。其他语言中可词用访问权限来实现封装的概念,像 privatepublic

JavaScript 中的封装可使用函数的方法(闭包)。

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

// 模拟 protected 属性,使用人为约束规则
var pro = ClassName.prototype;
pro._protectedMethod = function(){...};
pro.publicMethod = function(){...};

继承

原型继承

原型继承的方式为 JavaScript 中固有的继承方式。

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

var obj = Object.create(proto);

在不支持 EM5 中的实现方法:

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();
class-inherence.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容