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 相关文章推荐
网页里控制图片大小的相关代码
Jun 25 Javascript
jQuery 获取URL参数的插件
Mar 04 Javascript
jQuery简单实现banner图片切换
Jan 02 Javascript
jquery实现ajax提交form表单的方法总结
Mar 03 Javascript
js实现最短的XML格式化工具实例
Mar 12 Javascript
JavaScript字符串常用类使用方法汇总
Apr 14 Javascript
javascript每日必学之多态
Feb 23 Javascript
Javascript HTML5 Canvas实现的一个画板
Apr 12 Javascript
深入理解js promise chain
May 05 Javascript
基于zepto.js实现手机相册功能
Jul 11 Javascript
强大的JavaScript响应式图表Chartist.js的使用
Sep 13 Javascript
js实现简单的日历显示效果函数示例
Nov 25 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数组函数序列之ksort()对数组的元素键名进行升序排序,保持索引关系
2011/11/02 PHP
PHP学习笔记 IIS7下安装配置php环境
2012/10/29 PHP
php关联数组与索引数组及其显示方法
2018/03/12 PHP
PHP类的自动加载与命名空间用法实例分析
2020/06/05 PHP
用prototype实现的简单小巧的多级联动菜单
2007/03/24 Javascript
在JS中最常看到切最容易迷惑的语法(转)
2010/10/29 Javascript
JavaScript中创建对象和继承示例解读
2014/02/12 Javascript
jQuery实现下拉框左右选择的简单实例
2014/02/22 Javascript
基于bootstrap实现广告轮播带图片和文字效果
2016/07/22 Javascript
JS给按钮添加跳转功能类似a标签
2017/05/30 Javascript
javascript基本常用排序算法解析
2017/09/27 Javascript
JS获取并处理php数组的方法实例分析
2018/09/04 Javascript
vue this.reload 方法 配置
2018/09/12 Javascript
Vue中Axios从远程/后台读取数据
2019/01/21 Javascript
基于JavaScript实现猜数字游戏代码实例
2020/07/30 Javascript
解决vue路由name同名,路由重复的问题
2020/08/05 Javascript
Python绘制KS曲线的实现方法
2018/08/13 Python
在Python中实现替换字符串中的子串的示例
2018/10/31 Python
Python数据预处理之数据规范化(归一化)示例
2019/01/08 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
Python爬虫工具requests-html使用解析
2020/04/29 Python
python怎么判断素数
2020/07/01 Python
python如何写try语句
2020/07/14 Python
CSS3 渐变(Gradients)之CSS3 线性渐变
2016/07/08 HTML / CSS
使用Html5中的cavas画一面国旗
2019/09/25 HTML / CSS
Mytheresa英国官网:拥有160多个奢侈品品牌
2016/10/09 全球购物
东方电视购物:东方CJ
2016/10/12 全球购物
戴森香港官方网站:Dyson香港
2021/02/11 全球购物
社会实践自我鉴定
2013/11/07 职场文书
士力架广告词
2014/03/20 职场文书
委托书范本
2014/04/02 职场文书
中学生秋季运动会广播稿
2014/09/21 职场文书
模范班主任事迹材料
2014/12/17 职场文书
基于python实现银行管理系统
2021/04/20 Python
SpringBoot实现quartz定时任务可视化管理功能
2021/08/30 Java/Android
PyTorch中permute的使用方法
2022/04/26 Python