继承
当一个不具有某个功能或特征的事物,通过某种方式,能够使用另一个具有某个功能或特征的事物的功能或特征的方式叫继承
实例和类的关系是基本的继承
function fn(n){
this.name = n
}
fn.prototype.show = function(){
console.log(this.name)
}
var f = new fn("admin")
f.name
f.show();
类与类之间的继承
改变this指向的继承
- 构造函数继承
- 只能继承构造函数的内容,不能继承原型上的内容
- 多继承
function test01() {
this.test01 = "test01"
}
function test02() {
this.test02 = "test02"
}
function test03() {
this.test03 = "test03"
}
function test() {
this.test = "test";
test01.call(this);
test02.apply(this);
test03.bind(this)();
}
const otest = new test();
console.log(otest);
原型继承 - 原型对象继承 - 拷贝的是prototype
- 只能继承原型对象上的内容,不能继承构造函数的内容
- 注意参数的传递
- 原型对象是一个对象!注意拷贝方式,深拷贝
- 多继承
function test1() {}
test1.prototype.show = function () {
console.log("This is test1's method");
}
function test2() {}
test2.prototype.say = function (msg) {
this.msg = msg;
console.log(this.msg);
}
const t1 = new test1();
const t2 = new test2();
t2.say("test")
console.log(t1)
console.log(t2)
function test() {}
for (let i in test1.prototype) {
test.prototype[i] = test1.prototype[i];
}
for (let i in test2.prototype) {
test.prototype[i] = test2.prototype[i];
}
const test3 = new test();
test3.say("test3")
console.log(test3)
console.log(test3.show())
原型继承 - 原型链继承
- 既能继承构造函数的内容,又能继承原型对象上的内容
- 不方便处理参数
- 不方便实现多继承
- 会多消耗一些性能,多了一层原型链
function Test(msg) {
this.info = msg;
}
Test.prototype.say = function () {
console.log(this.info);
}
const test = new Test("test");
test.say();
console.log(test)
console.log(test.info)
function Test2(msg) {
}
Test2.prototype=new Test("test2");
const test2 = new Test2();
console.log(test2);
console.log(test2.info);
混合继承 - 改变this指向+原型对象继承
- 既能继承构造函数的内容,又能继承原型上的内容
- 原型对象是一个对象!注意拷贝方式,深拷贝
- 多继承
function Test(msg) {
this.msg = msg;
this.show = function () {
console.log(this.msg)
}
}
Test.prototype.say = function () {
console.log("I am test");
}
const test = new Test("test");
test.show()
test.say();
console.log(test);
function Test01(msg) {
Test.call(this, msg);
}
Test01.prototype={
constructor:Test01,
...Test.prototype,
say1:function(){
console.log("I am test1")
}
};
const test01 = new Test01("test1");
console.log(test01);
test01.say()
test01.say1()
ES6提供的class继承
class Test {
constructor(msg) {
this.msg = msg;
this.say();
}
say() {
console.log("I am " + this.msg)
}
}
const test = new Test("test");
console.log(test);
test.say();
class Test01 extends Test{
constructor(msg){
super(msg);
}
}
const test1 = new Test01("test1");
console.log(test1);
test1.say();
继承的应用场景 只要有重复功能出现,就可以将重复功能抽象成公共类,其他原有类都先继承公共类,再做具体的实现
例子-拖拽的继承
html
<div class="box1"></div>
<div class="box2"></div>
css
div {
width: 100px;
height: 100px;
position: absolute;
}
.box1 {
background-color: cornflowerblue;
}
.box2 {
top: 200px;
background-color: darkslateblue;
}
js
class Drag {
constructor(ele) {
this.ele = ele;
this.clientWidth = document.documentElement.clientWidth;
this.clientHeight = document.documentElement.clientHeight;
this.addEvent();
}
addEvent() {
const that = this;
this.ele.addEventListener("mousedown", function (eve) {
that.downE = eve || window.event;
that.down();
});
}
down() {
const that = this;
document.onmousemove = function (eve) {
that.moveE = eve || window.event;
that.move();
}
document.onmouseup = function () {
document.onmousemove = document.onmouseup = null;
}
}
}
class Drag1 extends Drag {
constructor(ele) {
super(ele);
}
move() {
this.ele.style.left = this.moveE.pageX - this.downE.offsetX + "px";
this.ele.style.top = this.moveE.pageY - this.downE.offsetY + "px";
}
}
const box1 = document.querySelector(".box1");
const test1 = new Drag1(box1);
console.log(test1);
class Drag2 extends Drag {
constructor(ele) {
super(ele);
}
move() {
let left = this.moveE.pageX - this.downE.offsetX;
let top = this.moveE.pageY - this.downE.offsetY;
if (left <= 0) {
left = 0;
} else if (left >= this.clientWidth - this.ele.offsetWidth) {
left = this.clientWidth - this.ele.offsetWidth;
}
if (top <= 0) {
top = 0;
} else if (top >= this.clientHeight - this.ele.offsetHeight) {
top = this.clientHeight - this.ele.offsetHeight;
}
this.ele.style.left = left + "px";
this.ele.style.top = top + "px";
}
}
const box2 = document.querySelector(".box2");
const test2 = new Drag2(box2);
console.log(test2);
闭包
是一个定义在一个函数内部的函数
函数嵌套时,利用作用域的嵌套,将原本的局部变量变成私有变量的方式(内部函数调用外部函数的局部变量,那么这个时候,这个局部变量就会变成内部函数的私有变量)
闭包的原理 函数的词法作用域
- 函数的定义作用域:函数被定义的地方
- 函数在执行时,可以使用自身词法作用域中的数据(变量)
闭包的应用
- 循环中的事件处理函数内,使用循环每次执行到的计数器
- 可以给系统功能的不能传参的回调函数传参
- 可以给“事件处理函数”传参
实现调用函数累加的效果
const test = (function fn(){
let a=0;
return function f(){
a++;
console.log(a);
}
})()
console.log(test)
test()
test()
test()
function f2(){
const aa=1;
}
console.log(f2)
用闭包实现点击当前对象的效果
html
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
js
const liList = document.querySelectorAll("li");
for (var i = 0; i < liList.length; i++) {
liList[i].index = i;
liList[i].onclick = function () {
console.log(this.index);
}
}
for (var i = 0; i < liList.length; i++) {
(function (i) {
liList[i].onclick = function () {
console.log(i);
}
})(i);
}
for (var i = 0; i < liList.length; i++) {
liList[i].onclick = (function f2(i) {
return function f1() {
console.log(i);
}
})(i);
}
for(let i=0;i<liList.length;i++){
liList[i].onclick=function(){
console.log(i);
}
}
实现延时器的效果
setTimeout(test("test"), 2000);
function test(msg){
console.log(msg);
}
function test(msg) {
return function test01() {
console.log(msg);
}
}
闭包的特点
- 可以在作用域外部操作作用域内部的变量
- 可以读取函数内部的变量
- 内部和外部沟通的桥梁
- 让这些变量的值,始终保存在内存中,不会在调用结束后被系统回收,避免全局变量命名空间的污染
- 消耗性能
- 闭包有可能会造成内存泄漏(低版本IE8-)
- 小心使用
设计模式
设计模式是一种可以复用的解决方案,是一套被反复使用,多数人知晓的,经过分类的,代码设计经验的总结
1. 单例模式
- 单个实例
- 单例模式 的 弹出框
- 通过手动模拟 new 的原理,实现单例模式
2. 观察者模式(发布订阅者)
- 发布:被观察者,主题对象
- 订阅:观察者
- 一个主题对象发布或更新信息,多个订阅者接收信息,并根据信息作出不同的功能处理
- 可以实现广播通信,一对多关系,耦合低
3. 适配器模式
- 适配器
- 假如现有数据A,和功能B,功能B只能接受B类型的数据,可是现有的数据类型是A
- 将数据A改成B类型的数据 x
- 将功能B接受的数据类型改成A类型 x
- 此时需要一个适配器,将数据A进行一层包装,让数据A看起来像,B类型的数据
4. 代理模式
- 代理
- 系统功能A在调用系统功能B的过程中,传输了数据,我们需要记录数据,或改写数据,或拦截数据
- 先断开执行,获取系统功能B的执行权限,编写代理程序执行功能B,让功能A调用代理程序,将原有的数据,发给代理程序,代理程序将数据发给功能B
5. 策略模式
- 策略,计划
- 根据程序执行过程中产生的不同的状态或信息,决定后续的功能执行
- 利用不同的功能接口(方法)决定执行不同的功能
6. 组合模式
- 按照一定的组织关系,将多个对象进行组合
- 组合模式就是为动态的html而生的
- 组合模式为了能够实现批量操作,节省操作过程,使用了递归思想,所以消耗比较多的性能
- 利用组合器将对象组合起来
- 枝对象:只有具有子对象,无论层级在哪,都是枝对象
- 叶对象:只有不具有子对象,无论层级在哪吗,都是叶对象
7. 抽象工厂模式
- 抽象
- 工厂
- 在工厂模式的继承之上,再次对同一个实例的相同属性进行抽象,抽象成一个公共对象,在做具体的工厂模式的创建
8. MVC模式
- M:model:模型层,只负责数据的管理
- V:view:视图层,只负责将来数据展示的视图的管理
- C:control:控制器层,负责接收用户的指令,根据指令,选择不同的模型,将模型中的数据,加给不同的视图渲染
- 工作流程:
- 控制器接收到指令后,根据指令读取指定的模型,拿到数据
- 控制器再根据指令获取指定的视图
- 将第一步读取到的数据,传给获取到的视图
- 由视图负责将接收到的数据,渲染
|