单例模式
正常情况,一个类创建出来的每个对象都是不一样的。
class Carousel{ } var a = new Carousel(); var b = new Carousel(); console.log(a === b); // false
单例模式就是让这两个对象是一样的,也就是说,一个类永远只有一个实例对象
var single = (function(){
class Carousel{
}
var res = undefined;
return function(){
if(!res){
res = new Carousel();
}
return res;
}
})();
var s1 = single();
var s2 = single();
console.log(s1 === s2); // true
组合模式
<script>
// 组合模式:批量启动的启动器
// 轮播图、tab切换、放大镜 - init - 启动方法
class Carousel{
init(){
console.log("轮播图启动了");
}
}
class Tab{
init(){
console.log("tab切换启动了");
}
}
class Enlarge{
init(){
console.log("放大镜启动了");
}
}
// 一种固定的模式,能将这3个效果一起启动起来
class Startor{
// 定义constructor,定义存放所有效果对象的容器
constructor(){
this.container = [];
}
// 添加要启动的那些效果对象
add(...arr){ // 将所有实参都收集为一个数组
this.container = this.container.concat(arr)
}
// 将添加好的效果对象,集体调用他们的init启动
init(){
// 遍历上面的arr,将arr中每个对象都调用init就好了
this.container.forEach(item=>item.init())
}
}
var s = new Startor()
// 添加了个效果
s.add(new Carousel,new Tab,new Enlarge)
s.add(new Carousel,new Tab)
// 全部启动
s.init()
</script>
设计者模式
<script>
// var obj = {}
// console.log(obj);
// // obj.addEventListener('click',fn)
// document.addEventListener('abc',fn)
// function fn(){
// console.log("点击了");
// }
// 观察者模式:
/*
1.给任意对象都可以绑定事件
2.可以绑定任意类型的事件
*/
/*
模拟addEventListener
同类型绑定多次
手动触发
解绑事件
触发时能给事件函数传递参数
*/
// 定义类
class Observer{
// 定义存储事件的容器
constructor(){
this.container = {}
}
// 绑定事件的方法
addEventListener(type, handler){
// 绑定其实就是将事件类型和对应的函数存起来
// console.log(type, handler);
// this.container[type] = [handler]
// 如果容器中,没有这个类型的事件 - 添加类型 - 值是 []
if(!this.container[type]){
this.container[type] = [];
}
// 给数组中添加一个函数
this.container[type].push(handler)
}
// 触发事件的方法
dispatchEvent(type,...brr){
// 通过事件类型type,到容器中找到对应的数组,将数组中的所有函数调用
var arr = this.container[type]
// 遍历
if(!arr){
throw new Error("事件"+type+"没有绑定过!")
}
// 制造一个事件对象
var e = {
type,
clientX:0,
clientY:0,
button:0,
data:brr
}
arr.forEach(item=>item(e))
}
// 解绑
removeEventListener(type, handler){
// 判断是否绑定过这个事件
if(!this.container[type]){
throw new Error("事件"+type+"没有绑定过")
}
// 将handler从容器中删除就好了
// 找handler在数组中的下标
var index = this.container[type].findIndex(item=>item===handler)
// 判断index是否找到
if(index<0){
throw new Error("事件函数不存在")
}
this.container[type].splice(index, 1)
// 如果删的数组中没有函数了 - 空数组了 - 就删除键值对
if(!this.container[type].length){
delete this.container[type]
}
}
// 清除事件对应的所有函数
clear(type){
if(!this.container[type]){
throw new Error("事件"+type+"没有绑定过")
}
delete this.container[type]
}
}
var obj = new Observer()
obj.addEventListener('aa',a1)
function a1(){
console.log("这是aa事件的a1函数");
}
obj.addEventListener('aa',a2)
function a2(){
console.log("这是aa事件的a2函数");
}
obj.addEventListener('bb',b1)
function b1(e){
console.log("这是bb事件的b1函数");
console.log(e);
}
// 解绑
obj.removeEventListener('aa',a1)
obj.removeEventListener('aa',a2)
// obj.removeEventListener('aa',a1)
// obj.clear('aa')
// obj.removeEventListener('cc')
// 触发
// obj.dispatchEvent('aa')
// obj.dispatchEvent('bb',10,20,30)
// obj.dispatchEvent('cc')
console.log(obj);
</script>
数据塌陷
var arr = [1,2,3,4,5]; for(var i=0;i<arr.length;i++){ arr.splice(i,1); } console.log(arr); // [2,4]
解决办法:
1、倒着删除
for(var i=arr.length-1;i>=0;i--){ arr.splice(i,1); }
2、不让变量递增
for(var i=0;i<arr.length;i++){ arr.splice(i,1); i--; }
3、每次都删除最后一个代码
var length = arr.length; for(var i=0;i<length;i++){ arr.splice(0,1); }
数据劫持
<body>
<input type="text" name="keywords" value="12">
</body>
<script>
var obj = {
age:12
}
/******* 数据双向绑定: MVVM *******/
// 当文本框中内容发生改变的时候,希望obj.age也跟着发生改变 - 值一样
// 当对象中的age发生改变的时候,让文本框中的值也跟着发生改变
var keywords = document.querySelector('[name="keywords"]');
keywords.oninput = function(){
obj.age = this.value
}
console.dir(Object);
// 监听obj的age属性被访问的时候
Object.defineProperty(obj, 'age', {
get(){
// console.log(111);
// 访问obj的age属性,就会先调用get方法,访问到的值,是这个get方法返回的值
return keywords.value
},
set(val){
// 当修改obj的age属性的值的时候,就会调用set方法 - 即将要改变的值,会被set方法形参接收到
// console.log(val);
keywords.value = val
}
})
</script>