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下有关dom以及xml节点访问兼容问题
Nov 26 Javascript
javascript中的prototype属性实例分析说明
Aug 09 Javascript
比较新旧两个数组值得增加和删除的JS代码
Oct 30 Javascript
Bootstrap每天必学之按钮
Nov 26 Javascript
浅析JavaScript中浏览器的兼容问题
Apr 19 Javascript
解决JS组件bootstrap table分页实现过程中遇到的问题
Apr 21 Javascript
浅谈javascript运算符——条件,逗号,赋值,()和void运算符
Jul 15 Javascript
学习Angular中作用域需要注意的坑
Aug 17 Javascript
jQuery中Find选择器用法示例
Sep 21 Javascript
JavaScript数组复制详解
Feb 02 Javascript
官方推荐react-navigation的具体使用详解
May 08 Javascript
vue 组件基础知识总结
Jan 26 Vue.js
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
C# Assembly类访问程序集信息
2009/06/13 PHP
php中去除所有js,html,css代码
2010/10/12 PHP
php array_intersect比array_diff快(附详细的使用说明)
2011/07/03 PHP
PHP运行出现Notice : Use of undefined constant 的完美解决方案分享
2012/03/05 PHP
php实现删除指定目录下相关文件的方法
2014/10/20 PHP
DWZ+ThinkPHP开发时遇到的问题分析
2016/12/12 PHP
PHP使用标准库spl实现的观察者模式示例
2018/08/04 PHP
基于JQuery的一个简单的鼠标跟随提示效果
2010/09/23 Javascript
THREE.JS入门教程(4)创建粒子系统
2013/01/24 Javascript
jquery中的ajax方法怎样通过JSONP进行远程调用
2014/05/04 Javascript
jQuery动态修改超链接地址的方法
2015/02/13 Javascript
深入浅析javascript中的作用域(推荐)
2016/07/19 Javascript
在Docker快速部署Node.js应用的详细步骤
2016/09/02 Javascript
javascript iframe跨域详解
2016/10/26 Javascript
js设置文字颜色的方法示例
2016/12/30 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
ejsExcel模板在Vue.js项目中的实际运用
2018/01/27 Javascript
JavaScript中常用的简洁高级技巧总结
2019/03/10 Javascript
js+html5 canvas实现ps钢笔抠图
2019/04/28 Javascript
JavaScript实现单英文金山打字通
2020/07/24 Javascript
基于vue实现简易打地鼠游戏
2020/08/21 Javascript
解决vue与node模版引擎的渲染标记{{}}(双花括号)冲突问题
2020/09/11 Javascript
nodejs处理tcp连接的核心流程
2021/02/26 NodeJs
Python 数据处理库 pandas 入门教程基本操作
2018/04/19 Python
pandas删除行删除列增加行增加列的实现
2019/07/06 Python
python文字和unicode/ascll相互转换函数及简单加密解密实现代码
2019/08/12 Python
世界上最好的威士忌和烈性酒购买网站:The Whisky Exchange
2016/11/20 全球购物
美国独家设计师眼镜在线光学商店:Glasses Gallery
2017/12/28 全球购物
儿科护士实习自我鉴定
2013/10/17 职场文书
市场营销计划书范文
2015/01/16 职场文书
团代会开幕词
2015/01/28 职场文书
追悼会答谢词范文
2015/09/29 职场文书
2016年学生会感恩节活动总结
2016/04/01 职场文书
小程序与后端Java接口交互实现HelloWorld入门
2021/07/09 Java/Android
「玫瑰之王的葬礼」舞台剧主视觉图公开
2022/03/21 日漫
使用Python开发冰球小游戏
2022/04/30 Python