let Tool = {
getISODate:function(){},
getUTCDate:function(){}
}
Es6
class Tool = {
constructor(name){
this.name=name
}
}
访问:Tool.func1()
let Tool = (function(){
let _instance = null
function init(){
let now = new Date()
this. getISODate:function(){
return now.toISOString()
}
this. getUTCDate:function(){
return now.toUTCString()
}
}
return function(){
if(!_instance){
_instance=new init()
}
return _instance
}
})
Es6
class Tool {
constructor(name){
if(!Tool._instance){
this.name=name
Tool._instance=this
}
return Tool._instance
}
}
var modle = (function(){
var modle1={}
var modle2={}
return { modle1: modle1, modle2: modle2}
})()
class Login {
constructor(){
this.init()
}
// 初始化init
init(){
// 创建dom
let mask = document.createElement('div')
mask.classList.add('mask-layer')
mask.innerHTML='<div class="login-wrapper">\n' +
' <div class="login-title">\n' +
' <div class="title-text">登录框</div>\n' +
' <div class="close-btn">×</div>\n' +
' </div>\n' +
' <div class="username-input user-input">\n' +
' <span class="login-text">用户名:</span>\n' +
' <input type="text">\n' +
' </div>\n' +
' <div class="pwd-input user-input">\n' +
' <span class="login-text">密码:</span>\n' +
' <input type="password">\n' +
' </div>\n' +
' <div class="btn-wrapper">\n' +
' <button class="confrim-btn">确定</button>\n' +
' <button class="clear-btn">清空</button>\n' +
' </div>\n' +
' </div>'
//插入元素
document.body.insertBefore(mask,document.body.childNodes[0])
//注册关闭弹框
Login.getCloseMask()
}
// 获取元素
static getLoginDom(cls){
return document.querySelector('cls')
}
// 关闭弹窗
static getCloseMask(){
this.getLoginDom('.closeBtn').addEventListener('click',()=>{
this.getLoginDom('mask-layer').style="display:none"
})
}
// 获取实例
static getInstance(){
if(!this.instance){
this.instance = new Login()
}else{
this.getLoginDom('mask-layer').removeAttribute('style')
}
return this.instance
}
}
// 点击弹出
Login.getInstance();
et Factory = function (role) {
function User(opt) {
this.name=opt.name
this.pages = opt.pages
}
switch (role) {
case 'admin':
return new User({name:'admin',pages:['首页','配置页']});
break;
case 'user':
return new User({name:'user',pages:['首页']});
break;
default:
throw new Error('参数错误');
}
}
let Factory = function (role) {
if(this instanceof Factory){
var s = new this[role]()
return s
}else{
return new Factory(role)
}
}
Factory.prototype={
admin:function () {
this.name='admin'
this.pages=['首页','配置页']
},
user:function () {
this.name='user'
this.pages=['首页']
}
}
ar Factory = function (supType,superType) {
if(typeof Factory.superType==='function'){
function F() {}
// 继承父类
F.prototype = new Factory[superType]()
supType.constructor = supType
supType.prototype = new F()
}else{
throw new Error('未创建该抽象类');
}
}
Factory.QQType =function () {
this.type=' QQType '
}
Factory.QQType.prototype = {
getName : function () {
return new Error('抽象方法不能调用');
}
}
//普通qq用户子类
function QQType(name) {
this.name = name;
this.pages = ['首页', '配置页']
}
//抽象工厂实现qq类的继承
Factory(QQType, 'QQType');
//子类中重写抽象方法
QQType.prototype.getName = function() {
return this.name;
}
//实例化qq用户
let QQTypea = new QQType('微信小李');
console.log(QQTypea.getName(), QQTypea.type); //微信小李 QQType
let QQTypeb = new QQType('微信小王');
console.log(QQTypeb.getName(), QQTypeb.type); //微信小王 QQType
*简单策略模式*/
//年终奖计算
const Bouns = {
S(salary){
return salary*3
},
A(salary){
return salary*2
},
B(salary){
return salary*1
},
C(salary){
return salary*0.5
}
}
// 冻结不改
Object.freeze(Bouns)
// 环境类Context
// @params {String} type 绩效等级
// @params {Number} salary 工资
const calculateBouns=function(type,salary){
return Bouns[type](salary)
}
/*策略模式--表单验证*/
//定义固定算法
const Verify = {
// 是否为空
isEmpty(value,errorMsg){
if(value===''){
return errorMsg
}
},
minLength(value,errorMsg,length){
if(value.length<length){
return errorMsg
}
},
// 手机号验证
formatPhone(value,errorMsg){
if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg
}
},
}
Object.freeze(Verify)
/*
* 模仿vue表单验证实现
* */
// 定义Validator类
var Validator = function () {
this.cache=[] // 保存校验规则
}
Validator.prototype.add=function (dom,rules) {
var self = this
for(var i=0,rule;rule=rules[i++];){
(function (rule) {
let verifyArr = rule.split(':')
let errorMsg = rule.errorMsg
self.cache.push(function () {
let verify = verifyArr.shift()
verifyArr.unshift(dom.value)
verifyArr.push(errorMsg)
return verifies[verify].apply(dom,verifyArr)
})
})(rule)
}
}
Validator.prototype.start=function () {
for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {
var msg = validateFunc(); // 开始效验 并取得效验后的返回信息
if(msg) {
return msg;
}
}
}
// 代码调用
var registerForm = document.getElementById('registerForm');
var validateFunc = function () {
var validator = new Validator()
validator.add(registerForm.userName,[
{Verify: 'isNotEmpty',errorMsg:'用户名不能为空'},
{Verify: 'minLength:6',errorMsg:'用户名长度不能小于6位'}
])
var errorMsg = validator.start()
return errorMsg
}
// 点击确定提交
registerForm.onsubmit = function(){
var errorMsg = validateFunc();
if(errorMsg){
alert(errorMsg);
return false;
}
}
/*保护模式*/
function sendMsg(msg){
console.log(msg)
}
function proxySendMsg(msg){
if(!msg) {
console.log('deny')
return
}
// 过滤
msg = (''+msg).replace('菜鸟','')
sendMsg(msg)
}
/*es6 proxy 实现成绩过滤*/
const scoreList={
zs:'58',
ls:'89'
}
const scoreProxy = new Proxy(scoreList,{
get:function (scoreList,name) {
if(scoreList[name]>60){
console.log('输出成绩')
return scoreList[name]
}else{
console.log('不及格成绩不能输出')
}
}
})
scoreProxy['zs'] //不及格成绩不能输出
scoreProxy['ls'] //输出成绩 89
/*不使用模式,耦合性太高*/
var myImageA = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
var img = new Image();
img.onload = function(){
imgNode.src = this.src;
};
return {
setSrc: function(src) {
imgNode.src = "http://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif";
img.src = src;
}
}
})();
// 调用方式
myImageA.setSrc("https://www.baidu.com/img/bd_logo1.png");
/*使用虚拟模式*/
/*实现图片懒加载*/
var myImage = (function () {
var imgNode = document.createElement('img')
document.body.appendChild(imgNode)
return{
setSrc:function (url) {
imgNode.src = url
}
}
})()
var proxyImage = (function () {
var img = new Image()
img.onload=function () {
myImage.setSrc(this.src)
}
return {
setSrc:function (src) {
myImage.setSrc('http://seopic.699pic.com/photo/40007/8839.jpg_wh1200.jpg');
img.src = src;
}
}
})()
proxyImage.setSrc('http://seopic.699pic.com/photo/40006/7735.jpg_wh1200.jpg')
/*缓存模式*/
var mult = function () {
var a=1;
for(var i=0;i<arguments.length;i++){
a=a*arguments[i]
}
return a
}
var plus = function () {
var a=0;
for(var i=0;i<arguments.length;i++){
a=a+=arguments[i]
}
return a
}
// 代理缓存
var proxyFun=function (fn) {
var cache = {} // 缓存对象
return function () {
var args = Array.prototype.join.call(arguments,',')
if(args in cache){
return cache[args] // 使用缓存代理
}
return cache[args]=fn.apply(this,arguments)
}
}
var proxyMult=proxyFun(mult)
proxyMult(1,2,3,4) // 24
proxyMult(1,2,3,4) // 缓存中24
/*
*发布订阅模式
*/
/*经典发布订阅模式*/
//订阅
document.body.addEventListener('click',function () {
console.log('click1')
})
//发布
document.body.click() // click1
/*自定义发布订阅*/
class Event{
constructor(){
this._cache=[] // 存储事件数据结构
}
// 订阅
on (type,callback){
let fns = (this._cache[type]=this._cache[type]||[])
if(fns.indexOf(callback)!==-1){
fns.push(callback)
}
return this
}
// 发布 emit
trigger(type,data){
let fns = this._cache[type]
if(Array.isArray(fns)){
fns.forEach((fn)=>{
fn(data)
})
}
return this
}
// 取消订阅
off(type,callback){
let fns = this._cache[type]
if(Array.isArray(fns)){
if(callback){
let index = fns.indexOf(callback)
if(index!=-1){
fns.splice(index,1)
}
}else{
fns.length = 0
}
}
return this
}
}
假如开发一个商城,网站有header nav 消息列表 购物车 强耦合写法,都是登陆模块中的
Login.success(function(data){
header.setAvatar(data.avatar)
nav.setAvatar(data.avatar)
message.refresh()
cart.refresh()
// 忽然增加地址刷新
address.refresh()
})
采用发布订阅,解除耦合度
/*应用场景--互联网商城登陆模块*/
$.ajax('http:xxx',function (data) {
login.trigger('loginsuccess',data)
})
// 各模块监听登陆
var header=(function () {
login.on('loginsuccess',function (data) {
header.setAvatar(data.avatar)
})
return{
setAvatar:function (avatar) {
console.log('设置头部头像成功')
}
}
})
var cart=(function () {
login.on('loginsuccess',function (data) {
cart.refresh(data)
})
return{
refresh:function (data) {
console.log('刷新成功')
}
}
})
// 忽然新增地址刷新
var address = (function (data) {
login.on('loginsuccess',function (data) {
address.refresh(data)
})
return {
refresh:function (data) {
console.log('刷新地址成功')
}
}
})
动态给对象增加职责的方式,称为装饰者模式。在不改变对象自身的基础上,在程序运行期间给对象动态添加职责。和继承相比,装饰者模式更加便捷。装饰者,也称为包装器,一个对象嵌套在另一个对象中,形成包装链。(出现原因,我们不想维护原有对象,但是有需要在原有对象基础上添加功能。)
/*
* 装饰函数
* */
var a = function () {
alert(1)
}
//需要增加alert(2)
//在原函数基础上写
var a = function () {
alert(1)
alert(2)
}
// 使用装饰函数
var a = function () {
alert(1)
}
var _a = a
a=function () {
_a()
alert(2)
}
问题:需要维护很多中间变量,可能会导致中间变量越来越多。
/*污染原型写法*/
Function.prototype.before=function (beforeFn) {
var _self = this // 保存原函数引用
return function () {
beforeFn.apply(this,arguments)
return _self.apply(this,arguments)
}
}
Function.prototype.after=function (afterFn) {
var _self = this // 保存原函数引用
return function () {
afterFn.apply(this,arguments)
return _self.apply(this,arguments)
}
}
window.onload(){
alert(1)
}
window.onload=(window.onload||function () {}).after(function () {
alert(2)
}).after(function () {
alert(3)
})
/*不污染原型变通写法*/
var before = function (fn,beforeFn) {
return function () {
beforeFn.apply(this,arguments)
return fn.apply(this,arguments)
}
}
var a = before(
function () {alert(1)},
function () {alert(2)}
)
a = before(a,function () {
alert(3)
})
a()//1,2,3
1预防CSRF攻击,在http 中添加token
/*预防CSRF攻击,在http中加入Token参数*/
/*一般写法*/
var getToken=function(){
return "token"
}
var ajax = function (type,url,param) {
param = param||{}
param.token = getToken()
}
/*AOP写法*/
var ajax = function (type,url,param) {
console.log(param)
}
ajax=ajax.before(function (type,url,param) {
param.token = getToken()
})
ajax('get','http:xxx',{name:json})
// {name:json,token:"token"}
2使用表单校验插件
/*表单校验*/
var validata=function () {
if(username.value==''){
return false
}
}
var submit=function () {
var param = {
username:username.value
}
$.ajax('http:xxx',param)
}
// 定义装饰函数
Function.prototype.before=function(beforefn){
var _self = this
return function () {
if(beforefn.apply(this,arguments)===false){
return
}
return _self.apply(this,arguments)
}
}
// 调用装饰函数
submit=submit.before(validata)
submitBtn.onclick=function () {
submit()
}
/*
* 适配器模式
* */
/*简单例子--调用谷歌百度地图*/
var gooleMap={
show:function () {
console.log('调用谷歌地图')
}
}
var baiduMap={
baiduShow:function () {
console.log('调用百度地图')
}
}
var renderMap=function (map) {
if(map.show instanceof Function){
map.show()
}
}
renderMap(gooleMap)//调用谷歌地图
renderMap(baiduMap)//没有show方法
// 百度地图适配器
var baiduMapAdpter={
show:function f() {
return baiduMap.baiduShow()
}
}
renderMap(gooleMap)//调用谷歌地图
renderMap(baiduMapAdpter)//调用百度地图
/*应用场景-常见数据结构之改变*/
var getZJCity = function () {
var zjCity = [
{name:'hangzhou',id:12},
{name:'ningbo',id:13},
]
return zjCity
}
var render = function (fn) {
document.write(JSON.stringify(fn()))
}
render(getZJCity)
// 忽然要采用新的数据结构
var zjCity={
hangzhou:12,
ningbo:13,
}
// 添加适配器(将老数据转为新数据)
getZJCityAdapter=function (oldfn) {
let address = {}
oldAddress = oldfn()
for(var i=0,c;c=oldAddress[i++];){
address[c.name] = c.id
}
return function () {
return address
}
}
render(getZJCityAdapter(getZJCity))