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 相关文章推荐
JavaScript随机排序(随即出牌)
Sep 17 Javascript
jquery maxlength使用说明
Sep 09 Javascript
js/html光标定位的实现代码
Sep 23 Javascript
jQuery选择器全面总结
Jan 06 Javascript
js动态创建标签示例代码
Jun 09 Javascript
Jquery 实现checkbox全选方法
Jan 28 Javascript
ES6所改良的javascript“缺陷”问题
Aug 23 Javascript
jQuery手指滑动轮播效果
Dec 22 Javascript
原生javascript实现的全屏滚动功能示例
Sep 19 Javascript
详解vuex之store拆分即多模块状态管理(modules)篇
Nov 13 Javascript
Vant的安装和配合引入Vue.js项目里的方法步骤
Dec 05 Javascript
vue父子组件间引用之$parent、$children
May 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脚本自动识别验证码查询汽车违章
2016/12/20 PHP
phpStudy配置多站点多域名和多端口的方法
2017/09/01 PHP
PHP实现广度优先搜索算法(BFS,Broad First Search)详解
2017/09/16 PHP
Javascript 表单之间的数据传递代码
2008/12/04 Javascript
查询json的数据结构的8种方式简介
2014/03/10 Javascript
JS中自定义定时器让它在某一时刻执行
2014/09/02 Javascript
Javascript实现禁止输入中文或英文的例子
2014/12/09 Javascript
$.extend 的一个小问题
2015/06/18 Javascript
鼠标经过子元素触发mouseout,mouseover事件的解决方案
2015/07/26 Javascript
javascript跨域方法、原理以及出现问题解决方法(详解)
2015/08/06 Javascript
浅析jQuery移动开发中内联按钮和分组按钮的编写
2015/12/04 Javascript
NodeJS的Promise的用法解析
2016/05/05 NodeJs
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
JavaScript正则表达式小结(test|match|search|replace|split|exec)
2016/12/08 Javascript
详解Vue整合axios的实例代码
2017/06/21 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
2018/01/08 Javascript
vue基础之模板和过滤器用法实例分析
2019/03/12 Javascript
JS中的算法与数据结构之集合(Set)实例详解
2019/08/20 Javascript
Element ui 下拉多选时新增一个选择所有的选项
2019/08/21 Javascript
taro 实现购物车逻辑的实例代码
2020/06/05 Javascript
Vue如何将页面导出成PDF文件
2020/08/17 Javascript
javascript实现扫雷简易版
2020/08/18 Javascript
Bootstrap FileInput实现图片上传功能
2021/01/28 Javascript
python日期时间转为字符串或者格式化输出的实例
2018/05/29 Python
python一行sql太长折成多行并且有多个参数的方法
2018/07/19 Python
Python使用pyautogui模块实现自动化鼠标和键盘操作示例
2018/09/04 Python
深入解析HTML5 Canvas控制图形矩阵变换的方法
2016/03/24 HTML / CSS
Avène雅漾美国官方网站:敏感肌肤护理专家
2016/10/24 全球购物
马来西亚演唱会订票网站:StubHub马来西亚
2018/10/18 全球购物
大整数数相乘的问题
2012/07/22 面试题
百日安全生产活动总结
2014/07/05 职场文书
小学生纪念九一八事变演讲稿
2014/09/14 职场文书
全国法院系统开展党的群众路线教育实践活动综述(全文)
2014/10/25 职场文书
小区保洁员岗位职责
2015/04/10 职场文书
2016廉政教育学习心得体会
2016/01/25 职场文书
Nginx使用Lua模块实现WAF的原理解析
2021/09/04 Servers