Javascript OOP之面向对象


Posted in Javascript onJuly 31, 2016

面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。——维基百科

一般面向对象包含:继承,封装,多态,抽象

对象形式的继承

浅拷贝

var Person = {
  name: 'allin',
  age: 18,
  address: {
    home: 'home',
    office: 'office',
  }
  sclools: ['x','z'],
};

var programer = {
  language: 'js',
};

function extend(p, c){
  var c = c || {};
  for( var prop in p){
    c[prop] = p[prop];
  }
}
extend(Person, programer);
programer.name; // allin
programer.address.home; // home
programer.address.home = 'house'; //house
Person.address.home; // house

从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本。

深拷贝

function extendDeeply(p, c){
  var c = c || {};
  for (var prop in p){
    if(typeof p[prop] === "object"){
      c[prop] = (p[prop].constructor === Array)?[]:{};
      extendDeeply(p[prop], c[prop]);
    }else{
      c[prop] = p[prop];
    }
  }
}

利用递归进行深拷贝,这样子对象的修改就不会影响到父对象。

extendDeeply(Person, programer);
programer.address.home = 'allin';
Person.address.home; // home
利用call和apply继承
function Parent(){
  this.name = "abc";
  this.address = {home: "home"};
}
function Child(){
  Parent.call(this);
  this.language = "js"; 
}
ES5中的Object.create()
var p = { name : 'allin'};
var obj = Object.create(o);
obj.name; // allin

Object.create()作为new操作符的替代方案是ES5之后才出来的。我们也可以自己模拟该方法:

//模拟Object.create()方法
function myCreate(o){
  function F(){};
  F.prototype = o;
  o = new F();
  return o;
}
var p = { name : 'allin'};
var obj = myCreate(o);
obj.name; // allin

目前,各大浏览器的最新版本(包括IE9)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署。

if (!Object.create) {


Object.create = function (o) {



 function F() {}



F.prototype = o;



return new F();


};

}

类的继承

Object.create()
function Person(name, age){}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
  console.log('eating...');
}
function Programmer(name, age, title){}

Programmer.prototype = Object.create(Person.prototype); //建立继承关系
Programmer.prototype.constructor = Programmer; // 修改constructor的指向

调用父类方法

function Person(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
  console.log('eating...');
}

function Programmer(name, age, title){
  Person.apply(this, arguments); // 调用父类的构造器
}


Programmer.prototype = Object.create(Person.prototype);
Programmer.prototype.constructor = Programmer;

Programmer.prototype.language = "js";
Programmer.prototype.work = function(){
  console.log('i am working code in '+ this.language);
  Person.prototype.eat.apply(this, arguments); // 调用父类上的方法
}

封装

命名空间

js是没有命名空间的,因此可以用对象模拟。

var app = {}; // 命名空间app
//模块1
app.module1 = {
  name: 'allin',
  f: function(){
    console.log('hi robot');
  }
};
app.module1.name; // "allin"
app.module1.f(); // hi robot

静态成员

function Person(name){
  var age = 100;
  this.name = name;
}
//静态成员
Person.walk = function(){
  console.log('static');
};
Person.walk(); // static

私有与公有

function Person(id){
  // 私有属性与方法
  var name = 'allin';
  var work = function(){
    console.log(this.id);
  };
  //公有属性与方法
  this.id = id;
  this.say = function(){
    console.log('say hello');
    work.call(this);
  };
};
var p1 = new Person(123);
p1.name; // undefined
p1.id; // 123
p1.say(); // say hello 123

模块化

var moduleA;
moduleA = function() {
  var prop = 1;

  function func() {}

  return {
    func: func,
    prop: prop
  };
}(); // 立即执行匿名函数

prop,func 不会被泄露到全局作用域。或者另一种写法,使用 new

moduleA = new function() {
  var prop = 1;

  function func() {}

  this.func = func;
  this.prop = prop;
}

多态

模拟方法重载

arguments属性可以取得函数调用的实参个数,可以利用这一点模拟方法的重载。

function demo(a, b ){
  console.log(demo.length); // 得到形参个数
  console.log(arguments.length); //得到实参个数
  console.log(arguments[0]); // 第一个实参 4
  console.log(arguments[1]); // 第二个实参 5
}

demo(4, 5, 6);
//实现可变长度实参的相加
function add(){
  var total = 0;
  for( var i = arguments.length - 1; i >= 0; i--){
    total += arguments[i];
  }
  return total;
}

console.log(add(1)); // 1
console.log(add(1, 2, 3)); // 7


// 参数不同的情况
function fontSize(){
  var ele = document.getElementById('js');
  if(arguments.length == 0){
    return ele.style.fontSize;
  }else{
    ele.style.fontSize = arguments[0];
  }
}
fontSize(18);
console.log(fontSize());

// 类型不同的情况
function setting(){
  var ele = document.getElementById('js');
  if(typeof arguments[0] === "object"){
    for(var p in arguments[0]){
      ele.style[p] = arguments[0][p];
    }
  }else{
    ele.style.fontSize = arguments[0];
    ele.style.backgroundColor = arguments[1];
  }
}
setting(18, 'red');
setting({fontSize:20, backgroundColor: 'green'});

方法重写

function F(){}
var f = new F();
F.prototype.run = function(){
  console.log('F');
}
f.run(); // F

f.run = function(){
  console.log('fff');
}
f.run(); // fff

抽象类

在构造器中 throw new Error(''); 抛异常。这样防止这个类被直接调用。

function DetectorBase() {
  throw new Error('Abstract class can not be invoked directly!');
}

DetectorBase.prototype.detect = function() {
  console.log('Detection starting...');
};
DetectorBase.prototype.stop = function() {
  console.log('Detection stopped.');
};
DetectorBase.prototype.init = function() {
  throw new Error('Error');
};

// var d = new DetectorBase();// Uncaught Error: Abstract class can not be invoked directly!

function LinkDetector() {}
LinkDetector.prototype = Object.create(DetectorBase.prototype);
LinkDetector.prototype.constructor = LinkDetector;

var l = new LinkDetector();
console.log(l); //LinkDetector {}__proto__: LinkDetector
l.detect(); //Detection starting...
l.init(); //Uncaught Error: Error
Javascript 相关文章推荐
JavaScript 注册事件代码
Jan 27 Javascript
javascript 弹出的窗口返回值给父窗口具体实现
Nov 23 Javascript
深入理解JavaScript系列(36):设计模式之中介者模式详解
Mar 04 Javascript
深入浅出理解javaScript原型链
May 09 Javascript
自己编写的支持Ajax验证的JS表单验证插件
May 15 Javascript
javascript自定义in_array()函数实现方法
Aug 03 Javascript
JavaScript人脸识别技术及脸部识别JavaScript类库Tracking.js
Sep 14 Javascript
详解javascript跨浏览器事件处理程序
Mar 27 Javascript
js实现砖头在页面拖拉效果
Nov 20 Javascript
JS及JQuery对Html内容编码,Html转义
Feb 17 Javascript
JS实现的RC4加密算法示例
Aug 16 Javascript
微信小程序入口场景的问题集合与相关解决方法
Jun 26 Javascript
JavaScript的字符串方法汇总
Jul 31 #Javascript
javascript 数组的正态分布排序的问题
Jul 31 #Javascript
详细谈谈javascript的对象
Jul 31 #Javascript
JS中使用DOM来控制HTML元素
Jul 31 #Javascript
图解prototype、proto和constructor的三角关系
Jul 31 #Javascript
JavaScript数据类型转换的注意事项
Jul 31 #Javascript
关于JavaScript 原型链的一点个人理解
Jul 31 #Javascript
You might like
PHP新手上路(八)
2006/10/09 PHP
经典的PHPer为什么被认为是草根?
2007/04/02 PHP
PHP面向对象学习笔记之一 基础概念
2012/10/06 PHP
php使用file函数、fseek函数读取大文件效率对比分析
2016/11/04 PHP
PHP有序表查找之二分查找(折半查找)算法示例
2018/02/09 PHP
基于jquery的checkbox下拉框插件代码
2010/06/25 Javascript
关于图片按比例自适应缩放的js代码
2011/10/30 Javascript
JavaScript splice()方法详解
2020/09/22 Javascript
JS实现根据出生年月计算年龄
2014/01/10 Javascript
DIV始终居中的js代码
2014/02/17 Javascript
javascript打开word文档的方法
2014/04/16 Javascript
AngularJS 避繁就简的路由
2016/07/01 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
2016/07/14 Javascript
又一款js时钟!transform实现时钟效果
2016/08/15 Javascript
easyui messager alert 三秒后自动关闭提示的实例
2016/11/07 Javascript
html5+canvas实现支持触屏的签名插件教程
2017/05/08 Javascript
AngularJS自定义过滤器用法经典实例总结
2018/05/17 Javascript
js事件on动态绑定数据,绑定多个事件的方法
2018/09/15 Javascript
jQuery 图片查看器插件 Viewer.js用法简单示例
2020/04/04 jQuery
深入理解python try异常处理机制
2016/06/01 Python
深入浅析Python科学计算库Scipy及安装步骤
2019/10/12 Python
Mac中PyCharm配置Anaconda环境的方法
2020/03/04 Python
浅谈pytorch 模型 .pt, .pth, .pkl的区别及模型保存方式
2020/05/25 Python
pytest fixtures装饰器的使用和如何控制用例的执行顺序
2021/01/28 Python
Matplotlib animation模块实现动态图
2021/02/25 Python
在线服装零售商:SheIn
2016/07/22 全球购物
BRASTY捷克:购买香水、化妆品、手袋和手表
2017/07/12 全球购物
英国豪华针织品牌John Smedley的在线销售商:The Outlet by John Smedley
2018/04/08 全球购物
新西兰最大的连锁超市:Countdown
2020/06/04 全球购物
国贸类专业毕业生的求职信分享
2013/12/08 职场文书
投资协议书范本
2014/04/21 职场文书
土木工程求职信
2014/05/29 职场文书
旅游文化节策划方案
2014/06/06 职场文书
教代会开幕词
2015/01/28 职场文书
暖春观后感
2015/06/08 职场文书
Python max函数中key的用法及原理解析
2021/06/26 Python