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 相关文章推荐
收集的网上用的ajax之chat.js文件
Apr 08 Javascript
javascript 拖放效果实现代码
Jan 22 Javascript
解决ExtJS在chrome或火狐中正常显示在ie中不显示的浏览器兼容问题
Jan 11 Javascript
JS动态创建Table,Tr,Td并赋值的具体实现
Jul 05 Javascript
原生JS实现响应式瀑布流布局
Apr 02 Javascript
使用jQuery监听DOM元素大小变化
Feb 24 Javascript
js方法数据验证的简单实例
Sep 17 Javascript
原生js实现焦点轮播图效果
Jan 12 Javascript
mui上拉加载功能实例详解
Apr 13 Javascript
纯js实现页面返回顶部的动画(超简单)
Aug 10 Javascript
react中fetch之cors跨域请求的实现方法
Mar 14 Javascript
vue实现直播间点赞飘心效果的示例代码
Sep 20 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循环检测目录是否存在并创建(循环创建目录)
2011/01/06 PHP
php addslashes及其他清除空格的方法是不安全的
2012/01/25 PHP
封装ThinkPHP的一个文件上传方法实例
2014/10/31 PHP
PHP实现UTF-8文件BOM自动检测与移除实例
2014/11/05 PHP
PHP输出两个数字中间有多少个回文数的方法
2015/03/23 PHP
smarty模板判断数组为空的方法
2015/06/10 PHP
PHP与SQL语句常用大全
2016/12/10 PHP
使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
2017/09/01 PHP
PHP的图像处理实例小结【文字水印、图片水印、压缩图像等】
2019/12/20 PHP
PHP安全之register_globals的on和off的区别
2020/07/23 PHP
js 对联广告、漂浮广告封装类(IE,FF,Opera,Safari,Chrome
2009/11/26 Javascript
菜鸟javascript基础资料整理3 正则
2010/12/06 Javascript
jQuery中绑定事件的命名空间详解
2011/04/05 Javascript
JavaScript检测上传文件大小的方法
2015/07/22 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
基于jquery实现简单的手风琴特效
2015/11/24 Javascript
node.js+express制作网页计算器
2016/01/17 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
JavaScript中Number对象的toFixed() 方法详解
2016/09/02 Javascript
js中Number数字数值运算后值不对的解决方法
2017/02/28 Javascript
jQuery实现QQ空间汉字转拼音功能示例
2017/07/10 jQuery
在knockoutjs 上自己实现的flux(实例讲解)
2017/12/18 Javascript
vue自定义指令的创建和使用方法实例分析
2018/12/04 Javascript
node.js中Buffer缓冲器的原理与使用方法分析
2019/11/23 Javascript
vue2.0 解决抽取公用js的问题
2020/07/31 Javascript
解决vue项目运行npm run serve报错的问题
2020/10/26 Javascript
[52:02]DOTA2-DPC中国联赛 正赛 Phoenix vs Dragon BO3 第二场 2月26日
2021/03/11 DOTA
零基础学Python(一)Python环境安装
2014/08/20 Python
python批量获取html内body内容的实例
2019/01/02 Python
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
2019/04/12 Python
详解numpy的argmax的具体使用
2019/05/27 Python
python实现AHP算法的方法实例(层次分析法)
2020/09/09 Python
html5本地存储 localStorage操作使用详解
2016/09/20 HTML / CSS
大众服装店创业计划书范文
2014/01/01 职场文书
幼儿园元旦家长感言
2014/02/27 职场文书
《假如》教学反思
2014/04/17 职场文书