JavaScript设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal {
constructor(){
console.log('Animal......')
}
}

class Dog extends Animal{
constructor(){
super();//必须调用父类构造函数
console.log("Dog......")
}
}

var d = new Dog();//Animal......,Dog......

简单模拟Object.create

1
2
3
4
5
Object.create = Object.create || function(obj){
var F = function(){}
F,prototype = obj;
return new F()
}

1.工厂模式

无法识别类型,无法复用函数,属性

1
2
3
4
5
6
7
8
9
10
11
12
function createPerson(name,age,job){
var o = {};
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
return o.name
}
return o
}

var conan = createPerson('conan',25,'ceo')

2.构造函数

构造函数内的函数,不能复用,都是不一样的函数

1
2
3
4
5
6
7
8
9
10
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
return this.name
}
}

var conan = new Person('conan',35,'ceo')

3.构造函数 + 原型模式

算是比较符合js设计原则的OOP模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
}

Person.prototype.sayName = function () {
return this.name
}

var conan = new Person('conan',35,'ceo')

Person.prototype = {
sayName(){
return this.name
},
sayJob(){
return this.job
},
constructor:Person
}


(构造)函数 都有一个prototype属性,指向原型对象,
原型对象都有一个constructor属性指向构造函数,
实例都有一个指向原型对象的指针proto

_继承_


原型链的继承

包含引用类型值的原型会被共享,class 方案解决了这个问题,besides,子类不能像父类构造函数传值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function SuperType(){
this.subs = []
}

function ChildType(){}

ChildType.prototype = new SuperType();
ChildType.prototype.constructor = ChildType;

class SuperType{
constructor(){
this.subs = [1,2,3]
}
}

class SubType extends SuperType{

}

var sub1 = new SubType();
var sub2 = new SubType();

借用构造函数

(可以调用父类的构造函数),复用是个问题

1
2
3
4
5
6
7
8
function SuperType(){
this.subs = ['old'];
}

function SubType(){
SubType.call(this)
this.newSubs = ['new'];
}

组合继承

(能够复用,能够调用父类构造函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function SuperType(name){
this.name = name;
this.subs = [1,2,3]
}

SuperType.prototype.SupersayName = function(){
return this.name
}

function SubType(name,age){
SuperType.call(this,name)
this.age = age
}

SubType.prototype = new SuperType()
SubType.prototype.constructor = SubType

原型式继承(子类和父类引用属性共享)

1
2
3
4
5
function create(obj){
function F(){}
F.prototype = obj;
return new F();
}

寄生式继承

1
2
3
4
5
6
7
function createAnother(obj){
var newObj = create(obj);
newObj.sayName = function () {
return 'lalala...'
}
return newObj;
}

寄生组合式继承

通过构造函数来继承属性,通过原型链来继承方法)这个最优,保持函数,属性复用,能调用父类构造函数,只执行一次父类构造函数

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
function inherit(subType,SuperType){
var proto = crate(SuperType.prototype)
proto.constructor = subType;
subType.prototype = proto;
}

*bind*

Function.prototype.bind = function(context){
var self = this;
return function(){
return self.apply(context,arguments)
}
}

*复杂版bind*

Function.prototype.bind = function(){
var that = this;
var args = [...arguments]
var context = args.shift()
return function(){
return that.apply(context,args.concat([...arguments]))
}
}

function a(){
return this.a
}

var b = {a:333}

*判断类型*

var isArray = function(arr){
return Object.prototype.toString.call(arr) === '[object Array]'
}

var isType = function(type){
return function(ele){
return Object.prototype.toString.call(ele) === `[object ${type}]`
}
}

var isArray = isType("Array");
isArray([]);//true

*单例*

var getSingle = function(fn){
var ret
return function(){
return ret || ret = fn.call(this,...arguments)
}
}

*分时处理函数*

var timeChunk = function(arr,fn,count){
var t
var start = function(){
for(var a=0;a<Math.min(count||1,arr.length);a++){
fn(arr.shift())
}
}
return function(){
t = setInterval(()=>{
if(arr.length <= 0){
clearInterval(t)
}
start()
},500)
}
}

单例模式

1
2
3
4
5
6
var getSingle = function(fn){
var res;
return function(){
return res || (res = fn.apply(this,arguments))
}
}

策略模式

迭代器模式

1
2
3
4
5
var each = function(arr,callback){
for(let a = 0; a < arr.length; a++){
callback.call(arr[a],i,arr[a]);//传递下标和元素本身
}
}

发布 - 订阅模式 (时间,空间上的解耦)

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
var Subscriber = {};

// Subscriber.subs = [];
Subscriber.subs = {};

Subscriber.listen = function(key,fn){
if(!this.subs[key]){
this.subs[key] = []
}
this.subs[key].push(fn)
}

Subscriber.trigger = function(){
var key = [...arguments][0]
if(this.subs[key].length === 0){
return
}
for(let a of this.subs[key]){
a.apply(this,arguments)
}
}

//- - - - - - 修改完善

var event = {
subs : {},
on: function(type,fn){
if(!this.subs[type]){
this.subs[type] = []
}
this.subs[type].push(fn)
},
emit: function(){
var args = [...arguments]
var type = args.shift()
var that = this
if(this.subs[type].length === 0){
return
}
this.subs[type].forEach(fn=>{
fn.apply(that,args)
})
},
off:function(type,fn){
var types = this.subs[type];
if(!types){
return false
}
if(!fn){
types && (types.length = 0)
}else{
for(let _fn of types){
if(_fn === fn){
types.splice(types.indexOf(_fn),1)
}
}
}
}
}

ES6 class 模式

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
class Event {
constructor(){
this.subs = {}
}
on(type,fn){
if(!this.subs[type]){
this.subs[type] = [];
}
this.subs[type].push(fn)
}
emit(){
var args = [...arguments]
var type = args.shift();
var that = this;
if(!type){
return false
}
this.subs[type].forEach(fn=>{
fn.apply(that,args)
})
}
off(type,fn){
var fns = this.subs[type]
if(!fns){
return false
}
if(!fn){
fns.length = 0
}else{
for(let _fn of fns){
if(_fn === fn){
fns.splice(fns.indexOf(_fn),1)
}
}
}
}
}