您的位置:首页 > Web前端 > JavaScript

JavaScript设计模式基础-----封装、继承、多态

2017-09-26 15:58 477 查看
// 函数的基本形式
function checkName() {
"use strict";

}
function checkEmail() {
"use strict";

}
function checkPassword() {
"use strict";

}

// 函数的另一种形式
var checkName = function () {
"use strict";

}
var checkEmail = function () {
"use strict";

}
var checkPassword = function () {
"use strict";

}

// 上面两种等于声明了全局变量
// 这个从功能上讲是没有问题的,但是如果别人也定义了同样的方法就会覆盖掉这个函数

/*
* 用对象收编变量
* */
var CheckObject = {
checkName: function () {
"use strict";

},
checkEmail: function () {
"use strict";

},
checkPassword: function () {
"use strict";

}
}

// 将所有的函数作为checkObject的方法,这样就只有一个对象 用法:CheckObject.checkName()

/*
* 对象的另一种形式
* */
var CheckObject = function () {

}
CheckObject.checkName = function () {
"use strict";

}
CheckObject.checkEmail = function () {
"use strict";

}
CheckObject.checkPassword = function () {
"use strict";

}
//用法:CheckObject.checkName()  不好处就是比人不能复制你的代码,这个对象在用new关键字创建新对象的时候新创建的对象是不能继承这些方法的

/*
* 实现简单复制
* */
var CheckObject = function () {
"use strict";
return {
checkName: function () {
"use strict";

},
checkEmail: function () {
"use strict";

},
checkPassword: function () {
"use strict";

}
}
}
// 这样每个人用的时候都是返回一个新对象 通过new 实例化的时候 互不影响
// 用法:var a= CheckObject(); a.checkName();

/*
* 用类的写法 每次new的时候新创建的对象都会有一套自己的方法,这样很消耗内存
* */
var CheckObject = function () {
"use strict";
this.checkName = function () {

}
this.checkEmail = function () {

}
this.checkPassword = function () {

}
}
// 用法:var a = new CheckObject(); a.checkPassword();

/*
这个对象创建出来的方法就都是相同的,因为他们都需要一来prototype原型一次查找
* */
var CheckObject = function () {
"use strict";

}
CheckObject.prototype.checkName = function () {
"use strict";

}
CheckObject.prototype.checkEmail = function () {

}
CheckObject.prototype.checkPassword = function () {

}
//简写
var CheckObject = function () {
}
CheckObject.prototype = {
checkName: function () {
"use strict";

},
checkEmail: function () {
"use strict";

},
checkPassword: function () {
"use strict";

}
}
// 用法:var a = new CheckObject(); a.checkName();
// =================== 注意==========================
// 这两种方法不能一起用 一起用的话 后面的prototype 方法会覆盖前面的

var CheckObject = {
checkName: function () {
"use strict";
return this;
},
checkEmail: function () {
"use strict";
return this;
},
checkPassword: function () {
"use strict";
return this;
}
}
// 链式调用
// CheckObject.checkName().checkEmail();
// 也可以放到原型中
var CheckObject = function () {
"use strict";

}
CheckObject.prototype = {
checkName: function () {
"use strict";
return this;

},
checkEmail: function () {
"use strict";
return this;

},
checkPassword: function () {
"use strict";
return this;
}
}
// 用法:var a = new CheckObject(); a.checkName().checkEmail();

/*
为函数的原型添加方法
* */
Function.prototype.addMethod = function (name, fn) {
this[name] = fn; // 如果要添加到prototype上 使用的时候要使用new 关键字 this.prototype[name]=fn; 使用的时候要使用new
return this;
}
var methods = new function ();
methods.addMethod('checkName', function () {
// 如果要链式调用 返回this

}).addMethod('checkEmail', function () {

});
methods.chekcName();

// ============================ 面向对象 ============================ //

// 创建一个类
var Book = function (id, bookname, price) {
this.id = id;
this.bookname = bookname;
this.price = price;
}
// 为类添加方法
Book.prototype = {
display: function () {

}
}

// 封装
var Book = function (id, name, price) {
// 私有属性 相当于php private 定义的方法
var num = 1;
// 私有方法
function checkId() {

}

// 特权方法  相当于php为变量设置和获取值的方法
this.getName = function () {

}
this.setName = function () {

}
this.getPrice = function () {

}
this.setPrice = function () {

}

// 公有属性 相当于php的public定义的属性和方法 【这相当于css的style 优先级要比prototype的高】
this.id = id;
// 公有方法
this.copy = function () {

}

// 构造器 相当于php的__construct
this.setName(name);
this.setPrice(price);
}
// 类外部通过 . 语法定义的属性和方法 称为 静态公有属性和方法 但是对象不能访问 相当于php static 定义的属性和方法 只能通过类名.属性、方法访问
Book.isChinese = true;
Book.resetTime = function () {
console.log('new time')
}
// 通过prototype定义的属性和方法称为公有属性和方法
Book.prototype = {
// 公有属性
isJsBook: false,
// 公有方法
display: function () {

}
}
// 用法 : var b= new Book(11,'JavaScript设计模式',50);

/*
* 升级版本的封装 function 对象的
* */

function Person(info) {
this._init_(info)
}
Person.prototype = {
constructor: Person,
_init_: function (info) {
this.name = info.name;
this.age = info.age;
this.sex = info.sex;
},
sayHello: function () {
console.log('hello');
}
}

/*
* 升级版本2  仿照jquery
* */
var Person = (function (window) {
var Person = function (name) {
// 直接实例化
return new Person.fn.init(name);
}

Person.fn = Person.prototype = {
constructor: Person,
init: function (name) {
this.name = name;
this.sayHello = function () {
this.makeArray();
}
},
makeArray: function () {
console.log(this.name);
}
}

Person.fn.init.prototype = Person.fn;

return Person;
})();
/*
var p = Person('pawn');
console.log(p);
p.sayHello();
*/

每个类都有三部分组成
1.
构造函数内部的这是供实例化对象复制用的
2.
构造函数外部的直接通关.语法添加的
只是类使用的
只有类.才可以访问
3.
添加在prototype中的
实例化对象时可以通过原型直接访问到
是给所有实例化对象所共用的

/*
* 继承 http://www.cnblogs.com/humin/p/4556820.html * */
// 定义一个动物类
function Animal(name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function () {
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function (food) {
console.log(this.name + '正在吃:' + food);
};

//1、原型链继承
//核心: 将父类的实例作为子类的原型

function Cat() {
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
//instanceof主要的目的是检测引用类型
//typeof 是一个操作符,主要的目的是检测一个变量是不是基本数据类型的变量
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true

/*特点:

非常纯粹的继承关系,实例是子类的实例,也是父类的实例
父类新增原型方法/原型属性,子类都能访问到
简单,易于实现

缺点:

要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
无法实现多继承
来自原型对象的引用属性是所有实例共享的(详细请看附录代码: 示例1)
创建子类实例时,无法向父类构造函数传参
推荐指数:★★(3、4两大致命缺陷)*/

//2、构造继承
//核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Cat(name) {
"use strict";
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

/*特点:

解决了1中,子类实例共享父类引用属性的问题
创建子类实例时,可以向父类传递参数
可以实现多继承(call多个父类对象)
缺点:

实例并不是父类的实例,只是子类的实例
只能继承父类的实例属性和方法,不能继承原型属性/方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
推荐指数:★★(缺点3)*/

//3、实例继承
//核心:为父类实例添加新特性,作为子类实例返回
function Cat(name) {
"use strict";
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
/*
特点:

不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:

实例是父类的实例,不是子类的实例
不支持多继承
推荐指数:★★*/

//4、拷贝继承

function Cat(name) {
var animal = new Animal();
for (var p in animal) {
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
/*特点:

支持多继承
缺点:

效率较低,内存占用高(因为要拷贝父类的属性)
无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
推荐指数:★(缺点1)*/

/*
5、组合继承

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
*/

function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
/*特点:

弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例
不存在引用属性共享问题
可传参
函数可复用
缺点:

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
推荐指数:★★★★(仅仅多消耗了一点内存)*/

/*
6、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
*/

function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
(function () {
// 创建一个没有实例方法的类 在js 中 继承是依赖于原型prototype链实现的
var Super = function () {
};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
/*
特点:

堪称完美
缺点:

实现较为复杂
推荐指数:★★★★(实现复杂,扣掉一颗星)
*/

//=============================================javascript 多继承========================================================
// 在JavaScript中继承是一来与prototype链实现的。因为只有一条原型链。理论上是不能继承多个父类,但是js是很灵活的。通过一些
//技巧和方法可以实现多继承
/**
* 作用就是将传入的多个对象的属性复制到源对象中 这样就可以实现对多个对象属性的继承
* 使用的时候第一个参数----需要传入要继承的对象
* @returns {*}
*/
var mix = function () {
var i = 1,// 从第一个参数起为被继承的对象
len = arguments.length,// 获取参数长度
target = arguments[0],// 第一个对象为目标对象
arg;// 缓存参数对象
for (; i < len; i++) {
// 缓存当前对象
arg = arguments[i];
// 遍历被继承对象中的属性
for (var property in arg) {
// 将被继承对象中的属性复制的目标对象中
target[property] = arg[property];
}
}
return target;
};

Object.prototype.mix = function () {
var i = 0, // 从第一个参数起为被继承的对象
len = arguments.length, // 获取参数长度
arg;// 缓存参数对象
// 遍历被继承的对象
for (; i < len; i++) {
// 缓存当前对象
arg = arguments[i];
// 遍历被继承对象中的属性
for (var property in arg) {
// 将被继承对象中的属性复制的目标对象中
this[property] = arg[property];
}
}
};

var book1 = {
name: 'book1',
alike: ['css', 'js', 'java']
};
var book3 = {
names: 'book1',
alikes: ['css', 'js', 'java']
};
var book2 = {
ccc: 'ccccccc'
};
var outhorBook = {
color: 'red'
};
outhorBook.mix(book1, book2, book3);
console.log(outhorBook);

/*
* ============================================= 多态 =============================================
* 指的是同一种方法多种调用方式
* */
function add() {
// 获取参数
var arg = arguments,
// 获取长度
len = arg.length;
switch (len) {
// 如果没有传参数
case 0:
return 10;
case 1:
return 10 + arg[0];
case 2:
return arg[0] + arg[1];
}
}
console.log(add()); // 10
console.log(add(5)); // 15
console.log(add(6, 7)); // 13

// or
function Add() {
function zero() {
return 10;
}

function one(num) {
return 10 + num;
}

function two(num1, num2) {
return num1 + num2;
}

// 相加共有方法
this.add = function () {
var arg = arguments,
len = arg.length;
switch (len) {
case 0:
return zero();
case 1:
return one(arg[0]);
case 2:
return two(arg[0], arg[1])
}
}
}
var a = new Add();
console.log(a.add());
console.log(a.add(5));
console.log(a.add(6, 7));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 设计模式