一.设计模式
所谓的设计模式,是 JavaScript 程序的一种高级书写规范
为了优化代码,减少重复冗余的代码
每一种设计模式是为了 解决 某个特定的问题而设置的代码书写规范
二.单例模式概念
<script>
// 有一个构造函数
class createObj{
constructor(name,age){
this.name = name;
this.age = age;
}
fun(){
console.log(this.name,this.age);
}
}
// 通过构造函数,生成实例化对象
const obj1 = new createObj('张三' , 18);
const obj2 = new createObj('李四' , 180);
console.log(obj1 , obj2);
// 此时,obj1 和 obj2 是两个独立的,对象
// 可以看做是重复的冗余的对象
// 因为 obj1 和 obj2 存储的是不同的对象的内存地址
// 判断结果是 false
console.log( obj1 === obj2 ); // false
// 现在 obj1 和 obj2 是两个完全独立的对象
// 属性,方法都完全相同,只是属性值不同
// 单例模式,解决的问题是:
// 让 obj1 和 obj2 指向的是同一个对象,只是数据数值不同
// 防止,建立过多的,重复冗余的对象
// 可以节约内存的存储空间
// 同一个构造函数,生成的实例化对象,是同一个对象,不会生成重复的冗余的对象,占用不同的存储空间,生成不同的存储地址,占用内存空间
// 单例模式就是 让 obj1 和 obj2 指向的是 同一个内存地址
// obj1 === obj2 结果要是 true
</script>
三.单例模式的核心原理代码
<script>
// 单例模式的核心原理
// 定义一个构造函数
// 定义一个变量
// 判断:如果变量内容是空,证明没有执行过构造函数
// 此时可以执行构造函数
// 如果变量内容不是空,证明已经执行过构造函数
// 此时不再执行构造函数,直接返回变量
// 构造函数
class cerateObj { };
// 定义一个变量,赋值初始值
let obj = null; // let obj;
function isObj() {
// 如果 obj 中 存储的是原始数值,证明没有执行过构造函数,没有对 obj 进行过新的赋值
// if判断里还可以写成 !obj 表示不是原始值即false
if (obj === null) {
// 执行构造函数,生成实例化对象,赋值给 obj 存储
obj = new cerateObj();
}
// 如果没有执行过构造函数
// 会先执行if判断中的程序,执行构造函数,生成实例化对象,obj中存储的是实例化对象的内存地址
// 如果执行过构造函数
// 不会再执行if判断,obj中存储的还是原来的实例化对象的内存地址,返回的也是之前的内存地址
return obj;
}
// 第一次执行,会调用构造函数,生成实例化对象,返回的结果是实例化对象的内存地址
// obj1中存储的是实例化对象的内存地址
let obj1 = isObj();
// 第二次执行,不会在调用构造函数,生成新的实例化对象,返回的结果仍然是之前实例化对象的内存地址
// obj2中存储的仍然是之前的实例化对象的内存地址
// 结果 : obj1,obj2中存储的是相同的内存地址
let obj2 = isObj();
console.log(obj1 , obj2);
console.log(obj1 === obj2); // true
</script>
四.单例模式的执行
<script>
// 单例模式,模拟代码的执行
// 定义一个立即执行函数,将函数的执行结果,赋值给 变量 存储
// utile 中 存储的是 函数的执行结果 也就是 100
// const utils = (function(){return 100})()
// 此时 utils 中存储的是 立即执行函数的 return
// 也就是 return后 function(){} 函数的 内容
const utils = (function(){
// 定义一个构造函数
function CreateObj(){};
// 定义变量
let obj = null;
// 定义判断,写在函数中,这个函数作为返回值
return function(){
if(obj === null){
obj = new CreateObj();
}
return obj;
}
})() ;
console.log(utils);
const obj1 = utils();
const obj2 = utils();
console.log(obj1 === obj2); // true
// 总结: 实际上为了防止全局变量污染,使用了闭包的概念
// 为什么这么写:
// 直接定义的 obj 等,都是全局作用域变量,很容易造成全局变量污染
// 定义成函数的局部作用域变量 / 私有变量 就可以确保不被全局变量污染
//
// 第一层函数是一个立即执行函数 utils 中 存储的就是 立即执行函数的 return 内容 也就是 另一个函数
//
// 执行 utils() 等于就是在 执行 return 的 function函数
// 如果是第一次执行, obj 中存储的是原始的null,会通过构造函数,生成实例化对象
// 之后执行 obj 中 存储的是 实例化对象 , 不是 null , 不会再次执行构造函数,生成新的实例化对象
// 防止重复的实例化对象的生成
</script>