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 相关文章推荐
document.documentElement和document.body区别介绍
Sep 16 Javascript
Javascript写入txt和读取txt文件示例
Feb 12 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
Sep 17 Javascript
简单介绍JavaScript数据类型之隐式类型转换
Dec 28 Javascript
JS代码实现百度地图 画圆 删除标注
Oct 12 Javascript
AngularJS压缩JS技巧分析
Nov 08 Javascript
详解Javascript数据类型的转换规则
Dec 12 Javascript
深入理解JavaScript 箭头函数
May 30 Javascript
vue axios重复点击取消上一次请求封装的方法
Jun 19 Javascript
iview实现图片上传功能
Jun 29 Javascript
vue 获取url参数、get参数返回数组的操作
Nov 12 Javascript
原生JavaScript实现幻灯片效果
Feb 19 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/05/18 PHP
Laravel框架实现的记录SQL日志功能示例
2018/06/19 PHP
javascript 一个自定义长度的文本自动换行的函数
2007/08/19 Javascript
ie下动态加态js文件的方法
2011/09/13 Javascript
在js文件中如何获取basePath处理js路径问题
2013/07/10 Javascript
javascript禁用Tab键脚本实例
2013/11/22 Javascript
jquery和ajax的关系详细介绍
2013/11/29 Javascript
js 去掉空格实例 Trim() LTrim() RTrim()
2014/01/07 Javascript
jQuery的cookie插件实现保存用户登陆信息
2014/04/15 Javascript
理解javascript定时器中的setTimeout与setInterval
2016/02/23 Javascript
利用JS判断字符串是否含有数字与特殊字符的方法小结
2016/11/25 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
Vue.js 父子组件通信的十种方式
2018/10/30 Javascript
nuxt.js中间件实现拦截权限判断的方法
2018/11/21 Javascript
echarts 使用formatter 修改鼠标悬浮事件信息操作
2020/07/20 Javascript
Element Steps步骤条的使用方法
2020/07/26 Javascript
vant 解决tab切换插件标题样式自定义的问题
2020/11/13 Javascript
[02:53]2018年度DOTA2最佳战队-完美盛典
2018/12/17 DOTA
Python编程中time模块的一些关键用法解析
2016/01/19 Python
python 性能提升的几种方法
2016/07/15 Python
Python实现PS滤镜特效Marble Filter玻璃条纹扭曲效果示例
2018/01/29 Python
深入浅析python 中的匿名函数
2018/05/21 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
阿迪达斯希腊官方网上商店:adidas希腊
2019/04/06 全球购物
大学生求职中的自我评价
2013/10/01 职场文书
在校学生职业规划范文
2014/01/08 职场文书
论文指导教师评语
2014/04/28 职场文书
毕业典礼演讲稿
2014/05/13 职场文书
应聘护士求职信
2014/07/21 职场文书
关于国庆节的演讲稿
2014/09/05 职场文书
乡镇干部党的群众路线教育实践活动个人对照检查材料
2014/09/24 职场文书
社区敬老月活动总结
2015/05/07 职场文书
首都博物馆观后感
2015/06/05 职场文书
幼儿园元旦主持词
2015/07/06 职场文书
思想品德课教学反思
2016/02/24 职场文书
vue 把二维或多维数组转一维数组
2022/04/24 Vue.js