类和原型

类与原型的结合使用

function Fn(){}

Fn.run=function(){} //这种写法与ES6中的静态方法一样
Fn.prototype.play=function(){} //这种写法就是正常的执行方法

实例化时会将构造函数的prototype对象下的所有方法和属性添加在实例化对象的原型链中

类的原型等于实例化对象的原型链

定义一个父类,并利用原型设置类中的方法,同时将被覆盖的构造函数重新设定出来

    function Box(){

        }
    Box.prototype={
        a:1,
        run:function(){


        },
        play:function(){

        }
    }
    Object.defineProperty(Box.prototype,"constructor",{
        value:Box
    })
var b=new Box();
console.log(Box.prototype===b.__proto__);   //true

类的原型(Box.prototype)与实例化的对象的原型链(b.proto)相同。
所以:

在任何类的原型上设置了方法,就能在该类的实例化对象中调用该方法。
例如:
数组的原型=数组的实例化, 所以在原型中添加了方法,在所有实例化的数组中的原型链中就存在了该方法。
Array.prototype.setWidth=funtion(){} 这就像等于给所有实例化的数组增加了setWidth这个方法。

给Div的类中添加多个方法,使实例化的div能够随意调用
 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);    //经过计算后的css样式
            }
        },
        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;  //通过drag的bool值控制是否能够拖拽
                if(_v){
                    this.style.position="absolute";
                    return this.addEventListener("mousedown",this.dragHandler); 
                    //这里加return的原因:添加了侦听事件后直接跳出,否则会就地移除刚侦听的事件
                }
                this.removeEventListener("mousedown",this.dragHandler);
            },
            get:function(){
                return this._drag;
            }
        },
        dragHandler:{
            value:function(e){
                if(e.type==="mousedown"){
                    e.preventDefault();
                    //因为下面侦听的源头变成了document,所以要将div的this存储下来。
                    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是上面存的document.target,this.offset是上面存的document.offset.
                    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){
        for(var i=0;i<this.length;i++){
            if(fn(this[i],i,this)) return true;
        }
        return false;
    }

    var arr=[2,4,6,8,10];
   var b=arr.some1(function(item,index,arr){
        return item%2===1;
    });
    console.log(b);
数组的原型方法

var arr=Array.prototype.slice.call(document.querySelectorAll(“div”)); //转换为数组 使用call的目的只是为了改变slice中的this。

var arr=Array.prototype.concat.apply([],document.querySelectorAll(“div”)); //将空数组与后面的参数连接。

给函数封装一个柯里化函数
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);
}

var f=getSum.currying();
f(1);
f(2,3,4);
console.log(f());
给函数封装一个反柯里化函数
Function.prototype.unCurrying=function(){
    var self=this;  //存一下push中的this
    return function(){
        return Function.prototype.call.apply(self,arguments);//arguments [[1,2,3,4],5]
        /* 当前实例的函数为数组中的push方法函数,所以这里就相当于
        Function.prototype.call.apply(push,arguments)//这里可以理解为将Function.prototype实例化为了push。
        push.call(arguments) ==> push.call([1,2,3,4],5)
        [1,2,3,4].push(5);
         */
        // push.call.apply(this,[[1,2,3,4],5]);
        // this.push.call([1,2,3,4],5);
        // [1,2,3,4].push(5)
        // call(arguments[0],arguments[1])
    }
}

var push=Array.prototype.push.unCurrying(); //这里Array.prototype.push将相当于一个实例化的Function
    /*  push就相当于function(){
        return Function.prototype.call.apply(self,arguments);//arguments [[1,2,3,4],5]
    }
    但此时push里面的this是一个数组,而不是想要改变的arguments。
     */

function getSum(){
    push(arguments,5); //push的参数带入了push.unCurrying()中
    console.log(arguments)
}

getSum(1,2,3,4);


 ~function(){

 }()
与下面的写法意思相同
 (function(){

 })();
给元素封装一个侦听事件的兼容写法
EventTarget.prototype.on=function(type,handler,bubbles){
    try{
        this.addEventListener(type,handler,bubbles);
    }catch(e){
        this.attachEvent("on"+type,handler);
    }
}

则侦听的时候无论是否兼容,可以直接:
(div的逐层原型中也有EventTarget)
div.on("click",clickHandler);

function clickHandler(e){

}
给对象的原型中增加克隆的方法
/* 
这里参数中省略了要复制的对象,因为在对象的原型增加了克隆方法后可由源对象直接调用该方法,则此时该方法中this即为要克隆的源对象。
*/

Object.prototype.cloneObject=function(target){
    if(target==undefined) target={};
    var names=Object.getOwnPropertyNames(this);
    for(var i=0;i<names.length;i++){
        var desc=Object.getOwnPropertyDescriptor(this,names[i]);
        if(typeof desc.value==="object" && desc.value!==null){
            var obj;
           switch(true){
               case desc.value.constructor===Date:
               obj=new Date(desc.value.toString());
               break;
               case desc.value.constructor===RegExp:
               obj=new RegExp(desc.value.source,desc.value.flags);
               break;
               case HTMLElement.isPrototypeOf(desc.value.constructor):
               obj=document.createElement(desc.value.nodeName);
               break;
               default:
               obj=new desc.value.constructor()
           }
            Object.defineProperty(target,names[i],{
                enumerable:desc.enumerable,
                writable:desc.writable,
                configurable:desc.configurable,
                value:obj
            });
            desc.value.cloneObject(obj);//要递归时直接将要复制的对象.cloneObject(目标对象)即可。
            为什么此时的目标对象是obj呢?因为上面的switch语句根据源对象的类型创建好了一个obj空壳,此时要将真实的数据复制进去。
        }else{
            Object.defineProperty(target,names[i],desc)
        } 
    }
    return target;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值