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 相关文章推荐
DIY jquery plugin - tabs标签切换实现代码
Dec 11 Javascript
Jquery网页内滑动缓冲导航的实现代码
Apr 05 Javascript
Bootstrap CSS组件之按钮下拉菜单
Dec 17 Javascript
Bootstrap进度条与AJAX后端数据传递结合使用实例详解
Apr 23 Javascript
anime.js 实现带有描边动画效果的复选框(推荐)
Dec 24 Javascript
JavaScript反射与依赖注入实例详解
May 29 Javascript
微信小程序利用canvas 绘制幸运大转盘功能
Jul 06 Javascript
JavaScript高级函数应用之分时函数实例分析
Aug 03 Javascript
js实现简单选项卡功能
Mar 23 Javascript
9102年webpack4搭建vue项目的方法步骤
Feb 20 Javascript
微信网页登录逻辑与实现方法
Apr 29 Javascript
vue实现随机验证码功能的实例代码
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获取php,mysql,apche的版本信息示例代码
2014/01/16 PHP
PHP7新增运算符用法实例分析
2016/09/26 PHP
三个思路解决laravel上传文件报错:413 Request Entity Too Large问题
2017/11/13 PHP
PHP+Oracle本地开发环境搭建方法详解
2019/04/01 PHP
Jquery实战_读书笔记2 选择器
2010/01/22 Javascript
一个CSS+jQuery实现的放大缩小动画效果
2014/02/19 Javascript
jquery中EasyUI实现同步树
2015/03/01 Javascript
jQuery实现气球弹出框式的侧边导航菜单效果
2015/09/22 Javascript
创建一个类Person的简单实例
2016/05/17 Javascript
基于gulp合并压缩Seajs模块的方式说明
2016/06/14 Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
2016/12/27 Javascript
vuex 项目结构目录及一些简单配置介绍
2018/04/08 Javascript
jQuery+CSS实现的标签页效果示例【测试可用】
2018/08/14 jQuery
微信小程序显示倒计时功能示例【测试可用】
2018/12/03 Javascript
JavaScript switch语句使用方法简介
2019/12/30 Javascript
[02:03]风行者至宝清风环佩外观展示
2020/09/05 DOTA
Python的几个高级语法概念浅析(lambda表达式闭包装饰器)
2016/05/28 Python
使用Django启动命令行及执行脚本的方法
2018/05/29 Python
解决Python3.5+OpenCV3.2读取图像的问题
2018/12/05 Python
Python使用Shelve保存对象方法总结
2019/01/28 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
pytorch 模型的train模式与eval模式实例
2020/02/20 Python
selenium自动化测试入门实战
2020/12/21 Python
用纯CSS3实现网页中常见的小箭头
2017/10/16 HTML / CSS
迪卡侬中国官网:Decathlon中国
2020/08/10 全球购物
护士毕业自我鉴定
2014/02/07 职场文书
《晏子使楚》教学反思
2014/02/08 职场文书
授权委托书格式模板
2014/04/03 职场文书
学校法制宣传月活动总结
2014/07/03 职场文书
纪念9.18事变演讲稿
2014/09/14 职场文书
党委领导班子整改方案
2014/09/30 职场文书
解约证明模板
2015/06/19 职场文书
文明礼貌主题班会
2015/08/14 职场文书
高考要来啦!用Python爬取历年高考数据并分析
2021/06/03 Python
Java 获取Word中所有的插入和删除修订的方法
2022/04/06 Java/Android
JavaScript原型链中函数和对象的理解
2022/06/16 Javascript