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 相关文章推荐
pjblog修改技巧汇总
Mar 12 Javascript
JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
Oct 11 Javascript
12款经典的白富美型—jquery图片轮播插件—前端开发必备
Jan 08 Javascript
简单易用的倒计时js代码
Aug 04 Javascript
node.js中的http.request.end方法使用说明
Dec 10 Javascript
JavaScript模拟可展开、拖动与关闭的聊天窗口实例
May 12 Javascript
JavaScript中setFullYear()方法的使用详解
Jun 11 Javascript
jQuery实现仿百度首页滑动伸缩展开的添加服务效果代码
Sep 09 Javascript
ES6中如何使用Set和WeakSet
Mar 10 Javascript
AngularJS之依赖注入模拟实现
Aug 19 Javascript
JS 实现可停顿的垂直滚动实例代码
Nov 23 Javascript
用几道面试题来看JavaScript执行机制
Apr 30 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 has encountered an Access Violation
2007/01/15 PHP
Laravel中扩展Memcached缓存驱动实现使用阿里云OCS缓存
2015/02/10 PHP
php查看当前Session的ID实例
2015/03/16 PHP
PHP+MySql+jQuery实现的"顶"和"踩"投票功能
2016/05/21 PHP
PHP通过引用传递参数用法分析
2016/12/01 PHP
js实现弹出窗口、页面变成灰色并不可操作的例子分享
2014/05/10 Javascript
原生javascript获取元素样式
2014/12/31 Javascript
ECMAScript 5严格模式(Strict Mode)介绍
2015/03/02 Javascript
bootstrap快速制作后台界面
2016/12/05 Javascript
JavaScript 动态三角函数实例详解
2017/01/08 Javascript
Bootstrap超大屏幕的实现代码
2017/03/22 Javascript
vue2中使用less简易教程
2018/03/27 Javascript
微信小程序swiper实现滑动放大缩小效果
2018/11/15 Javascript
JS实现瀑布流效果
2020/03/07 Javascript
在vscode 中设置 vue模板内容的方法
2020/09/02 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
详解vue实现坐标拾取器功能示例
2020/11/18 Vue.js
[00:23]魔方之谜解锁款式
2018/12/20 DOTA
python中的lambda表达式用法详解
2016/06/22 Python
Python利用matplotlib生成图片背景及图例透明的效果
2017/04/27 Python
python脚本替换指定行实现步骤
2017/07/11 Python
python 实现登录网页的操作方法
2018/05/11 Python
Django分页功能的实现代码详解
2019/07/29 Python
keras得到每层的系数方式
2020/06/15 Python
Django Admin 上传文件到七牛云的示例代码
2020/06/20 Python
Python 串口通信的实现
2020/09/29 Python
css3实现针线缝合效果(图解步骤)
2013/02/04 HTML / CSS
vue项目实现分页效果
2021/03/24 Vue.js
学生期末评语大全
2014/04/30 职场文书
红头文件任命书范本
2014/06/05 职场文书
教师国庆节演讲稿范文2014
2014/09/21 职场文书
终止劳动合同协议书
2014/10/05 职场文书
2014年学校工作总结
2014/11/20 职场文书
2014小学教师年度考核工作总结
2014/12/03 职场文书
小学五一劳动节活动总结
2015/02/09 职场文书
2015中学政教处工作总结
2015/07/22 职场文书