类和原型
-
类
- 类(Class)是对某种类型的对象定义变量和方法的原型。
- 它表示对现实生活中一类具有共同特征的事物的抽象,是面向对象编程的基础。
- 类是对象的抽象
-
对象
- 对象是类的实例化
-
ES5的面向对象
- 没有类的概念
- 函数是对象,可以写方法,用函数来模拟类
-
原型
-
–proto–是函数基于对象的原理
-
prototype,是函数独有的属性——原型
- 包含constructor和–proto–
- constructor与当前函数相同,所以当前函数可以作为构造函数使用
- Fn.prototype是当前构造函数所属类下面的实例化方法
- 包含constructor和–proto–
-
new Fn() 表示实例化构造函数,实例化类
-
实例化时会将构造函数的prototype对象下的所有方法和属性添加在实例化对象的原型链下
var f=new Fn(); console.log(f);
-
类的原型等于实例化对象的原型链
console.log(Box.prototype===b.__proto__);//true
-
-
-
创建类
function Box(){ }
-
给类的原型上添加方法
Box.prototype.run=function(){ } Box.prototype.play=function(){ }
-
给类的构造函数上添加方法
Box.run=function(){ }
-
一类所有的实例化对象增加方法
var div0=document.querySelector(".div0"); var div1=document.querySelector(".div1"); HTMLDivElement.prototype.setBg=function(){ this.style.width="50px"; this.style.height="50px"; this.style.border="1px solid #000000"; this.style.backgroundColor="red"; } div0.setBg(); div1.setBg();
-
给某一类所有的实例化对象增加set/get属性
- 以拖拽为例
Object.defineProperties(HTMLDivElement.prototype,{ _drag:{ writable:true, value:false }, width:{ set:function(_v){ this.style.width=_v.toString().indexOf("px")>-1?_v:_v+"px"; }, get:function(){ return parseFloat(getComputedStyle(this).width); } }, height:{ set:function(_v){ this.style.height=_v.toString().indexOf("px")>-1?_v:_v+"px"; }, get:function(){ return parseFloat(getComputedStyle(this).height); } }, bgColor:{ set:function(_v){ this.style.backgroundColor=(typeof _v === "string")?_v:_v.toString(16).padStart(6,"0"); }, get:function(){ return parseFloat(getComputedStyle(this).backgroundColor); } }, drag:{ set:function(_v){ this._drag=_v; if(_v){ this.style.position="absolute"; return this.addEventListener("mousedown",this.dragHandler); } this.removeEventListener("mousedown",this.dragHandler); }, get:function(){ return this._drag; } }, dragHandler:{ value:function(e){ if(e.type==="mousedown"){ e.preventDefault(); document.target=this; document.offset={x:e.offsetX,y:e.offsetY}; document.addEventListener("mousemove",this.dragHandler) document.addEventListener("mouseup",this.dragHandler) }else if(e.type==="mousemove"){ this.target.style.left=e.clientX-this.offset.x+"px"; this.target.style.top=e.clientY-this.offset.y+"px"; }else if(e.type==="mouseup"){ document.removeEventListener("mousemove",this.target.dragHandler) document.removeEventListener("mouseup",this.target.dragHandler) } } } })
-
给数组增加方法
Array.prototype.some1=function(fn){ // this是调用该方法的数组 for(var i=0;i<this.length;i++){ if(fn(this[i],i,this)) return true; } return false; } var arr=[2,4,6]; var b=arr.some1(function(item,index,arr){ return item%2===1; }) console.log(b);
-
将HTMLCollection转换成数组
var arr=Array.prototype.slice.call(document.querySelectorAll("div")); console.log(arr); var arr=Array.prototype.concat.apply([],document.querySelectorAll("div")); console.log(arr);
-
柯里化
Function.prototype.currying=function(){ var arr=[]; var self=this; return function(){ if(arguments.length>0){ arr=arr.concat(Array.from(arguments)); return arguments.callee; } return self.apply(null,arr); } } function getSum(){ return Array.from(arguments).reduce((value,item)=>value+=item); }
-
反柯里化
- 延迟传参,增加适用范围
Function.prototype.unCurrying=function(){ var self=this; return function(){ return Function.prototype.call.apply(self,arguments); //arguments=[[1,2,3,4],-4] //push.call.apply(self,arguments)=this.push.call([1,2,3,4],-4)=[1,2,3,4].push(-4) } } var push=Array.prototype.push.unCurrying(); function getSum(){ push(arguments,-4); console.log(arguments); } getSum(1,2,3,4);
- 解决调用uncurrying的函数不确定的问题
- call.apply()
- apply.apply()
-
用原型封装事件解决兼容性问题
var div=document.querySelector("div"); EventTarget.prototype.on=function(type,handler,bubbles){ try{ this.addEventListener(type,handler,bubbles); }catch(e){ this.attachqEvent("on"+type,handler); } } div.on("click",clickhandler); function clickhandler(e){ console.log("aa"); }
继承
-
ES5的继承
function Box(){ } Box.prototype.a=10; function Ball(){ } Ball.prototype=new Box(); Object.defineProperty(Ball.prototype,"constructor",{ value:Ball }) var c=new Ball(); console.log(c);
-
在new Box 时已经执行过一次Box,所以无法对被继承的类进行传参
-
组合式继承
- 原型链继承
- 冒充继承
function Box(v){ this.v=v; console.log(v); } Box.prototype.run=function(){ } Box.prototype.a=10; function Ball(v){ Box.call(this,v);//冒充继承 } Ball.prototype=new Box();//原型链继承 Object.defineProperty(Ball.prototype,"constructor",{ value:Ball }) var c=new Ball(3); console.log(c);
- Box会执行两次,new Box()时会执行一次,call时会执行一次
-
寄生式继承
function Box(v){ this.v=v; console.log(v); } Box.prototype.run=function(){ } Box.prototype.a=10; function F(){ } F.prototype=Box.prototype; function Ball(v){ Box.call(this,v); } Ball.prototype=new F(); Object.defineProperty(Ball.prototype,"constructor",{ value:Ball }) var c=new Ball(3); console.log(c);
- new Box()时始终都会执行一次Box(),为了不执行Box(),重新定义了一个函数F()将Box的原型赋值给F的原型,所以F的原型与F的原型的引用地址相同,让Ball继承F类,因为F没有函数体,所以什么都不会执行,就不会多执行一次Box的函数体
- 寄生在F()上
-
封装寄生式继承
Function.prototype.extend=function(superClass){ function F(){}; F.prototype=superClass.prototype; var proto=this.prototype; this.prototype=new F(); var names=Object.getOwnPropertyNames(proto); for(var i=0;i<names.length;i++){ var desc=Object.getOwnPropertyDescriptor(proto,names[i]); Object.defineProperty(this.prototype,names[i],desc); } Object.defineProperty(this.prototype,"constructor",{ value:this }); this.prototype.superClass=superClass; if(superClass.prototype.constructor!==superClass){ Object.defineProperty(superClass.prototype,"constructor",{ value:superClass, }); } } function Box(v){ this.v=v; console.log(v); } Box.prototype.run=function(){ console.log("a"); } Box.prototype.a=10; function Ball(v){ this.superClass.apply(this,arguments); } Ball.extend(Box); Ball.prototype.run=function(){ this.superClass.prototype.run.apply(this,arguments); console.log("b"); } var c=new Ball(5); console.log(c); c.run()
-
设计模式
- 共23种模式,分为3大类
- 创建型模式
- 单例模式
- 抽象工厂模式
- 建造者模式
- 工厂模式
- 原型模式
- 结构型模式
- 适配器模式
- 桥接模式
- 装饰模式
- 组合模式
- 外观模式
- 享元模式
- 代理模式
- 行为型模式
- 模板方法模式
- 命令模式
- 迭代器模式
- 观察者模式
- 中介者模式
- 备忘录模式
- 解释器模式
- 状态模式
- 策略模式
- 职责链模式
- 访问者模式
- 创建型模式
- 工厂模式
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类
- 根据传入的不同数据,创建不同的类,
- 单例模式
- 最后只创造唯一的对象
- 优点
- 可以用来划分命名空间,减少全局变量的数量
- 使用单例模式可以是代码组织的更为一致,使代码容易阅读和维护
- 可以被实例化,且实例化一次
- Proxy对象--------代理模式
- 把对一个对象的访问交给另一个代理对象来操作
- 观察者模式
- 一个被称为被观察者的对象,维护一组被称为观察者的对象,这些对象依赖于被观察者,被观察者自动将自身的状态的任何变化通知给他们。