面向对象就是将需求抽象出来成一个对象,针对对象分析其特性(属性)和动作(方法)。这个对象称之为类,面向对象最大的特点就是封装,将所需要的功能放在一个对象中。
1、封装一个类
在函数(类)内部通过 this 或者通过类的原型 prototype 来添加属性和方法
function People(name, sex) {
this.name = name
this.sex = sex
this.show = function(){
console.log('my name is' + this.name)
}
}
People.prototype.say = function() {
return 'Hello World'
}
此时已经将需要用的属性和方法都封装在了抽象的类 People 中。使用时只需通过关键字 new 来进行实例话。
var people = new People('小平不小', '男')
console.log(people)
console.log(people.name) //小平不小
console.log(people.say()) //Hello World
通过 this 添加的方法和属性是在当前对象上添加的,而通过prototype添加的方法和属性在当前对象的 proto 上。而js是基于原型 prototype 的语言,因此它会通过 prototype 向上一级一级的查找。如下图:

2、属性和方法的封装
js中没有显示的声明私有属性、私有方法。但可以通过js的灵活性来创建类的私有变量和私有方法。
var People = function(name, sex, age) {
//静态私有属性和私有方法
var like = 'gril'
function checkName() {}
// 特权方法
this.getName = function() {
return this.name
}
this.getSex = function() {
return this.sex
}
this.setName = function(name) {
this.name = name
}
this.setSex = function(sex) {
this.sex = sex
}
this.getLike = function() {
return like
}
//对象的公有属性
this.age = age
this.say = function() {
return 'Hello World'
}
//构造器
this.setName(name)
this.setSex(sex)
}
//类的静态共有属性和静态共有函数
People.country = 'China'
People.introduce = function() {
return 'I come from China'
}
//类的共有属性和共有方法
People.prototype = {
isAnimal: true,
display: function() {
return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
}
}
var people = new People('小平不小', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country) //undefined
console.log(People.country) //China 只能通过类来访问
在类的内部,通过 this 创建的对象和属性,在类的实例话创建对象时,每个对象都会拥有一份,并且在外部可以访问的到,因此 this 创建的属性可以看作时对象的共有属性和共有方法, this 创建的方法不仅可以访问对象的共有属性和共有方法,而且还可以访问类创建时的私有属性和私有方法,由于权利比较大,因此被称为特权方法。同时在对象创建时可以使用特权方法来初始化对象的属性,因此在创建对象时调用的特权方法还可以看成是类的构造器。通过类的 prototype 创建的属性和方法并不会在每一个对象上创建,但可以通过原型链一级一级的找到,因此被称为类的共有属性和共有方法。
3、利用闭包来实现一个完整的类
var People = function() {
var like = 'gril'
function checkName() {}
function _people(name, sex, age) {
// 静态私有属性和私有方法
var like = 'gril'
function checkName() {}
// 特权方法
this.getName = function() {
return this.name
}
this.getSex = function() {
return this.sex
}
this.setName = function(name) {
this.name = name
}
this.setSex = function(sex) {
this.sex = sex
}
this.getLike = function() {
return like
}
// 对象的公有属性和共有方法
this.age = age
this.say = function() {
return 'Hello World'
}
//构造器
this.setName(name)
this.setSex(sex)
}
//类的静态共有属性和静态共有函数
_people.country = 'China'
_people.introduce = function() {
return 'I come from China'
}
//构建原型
_people.prototype = {
//公有属性和共有方法
isAnimal: true,
display: function() {
return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
}
}
return _people
}()
var people = new People('小平不下', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country) //undefined
console.log(People.country) //China
此时看起来更像是一个整体,代码更加清晰。
4、创建对象的安全模式
上面的代码当我们在使用时,如果忘记进行 new 的操作,则函数内所有的 this 都指向 window,从而引起错误,因此可以再进行处理。如下
var People = function() {
var like = 'gril'
function checkName() {}
function _people(name, sex, age) {
// 静态私有属性和私有方法
if (this instanceof People) {
var like = 'gril'
function checkName() {}
// 特权方法
this.getName = function() {
return this.name
}
this.getSex = function() {
return this.sex
}
this.setName = function(name) {
this.name = name
}
this.setSex = function(sex) {
this.sex = sex
}
this.getLike = function() {
return like
}
// 对象的公有属性和共有方法
this.age = age
this.say = function() {
return 'Hello World'
}
//构造器
this.setName(name)
this.setSex(sex)
} else {
return new People(name,sex,age)
}
}
//类的静态共有属性和静态共有函数
_people.country = 'China'
_people.introduce = function() {
return 'I come from China'
}
//构建原型
_people.prototype = {
//公有属性和共有方法
isAnimal: true,
display: function() {
return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
}
}
return _people
}()
此时即使是忘记 new 操作,也能正常使用。
var people = People('小平不下', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country) //undefined
console.log(People.country) //China
4、继承
5、参考资料
《JavaScript设计模式 张容铭》
《JavaScript设计模式 》Addy Osmani著 徐涛译版
6、结束语
最近在看有关js设计模式的知识,整理出来作为笔记,如果错误,欢迎大家指正,谢谢🙏