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 相关文章推荐
禁止js文件缓存的代码
Apr 09 Javascript
jquery ajax 同步异步的执行示例代码
Jun 23 Javascript
各种常用的JS函数整理
Oct 25 Javascript
js获取IFRAME当前的URL的方法
Nov 13 Javascript
node.js中的fs.realpath方法使用说明
Dec 16 Javascript
Javascript基础教程之JavaScript语法
Jan 18 Javascript
手机端页面rem宽度自适应脚本
May 20 Javascript
简介JavaScript中的setHours()方法的使用
Jun 11 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
Sep 21 Javascript
jQuery实现简单全选框
Sep 13 jQuery
js实现石头剪刀布游戏
Oct 11 Javascript
vue使用swiper实现左右滑动切换图片
Oct 16 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下检测字符串是否是utf8编码的代码
2008/06/28 PHP
PHP手机号码归属地查询代码(API接口/mysql)
2012/09/04 PHP
几道坑人的PHP面试题 试试看看你会不会也中招
2014/08/19 PHP
php防止恶意刷新与刷票的方法
2014/11/21 PHP
php发送html格式文本邮件的方法
2015/06/10 PHP
PHP实现的简单网络硬盘
2015/07/29 PHP
PHP结合Jquery和ajax实现瀑布流特效
2016/01/07 PHP
php快速排序原理与实现方法分析
2016/05/26 PHP
PHP 进度条函数的简单实例
2017/09/19 PHP
创建一个复制UBB软件信息的链接或按钮的js代码
2008/01/06 Javascript
最短的IE判断代码
2011/03/13 Javascript
JS读取cookies信息(记录用户名)
2012/01/10 Javascript
jQuery的Scrollify插件实现滑动到页面下一节点
2015/07/05 Javascript
个人网站留言页面(前端jQuery编写、后台php读写MySQL)
2016/05/03 Javascript
基于javascript实现图片滑动效果
2016/05/07 Javascript
javascript类型系统——undefined和null全面了解
2016/07/13 Javascript
javascript运算符语法全面概述
2016/07/14 Javascript
AngularJS 在同一个界面启动多个ng-app应用模块详解
2016/12/20 Javascript
bootstrap——bootstrapTable实现隐藏列的示例
2017/01/14 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
微信小程序 授权登录详解(附完整源码)
2019/08/23 Javascript
vue cli3 调用百度翻译API翻译页面的实现示例
2019/09/13 Javascript
通过原生vue添加滚动加载更多功能
2019/11/21 Javascript
Javascript幻灯片播放功能实现过程解析
2020/05/07 Javascript
[04:53]DOTA2英雄基础教程 祈求者
2014/01/03 DOTA
[01:52]PWL S2开团时刻第四期——DOTA2成语故事
2020/12/03 DOTA
Python处理json字符串转化为字典的简单实现
2016/07/07 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
flask开启多线程的具体方法
2020/08/02 Python
three.js模拟实现太阳系行星体系功能
2019/09/03 HTML / CSS
个人自我鉴定怎么写
2013/10/28 职场文书
见习期自我鉴定
2013/11/07 职场文书
工程招投标邀请书
2014/01/26 职场文书
2014老师三严三实对照检查材料思想汇报
2014/09/18 职场文书
广播体操比赛主持词
2015/06/29 职场文书
Redis基本数据类型Set常用操作命令
2022/06/01 Redis