面向对象和设计模式
类的声明
以下以 ES5 为例,ES6 引入
class
关键字,可以像其他语言一样直接使用class
声明类
我们可以使用 function 关键字,类似于声明一个函数一样,声明一个类。
function Book(name,writer,price){
this.name=name;
this.writer=writer;
this.price=price;
}
注意,根据命名规范,如果 function 声明的是类,类名首字母需要大写。
声明好了类,我们就可以使用 new
关键字来生成一个对象
var book = new Book("book1","Tom","59.9")
Ï当然,我们也可以给 Book 类添加成员方法,给 类添加成员方法 一般有两种常用方法
使用 this
赋值成员方法
我们可以像声明成员变量一样声明类的成员方法,毕竟 js 中函数是一等公民,可以当变量一样使用
function Book(name,writer,price){
this.name=name;
this.writer=writer;
this.price=price;
// 这里需要注意保留 Book 函数域内的 this
var that = this;
// function 中的 this 是指向自身的,所以需要使用 that
this.getRMB = function (){
return that.price+"元";
}
}
var book = new Book("book1","Tom","59.9")
var book2 = new Book("book2","jack","29.9")
// 调用成员方法
book.getRMB()
console.log(book.getRMB == book2.getRMB) //false,每个对象的 getRMB 都是独立的函数
使用 prototype
声明成员方法
我们可以通过给类的 constructor 添加 prototype
,js 会自动给其生成的对象添加 __proto__
属性,形成原型链.
从而实现对象共享成员方法
function BookP(name,writer,price){
this.name=name;
this.writer=writer;
this.price=price;
}
// 设置 BookP 的 prototype 属性
BookP.prototype.getRMB = function(){
return this.price+"元";
}
var bookp = new BookP("book1","Tom","59.9")
var bookp2 = new BookP("book2","jack","29.9")
// 调用成员方法
bookp.getRMB()
console.log(bookp.getRMB == bookp2.getRMB) // true, 所有对象共用一个 getRMB
这个方法所有对象共享同一成员函数,效率更高,建议使用
代码封装
学会了类的概念,我们就可以使用类来封装模块,使得我们的代码可重用,同时又屏蔽了代码的复杂性。
下面就以 返回顶部
为例,进行代码封装
目的
我们在外部可以使用如下代码,即可在页面中添加 返回顶部
按钮
var ele = $(".back-top")
new BackTop(ele);
实现
function BackTop($node){
var timer;
$node.on("click",function(){
window.scrollTo(0,0);
})
window.onscroll = function () {
console.log("onscroll")
// 防止事件过多
clearTimeout(timer)
timer = setTimeout(function () {
var windowH = $(window).height();
var scrollTop = $(window).scrollTop();
if(scrollTop > windowH *0.5){
$node.addClass("show")
}
if(scrollTop < windowH *0.5){
$node.removeClass("show")
}
}, 50)
}
}
我们可以把复杂的逻辑包装在 BackTop
这个类里
完整代码可以参看这里
常用设计模式
工厂模式
我们来看一个简单的例子:
var employee1 = new Object();
employee1.position = "Front end engineer";
employee1.tool = "I love vscode.";
employee1.introduction = function () {
console.log("I am a " + this.position + ", and " + this.tool);
}
var employee2 = new Object();
employee2.position = "UI designer";
employee2.tool = "I love photoshop.";
employee2.introduction = function () {
console.log("I am a " + this.position + ", and " + this.tool);
}
employee1.introduction(); // I am a Front end engineer, and I love vscode.
employee2.introduction(); // I am a UI designer, and I love photoshop.
在上边这个例子中,我们定义了两个employee,一个是Front End Engineer,另一个是UI designer,他们都有position属性和tool属性,也都有introduction方法。如果我们需要创建很多个类似employee的对象呢,那我们就需要重复很多类似的代码。接下来,我们做一些简单的修改:
function Employee(type) {
var employee;
if (type == "programmer") {
employee = new Programmer();
} else if (type == "designer") {
employee = new Designer();
}
employee.introduction = function () {
console.log("I am a " + this.position + ", and " + this.tool);
}
return employee;
}
function Programmer() {
this.position = "Front end engineer";
this.tool = "I love vscode.";
}
function Designer() {
this.position = "UI designer";
this.tool = "I love photoshop.";
}
var employee1 = Employee("programmer");
employee1.introduction();//I am a Front end engineer, and I love vscode.
var employee2 = Employee("designer");
employee2.introduction();//I am a UI designer, and I love photoshop.
单例模式
单例模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一变量进行访问。 优点是:
- 可以用来划分命名空间,减少全局变量的数量。
- 使用单体模式可以使代码组织的更为一致,使代码容易阅读和维护。
- 可以被实例化,且实例化一次。
function Singleton(name){
this.name = name;
};
Singleton.prototype.getName = function(){
return this.name;
}
// 获取实例对象
Singleton.getInstance = function() {
if(!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
// 测试单体模式的实例
var a = Singleton.getInstance();
var b = Singleton.getInstance();
console.log(a == b) // true,为同一个对象
在实际使用中,如遇模式对话框等场景,我可以考虑使用单例模式
其他设计模式
其实还有很多设计模式,如
- 模块模式
- 代理模式
- 职责链模式
- 命令模式
- 模板方法模式
- 策略模式
- 订阅模式
- 中介者模式
具体可以参看这里