第一部分基础知识
1.面向对象的Javascript
1.1:动态类型语言和鸭子类型
编程语言按照数据类型大致可以分为两类:静态类型语言和动态类型语言。相对于静态类型语言,动态类型语言具有编写代码的数量更少,代码更简洁,更专注于逻辑表达等优点。动态类型语言的一种编写风格就是鸭子类型,鸭子类型知道我们应该关注对象的行为,而不是关注对象的本身。我们下面可以使用代码来模拟一下这个场景
var duck = {
singing:function() {
console.log("嘎嘎嘎")
}
}
var chicken = {
singing:function() {
console.log("嘎嘎嘎")
}
}
var choir = []
function joinChoir(animal) {
if(animal && animal.singing == "function") {
choir.push(animal)
console.log("恭喜加入合唱团,当前合唱团的人员数量" + choir.length)
}
}
joinChoir(duck)
joinChoir(chicken)
在鸭子类型中,关注点在于对象的行为,而不是对象的本身,上述代码中因为chicken具有singing方法,所以以假乱真的加入了合唱团
1.2 多态
下面我们来看一段真实开发中的场景
现在需要开发一个表盘,表盘的顶部需要渲染出一个日期,需求很简单,我们很容易就能写出如下的代码
function renderTop() {
console.log("开始渲染顶部的日期")
}
后来,公司领导觉得这个表盘太单调了,于是提了一些新的需求。表盘的头部是支持自定义的,可以显示日期,自定义文本,和时间,于是理所当然的你又写出了如下的代码
function renderTop(type) {
if(type == "date") {
console.log("顶部渲染日期")
}else if(type == "text") {
console.log("顶部渲染自定义文本")
}else if(type == "time") {
console.log("顶部渲染时间")
}
}
可以看到,虽然renderTop这个函数保持了一定的弹性,但这种弹性是很脆弱的,一但将来顶部需要增加其它的编辑选项,我们就需要改动renderTop这个函数的内部逻辑,继续往里面堆积嵌套分支语句。
现在我们借用多态的思想来改写这堆代码kyi
function renderTop(widget) {
widget.show()
}
let date = {
show:function() {
console.log("渲染日期")
}
}
let text = {
show:function(text) {
console.log("渲染自定义文本" + text)
}
}
let time = {
show:function() {
console.log("渲染时间")
}
}
renderTop(date)
renderTop(text("hello world"))
renderTop(time)
可以看到,经过改造后的代码,弹性大大加强,如果后期我们需要头部可以渲染成一张banner图片,那么我们只需要在添加一个banner对象,确保它拥有show方法就可以,而不需要去深入修改renderTop这个函数的逻辑 。
1.3 封装
封装的目的是将信息隐藏,一般而言,我们讨乱的封装是封装数据和封装实现。这一节,我们将讨乱更广义上的封装,不仅包括封装数据和封装实现,还包括封装类型和封装变化
1.3.1封装数据
在许多语言中,封装数据是通过语法解析来实现的,但是在JS中并没有提供对这些语法的支持,所以,在JS中只能依赖变量的作用域特性来实现封装数据特性
下面我们来看一段模拟出public,private两种特性的代码1
var myObject = (function() {
var _name = "jack" //私有变量
return {
getName:function() { //公开方法
return _name
}
}
})()
1.3.2封装实现
封装实现就是对象只对他自己的行为负责,只需要暴露一个对外的接口供外部使用,其它用户并不需要关注内部的具体实现
1.3.3封装变化
通过封装变化的方式,把系统中稳定不变的部分和容易变化的部分隔离开来,在系统的演变 过程中,我们只需要替换那些容易变化的部分,如果这些部分是已经封装好的,替换起来也相对 —容易。这可以最大程度地保证程序的稳定性和可扩展性