一、设计:设计原则 模式:设计模式
设计原则:
1、单一职责
2、开闭原则
3、里氏替换
4、迪米特法则
5、接口隔离
6、依赖倒置
单例模式-高阶函数
<script type='module'>
// 单例模式,高阶函数,函数作为参数输出,或者输出函数
import Person from './object2.js'
function getSingle(fn){
let instance
return function (...arg){
if(!instance){
instance = new fn(...arg)
}
return instance
}
}
let createSingleFn = getSingle(Person)
let joy = createSingleFn('joy')
let tom = createSingleFn('tom')
console.log(joy, tom) // joy
</script>
工厂函数
根据不同的参数,生成不同的实例
class Luban{
constructor(){
this.name = 'luban'
}
}
class Yase{
constructor() {
this.name = 'yase'
}
}
function Factory(heroName){
if(heroName == 'luban'){
return new Luban()
}
if(heroName == 'Yase'){
return new Yase()
}
}
// 工厂函数,根据不同的参数,生成不同的对象实例
console.log(Factory('luban'))
console.log(Factory('Yase'))
装饰者模式
class Hero{
constructor() {
this.name = 'yase'
}
fire(){
console.log('释放了技能')
}
}
function hurt(num){
console.log('造成了' + num + '伤害')
}
// 装饰着模式
// 在方法的原型上面添加Decorator方法,让每一个方法都有一个装饰者方法
Function.prototype.Decorator = function (fn, ...arg){
this() // 执行Function方法,即执行被装饰的方法先执行一遍
fn(...arg) // 参数方法 的执行,该方法传入..arg里面的参数
}
// 获取实例
let yase = new Hero()
// 获取实例方法,并且传入要装饰的方法和参数
yase.fire.Decorator(hurt, 100)
自定义事件
index.html
<script type='module'>
import './object2.js'
</script>
index.js
export default class myEvent{
constructor() {
this.handle = {}
}
addEvent(eventName, fn){
if(typeof this.handle[eventName] === 'undefined'){
this.handle[eventName] = []
}
this.handle[eventName].push(fn)
}
trigger(eventName){
this.handle[eventName].forEach(fn => {
fn()
})
}
removeEvent(eventName, fn){
let fns = this.handle[eventName]
let index
if((index = fns.indexOf(fn)) !== -1){
fns.splice(index, 1)
}
}
}
function fn1(){
console.log('fn1...')
}
function fn2(){
console.log('fn2...')
}
function fn3(){
console.log('fn3...')
}
let events = new myEvent()
events.addEvent('myEvent', fn1)
events.addEvent('myEvent', fn2)
events.addEvent('myEvent', fn3)
events.removeEvent('myEvent', fn2)
events.trigger('myEvent') // fn1 fn3
二、面向对象的编程思想
- 面向过程: 注重解决问题的步骤,分析问题需要的每一步,实现函数一次调用
- 面向对象: 是一种程序设计思想。将数据和处理数据的程序封装到对象中。
- 面向对象特性: 抽象、继承、封装、多态
优点: 提高代码的复用性及可维护性。
1.对象的创建
1.1对象字面量
let obj = {
name: 'joy',
age: 15,
hobby: function (){
console.log('swim')
}
}
console.log(obj) // obj{name: 'joy'...}
1.2构造函数
let obj = new Object()
obj.name = 'joy'
obj.age = 17
obj.hobby = function (){
console.log('swim')
}
console.log(obj) // obj{name : 'joy' ...}
1.3Object.create() 属性方法放在原型上
let str = 'sex'
let obj = Object.create({
name: 'joy',
[str]: 'man',
age: 15,
hobby(){
console.log('swim')
}
})
console.log(obj) // 属性在原型上
console.log(obj[str]) // 'man'
2.工厂模式
//工厂模式
function Person(name, age, hobby){
let obj = {} // 添加原料
obj.name = name
obj.age = age
obj.hobby = hobby
// 加工
return obj // 返回成品,
}
let joy = Person('joy', '14', 'swim')
console.log(joy) // {name: 'joy', age: 14, hobby: 'swim'}
3.原型
Person.prototype.fn2 = () => {
console.log('fn2')
}
function Person(name){
this.name = name
this.fn = () => {
console.log('fn')
}
}
let joy = new Person('joy')
let tom = new Person('tom')
console.log(joy.fn === tom.fn) // false 虽然函数一样,但是函数地址不一样,存在不同空间
console.log(joy.fn2 === tom.fn2) // true 在同一空间存储内容,更节约性能
console.log(joy.__proto__ === Person.prototype) // true
console.log(joy.constructor === Person) // true 系统自己在原型上指定了来自哪个构造函数
4.原型、实例、构造函数三者的关系
let temp
function Person(name){
this.name = name
this.age = 20
//temp = this
}
// 如果这里使用箭头函数,this就会指向其父级
Person.prototype.fn = function() {
console.log(1)
temp = this
}
console.log(Person.prototype.constructor === Person) // true
// 构造函数里面的this指向实例对象
// 原型上面的方法里面的this也指向实例化对象,如果用了箭头函数,this指向其父级
let joy = new Person('joy')
joy.fn()
console.log(temp)
console.log(joy === temp) // true
5.call,apply,bind
function foo(name, age){
console.log('姓名是' + this.name + ',年龄是' + age)
console.log(this)
}
let obj = {
name: 'joy'
}
//foo.call(obj, 'tom', 16) // joy
//foo.apply(obj,['tom', 15]) // joy
foo.bind(obj)('tom', 13) // 返回的是一个函数,需要传参执行或者直接执行 joy
6.深拷贝
let obj = {
name: 'joy',
age: '15',
son: {
name: 'you',
age: 1
},
test: undefined,
hobby(){
console.log('swim')
}
}
// 用JSON可以进行深拷贝,但是会丢失undefined和方法属性
//let obj2 = JSON.parse(JSON.stringify(obj))
let obj2 = deepCopy(obj)
obj2.son.sex = 'man'
console.log(obj2)
console.log(obj)
// 自定义深拷贝函数
function deepCopy(obj){
// 判断如果obj是对象的话,就分别创建{}和[]
let newObj = Array.isArray(obj) ? [] : {};
// 遍历
for(let prop in obj){
// for in 也会遍历父级的属性,需要判断该属性是不是自己的
if(obj.hasOwnProperty(prop)){
if(typeof obj[prop] === 'object'){
// 如果是对象,递归
newObj[prop] = deepCopy(obj[prop])
}else{
// 否则直接赋值
newObj[prop] = obj[prop]
}
}
}
return newObj
}
// 原型继承也可以用深拷贝
Son.prototype = deepCopy(Dad.prototype)
// 可以达到父子之间的有独立的方法和属性
// 或者以下方法也可以解决父原型与子原型的同地址问题
let link = function (){}
link.prorotype = Dad.prototype
Son.prototype = new link()
// 把构造函数指向重新指向Son
Son.prototype.constructor = Son