• jQuery分离构造器


    http://www.imooc.com/code/3401

    通过new操作符构建一个对象,一般经过四步:

      A.创建一个新对象

      B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象)

      C.执行构造函数中的代码

      D.返回这个新对象

    最后一点就说明了,我们只要返回一个新对象即可。其实new操作符主要是把原型链跟实例的this关联起来,这才是最关键的一点,所以我们如果需要原型链就必须要new操作符来进行处理。否则this则变成window对象了。

    下面这个例子,console结果一样。因为都用了new 。如果不用new就不一样了。

    var $$ = ajQuery = function(selector) {
            this.selector = selector;//this是aJquery {}name: "sss"__proto__: Object
            return this
        }
        var ins = new $$("111");
        console.log(ins);//
        var $$2 = ajQuery2 = function(selector) {
            this.selector = selector;
        }
        var ins2 = new $$2("2222");
        console.log(ins2);//

    去掉new 后。ajQuery里的return this就起了作用。

    var $$ = ajQuery = function(selector) {
            this.selector = selector;
            return this
        }
        var ins = $$("111");
        console.log(ins);//window
        var $$2 = ajQuery2 = function(selector) {
            this.selector = selector;
        }
        var ins2 = $$2("2222");
        console.log(ins2);//undefined

    我们常见的类式写法:

    var $$ = ajQuery = function(selector) {
            console.log(this instanceof ajQuery);//true ajQuery被new形式调用时,this就是ajQuery的实例
            this.selector = selector;
            return this
        }
        ajQuery.fn = ajQuery.prototype = {
            selectorName:function(){
                return this.selector;
            },
            constructor: ajQuery
        }
        var ins = new $$("111");
        console.log(ins.selectorName());

    首先改造jQuery无new的格式,我们可以通过instanceof判断this是否为当前实例

    var $$ = ajQuery = function(selector) {
            console.log(this);//先是window,再是ajQuery的实例
            if(!(this instanceof ajQuery)){
                return new ajQuery(selector);
            }
            this.selector = selector;
            return this
        }
        ajQuery.fn = ajQuery.prototype = {
            selectorName:function(){
                return this.selector;
            },
            constructor: ajQuery
        }
        var ins = $$("111");
        console.log(ins.selectorName());

    注意千万不要像下面这样写:

    var $$ = ajQuery = function(selector) {
        this.selector = selector;
        return new ajQuery(selector);
    }
    Uncaught RangeError: Maximum call stack size exceeded

    这样会无限递归自己,从而造成死循环并且溢出。

     jQuery为了避免出现这种死循环的问题,采取的手段是把原型上的一个init方法作为构造器。

    function aJquery(selector){
            return new aJquery.fn.init(selector);
        }
        aJquery.fn = aJquery.prototype = {
            showName:function(){
                console.log(this.name)
            },
            init: function(){
                console.log(this);
            }
        }
        var a = aJquery("sss");
        a.showName();//报错

    这样确实解决了循环递归的问题,但是又问题来了,init是ajQuery原型上作为构造器的一个方法,那么其this就不是ajQuery了,所以this就完全引用不到ajQuery的原型了(showName报错),所以这里通过new把init方法与ajQuery给分离成2个独立的构造器。

    静态与实例方法共享设计

    jQuery遍历方法:

    $(".aaron").each()   //作为实例方法存在
    $.each()             //作为静态方法存在

    这是最常见的遍历方法,第一条语句是给有指定的上下文调用的,就是(".aaron")获取的DOM合集,第二条语句$.each()函数可用于迭代任何集合,无论是“名/值”对象(JavaScript对象)或数组。在迭代数组的情况下,回调函数每次都会传递一个数组索引和相应的数组值作为参数。本质上来说2个都是遍历,那么我们是不是要写2个方法呢?

    我们来看看jQuery的源码:

    jQuery.prototype = {
        each: function( callback, args ) {
            return jQuery.each( this, callback, args );
        }
    }
    var Newobj = function(name){
            this.name = name;
        }
       Newobj.showName = function(args){//静态方法:不能被实例对象调用
            console.log(args);
       }
       Newobj.prototype = {
            showName: function(args){//实例方法
                return Newobj.showName(this.name + args );
            }
       }
       var s = new Newobj("sss");
       s.showName("bbb");//sssbbb

    实例方法取于静态方法,换句话来说这是静态与实例方法共享设计,静态方法挂在jQuery构造器上,原型方法挂在哪里呢?

    我们上节不是讲了内部会划分一个新的构造器init吗?jQuery通过new原型prototype上的init方法当作构造器,那么init的原型链方法就是实例的方法了,所以jQuery通过2个构造器划分2种不同的调用方式一种是静态,一种是原型。

    方法是共享的,并且实例方法取于静态方法,2个构造器是完全隔离的 ,这个要如何处理?

    看看jQuery给的方案:

    画龙点睛的一处init.prototype = jQuery.fn,把jQuery.prototype原型的引用赋给jQuery.fn.init.prototype的原型,这样就把2个构造器的原型给关联起来了。

    ajQuery.fn = ajQuery.prototype = {
            name: 'aaron',
            init: function(selector) {
                   this.selector = selector;
                   return this;
            },
            constructor: ajQuery
    }
    ajQuery.fn.init.prototype = ajQuery.fn

    这段代码就是整个结构设计的最核心的东西了,有这样的一个处理,整个结构就活了!不得不佩服作者的设计思路,别具匠心。

    看看init的的构造图:

    (单击图片查看大图)

    通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype。换句话说jQuery的原型对象覆盖了init构造器的原型对象,因为是引用传递所以不需要担心这个循环引用的性能问题。

    var $$ = ajQuery = function(selector) {
        //把原型上的init作为构造器
        return new ajQuery.fn.init( selector );
    }
    ajQuery.fn = ajQuery.prototype = {
        name: 'aaron',
        init: function(selector) {
            this.selector = selector;
            return this;
        },
        constructor: ajQuery
    }
    ajQuery.fn.init.prototype = ajQuery.fn;
    ajQuery.fn.foo = function () { alert("foo!"); };
    ajQuery(".some-selector").foo();
    //挂在ajQuery.fn上的实例方法变成了ajQuery(ajQuery.fn.init)上的原型方法

    现在的ajQuery(".some-selector")

    原型中有foo有init。

    http://stackoverflow.com/questions/1755080/why-jquery-do-this-jquery-fn-init-prototype-jquery-fn
  • 相关阅读:
    函数传参-修改文本
    函数传参-商品计价
    嵌套选项卡自动播放
    仿淘宝自动播放菜单栏
    仿淘宝侧边栏菜单
    图片自动切换
    定时器应用-页面弹出广告
    转:Java面试题集(1-50)
    转:115个Java面试题和答案——终极列表(上)
    毕向东day01笔记--dos-jdk-jre-环境变量等
  • 原文地址:https://www.cnblogs.com/darr/p/5118650.html
Copyright © 2020-2023  润新知