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

     
     
  • 从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本
深拷贝

     
     
1
2
3
4
5
6
7
8
9
10
11
     
     
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];
}
}
}
  • 利用递归进行深拷贝,这样子对象的修改就不会影响到父对象
     
     
1
2
3
     
     
extendDeeply(Person, programer);
programer.address.home = 'allin';
Person.address.home; // home
利用call和apply继承

     
     
1
2
3
4
5
6
7
8
     
     
function Parent(){
this.name = "abc";
this.address = { home: "home"};
}
function Child(){
Parent.call( this);
this.language = "js";
}
ES5中的Object.create()
     
     
1
2
3
     
     
var p = { name : 'allin'};
var obj = Object.create(o);
obj.name; // allin
  • Object.create()作为new操作符的替代方案是ES5之后才出来的。我们也可以自己模拟该方法:
     
     
1
2
3
4
5
6
7
8
9
10
     
     
//模拟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)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署
     
     
1
2
3
4
5
6
7
     
     
  if (! Object.create) {
     Object.create = function (o) {
       function F() {}
      F.prototype = o;
       return new F();
    };
  }
类的继承

Object.create()

     
     
1
2
3
4
5
6
7
8
9
     
     
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的指向
调用父类方法

     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
     
     
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是没有命名空间的,因此可以用对象模拟
     
     
1
2
3
4
5
6
7
8
9
10
     
     
var app = {}; // 命名空间app
//模块1
app.module1 = {
name: 'allin',
f: function(){
console.log( 'hi robot');
}
};
app.module1.name; // "allin"
app.module1.f(); // hi robot
静态成员

     
     
1
2
3
4
5
6
7
8
9
     
     
function Person(name){
var age = 100;
this.name = name;
}
//静态成员
Person.walk = function(){
console.log( 'static');
};
Person.walk(); // static
私有与公有

     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     
     
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
模块化

     
     
1
2
3
4
5
6
7
8
9
10
11
     
     
var moduleA;
moduleA = function() {
var prop = 1;
function func() {}
return {
func: func,
prop: prop
};
}(); // 立即执行匿名函数
多态

模拟方法重载

  • arguments属性可以取得函数调用的实参个数,可以利用这一点模拟方法的重载
     
     
1
2
3
4
5
6
7
8
     
     
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);
     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
     
     
//实现可变长度实参的相加
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'});
方法重写

     
     
1
2
3
4
5
6
7
8
9
10
11
     
     
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(''); 抛异常。这样防止这个类被直接调用
     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     
     
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值