目录
1 原型链图
instanceof
该关键字用于判定某一个对象是否是某一个构造函数的实例, 原理是:在对象的原型链上查找构造函数的原型
hasOwnProperty:
该方法检测某个对象身上是否包含了指定的属性
内置构造函数
String Number Boolean 是该类型的对应包装类型
Object Array Function RegExp Error Date
函数名.length 得到的是 形参的个数
arguments.length 得到的是 实参的个数
2 继承
1 构造函数式继承 在子构造函数中 调用父构造函数 可以继承父元素的实例属性,不能继承父原型上的属性方法
function Student(name, age, sex, cls) {
// 构造函数式继承,两种写法
// Teacher.apply(this, [name, age, sex])
Teacher.call(this, name, age, sex);
// 重写属性
this.cls = cls;
}
2 类式继承:(原型式继承)将子原型对象指向父实例对象,缺点是:不能继承父实例属性;多执行实例化一次父构造函数;子原型对象被污染;constructor指向父构造函数
function Teacher(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, cls) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 类式继承
Student.prototype = new Teacher();
3 组合式继承 1 和 2 结合起来
function Teacher(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, cls) {
// 构造函数式继承
Teacher.call(this, name, age, sex);
// 添加属性
this.cls = cls;
}
//类式继承
Student.prototype = new Teacher();
4 寄生式继承 定义寄生类 1:将寄生类的原型指向父原型 2将子原型指向寄生类实例 3更改constructor
function inherite(child, parent) {
// 定义寄生类
function F() {
// 纠正构造函数指向问题
this.constructor = child;
}
// 让寄生类的原型式父类的原型
F.prototype = parent.prototype;
// 让子类的原型指向寄生类的原型对象
// 通过实例化寄生类,代替了实例化父类
child.prototype = new F();
// 纠正子类的原型
// child.prototype.constructor = child;
// 返回子类
return child;
}
5 寄生式组合继承 4 和 1结合起来
/***
* 组合式继承
* 综合运用构造函数式继承以及寄生式继承
* 完美的解决了对父类的构造函数以及原型的复用问题。
* 是目前为止最完美的继承方式了
* ***/
// 学生类
function Student(name, age, sex, cls) {
// 构造函数式
Teacher.call(this, name, age, sex);
// 重写属性
this.cls = cls;
}
// 子类寄生父类
inherite(Student, Teacher);
3 设计模式
1 单例模式
定义:是能被实例化一次的类或者对象(只能存在一个)
作用:管理命名空间,管理数据,方法的存储
应用:一些代码库中命名空间就是通过单例模式实现的
// 单例模式
var single = (function() {
function Demo1(name, age) {
this.name = name;
this.age = age;
}
return function() {
var instance = new Demo1('小花', 18);
return instance;
}
})();
//不管输不输出 当函数声明的时候 instance已经被赋值了
console.log(single());
2 惰性单例
定义:延迟单例类的实例化时间
作用:如果单例类实例化开销很大,页面加载时候,有很多业务逻辑需要执行,并不需要这个单例类,此时我们可以推迟这个单例类的实例化时间
//惰性单例
var Single1 = (function() {
function Demo2(name, age) {
this.name = name;
this.age = age;
}
var instance;
return function(name, age) {
if (instance) {
return instance;
} else {
return instance = new Demo2(name, age);;
}
}
})();
var ss = Single1('大明', 20);
3 静态变量
定义: 一旦被定义,只能被读取,无法被修改
我们实现的静态变量有个局限性:只能定义值类型的数据
// 定义闭包
var Conf = (function() {
// 定义对象
var obj = {
msg: 'hello',
num: 100,
title: 'nihao',
size: {
width: 100,
height: 200
}
}
// 定义接口函数
// 只定义取值函数 不要定义赋值函数
return function(key) {
return obj[key];
}
})()
// 查看数据
console.log(Conf('msg'));
console.log(Conf('num'));
// 改变内部应用类型数据值
Conf('size').width = 1000;
// 访问引用类型
console.log(Conf('size').width);
4 适配器模式
// 适配代码库 将代码改为jquery实现
var Ickt = {
bindEvent: function(dom, type, fn) {
$(dom).on(type, fn);
},
css: function(dom, key, value) {
$(dom).css(key, value);
},
getStyle: function(dom, key) {
return $(dom).css(key);
}
}
// 绑定事件
Ickt.bindEvent(btn, 'click', function() {
// 改变box的样式
Ickt.css(box, 'color', 'red');
// 切换显隐
Ickt.css(box, 'display', Ickt.getStyle(box, 'display') === 'none' ? 'block' : 'none');
})
5 观察者模式
定义:观察者模式,又叫发布订阅者模式,又叫消息系统,又叫消息机制,又叫自定义事件,解决主体与观察者之间的耦合问题。
on 用来注册消息 第一个参数表示消息的名称,第二个参数表示回调函数
trigger 用来触发消息,第一个参数表示消息的名,从第二个参数开始表示传递数据
off 用来移除消息的方法。
once 单次订阅方法。
var Observer = (function() {
_data = {};//存储数据对象
return {
on: function(name, fn) {
_data[name] ? _data[name].push(fn) : _data[name] = [fn];
},
trigger: function(name) {
var arg = Array.prototype.slice.call(arguments, 1);
if (_data[name]) {
for (var i = 0; i < _data[name].length; i++) {
_data[name][i](arg);
}
}
},
off: function(name, fn) {
if (!name) {
_data = {};
} else if (!fn) {
_data[name] = [];
} else {
for (var i = 0; i < _data[name].length; i++) {
if (_data[name][i] === fn) {
_data[name].splice(i, 1);
}
}
}
},
once: function(name, fn) {
function callback(arg) {
Observer.off(name, callback);
fn.apply(null, arg);
}
Observer.on(name, callback);
}
}
})();
7 组合模式 看笔记49
8 策略模式
定义:将一组算法封装起来,使其彼此之间可以相互替换,封装的算法具有独立性,不会随着客户端的变换而变化。行为型设计模式。
// 封装策略对象
var strategy = (function() {
// 存储数据的对象
var _method = {
username: function(val) {
if (!/^\w{4,12}$/.test(val)) {
return '用户名是4-12位数字字母下划线组合';
}
return '恭喜,用户名可以使用';
},
// 验证密码的策略
password: function(val) {
// 判断
if (!/^\w{4,8}$/.test(val)) {
return '密码是4-8位数字字母下划线组合'
}
return '恭喜,该密码可以使用';
}
};
// 返回接口对象
return {
// 使用策略方法
use: function(name, str) {
return _method[name](str)
},
// 添加策略方法
add: function(name, fn) {
_method[name] = fn;
}
}
})()
// 添加另一种用户名验证
strategy.add('checkNickName', function(val) {
if (!/^[a-zA-Z][0-9]{4,8}$/.test(val)) {
return '用户名是以字母开头后面是4-8位数字';
}
return '恭喜, 该用户名可以使用';
})
// 使用
var result = strategy.use('checkNickName', 'w123456');
console.log(333, result);
// 验证密码
var result = strategy.use('password', wwwwwwwwwww);
console.log(result);
9 命令模式
定义:将请求与实现解耦并封装成独立的对象,从而使不同的请求对客户端实现的参数化。
行为型设计模式,将执行的命令封装,解决命令的发起者与命令的执行者之间的耦合
例子:
// 获取画布
var canvas = document.getElementById('myCanvas');
// 获取画笔
var ctx = canvas.getContext('2d');
// 定义命令对象
var commond = (function() {
// 定义存储数据对象
var _C = {
// 绘制描边圆
strokeCirle: function(x, y, r, color) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.closePath();
ctx.strokeStyle = color;
ctx.stroke();
},
// 填充圆
fillCirle: function(x, y, r, color) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
},
// 绘制矩形
drawRect: function(x, y, w, h, color) {
// 判断是否传递color
if (color) {
ctx.fillStyle = color;
}
ctx.fillRect(x, y, w, h);
}
};
// 返回接口对象
return {
exec: function(name) {
// 获取剩余参数语法
var arg = Array.prototype.slice.call(arguments, 1);
// 执行方法
_C[name] && _C[name].apply(_C, arg);
}
}
})()
// 绘制描边圆
commond.exec('strokeCirle', 200, 200, 100, 'orange');
// 绘制填充圆
commond.exec('fillCirle', 200, 200, 100, 'orange');
// 绘制矩形
commond.exec('drawRect', 300, 300, 100, 100, 'blue');
10 迭代器模式
定义:在不暴露对象内部结构的同时,可以顺序的访问聚合对象内部的元素。
行为型设计模式
// 封装迭代器类
function Iterator(select) {
// 接收数据
this.select = select;
// 获取元素
this.elements = document.querySelectorAll(select);
// 索引值
this.index = 0;
}
// 添加方法
Iterator.prototype = {
// 补回constructor
constructor: Iterator,
// 获取当前元素
getCurrentElement: function() {
return this.elements[this.index];
},
// 获取上一个元素
prev: function() {
// 改变索引值
this.index--;
// 做边界限制
if (this.index < 0) {
throw new Error('前面没有元素了');
}
// 返回元素
return this.getCurrentElement();
},
// 获取下一个元素
next: function() {
// 改变索引值
this.index++;
// 做判断
if (this.index > this.elements.length - 1) {
throw new Error('已经是最后一个了')
}
// 返回元素
return this.getCurrentElement();
},
// 获取第一个元素的方法
first: function() {
return this.getCurrentElement();
},
// 获取最后一个元素的方法
last: function() {
// 改变索引值
this.index = this.elements.length - 1;
// 获取元素
return this.getCurrentElement();
}
}
var iterator = new Iterator('li');
var li1 = iterator.getCurrentElement();
var li2 = iterator.first()
var li3 = iterator.next();
var li4 = iterator.last()
11 委托模式 请求委托:
多个对象接收并处理同一请求,他们将请求委托给另一个对象统一处理请求。
解决请求与委托者之间的耦合
被委托者接收到请求分发给委托者去处理
// 数据分发
$.get('/data/all.json', function(res) {
tools.renderHeader(res.data.header);
tools.renderBody(res.data.body);
tools.renderFooter(res.data.footer);
})
// 封装一个工具方法
var tools = {
renderHeader: function(html) {
$('#header').html(html);
},
renderBody: function(html) {
$('#body').html(html);
},
renderFooter: function(html) {
$('#footer').html(html);
}
}
12 事件委托
事件委托:将所有元素的事件绑定委托给同一个父元素,根据事件冒泡捕获机制,可以在父元素绑定事件中获取的触发事件的这个元素,根据这个元素具有的某类特征(例如元素名称,元素id,元素类,元素属性等等)做不同的处理,实现事件从父元素到被委托的元素传递。其特点:
减少事件数量
预言未来元素,新增的元素也可以绑定事件
避免内存外泄:通常创建一个对象需要占用一些内存,这类占用是有意义的;有时候一些已 经被删除数据还占用着内存,这部分内存对我们来说是没用的,就是外泄内存
//list是父元素 里面有p和h1,给他们注册点击时 背景色改变事件
list.onclick = function(e) {
// 获取触发事件的元素
var target = e.target;
// 判断
if (target.tagName === 'P') {
// 如果是p改变背景颜色为orange
target.style.backgroundColor = 'orange';
} else if (target.tagName === 'H1') {
// 如果是h1改变背景颜色为yellowgreen
target.style.backgroundColor = 'yellowgreen';
}
}
jQuery中的事件委托
on方法和delegate方法都可以实现事件委托,当事件触发的时候 父元素身上的事件不会执行 而是指定的元素执行,也不需要通过事件对象判断是否是触发事件的元素 这一点明显优于Javascript
// jquery中的事件委托 通过on方法
$('#list').on('click', 'li', function() {
console.log(this);
})
// 使用更具有语义化的方法 delegate
$('#list').delegate('li', 'click', function() {
console.log(this);
})