Java程序员的JavaScript学习笔记(7——jQuery基本机制)

27 篇文章 0 订阅
16 篇文章 0 订阅
计划按如下顺序完成这篇笔记:
  1. Java程序员的JavaScript学习笔记(1——理念)
  2. Java程序员的JavaScript学习笔记(2——属性复制和继承)
  3. Java程序员的JavaScript学习笔记(3——this/call/apply)
  4. Java程序员的JavaScript学习笔记(4——this/闭包/getter/setter)
  5. Java程序员的JavaScript学习笔记(5——prototype)
  6. Java程序员的JavaScript学习笔记(6——面向对象模拟)
  7. Java程序员的JavaScript学习笔记(7——jQuery基本机制)
  8. Java程序员的JavaScript学习笔记(8——jQuery选择器)
  9. Java程序员的JavaScript学习笔记(9——jQuery工具方法)
  10. Java程序员的JavaScript学习笔记(10——jQuery-在“类”层面扩展)
  11. Java程序员的JavaScript学习笔记(11——jQuery-在“对象”层面扩展)
  12. Java程序员的JavaScript学习笔记(12——jQuery-扩展选择器)
  13. Java程序员的JavaScript学习笔记(13——jQuery UI)
  14. Java程序员的JavaScript学习笔记(14——扩展jQuery UI)
这是笔记的第7篇,聊聊jQuery基本机制,学习的同时,我们试图实现一个缩略版本的jQuery,我们叫他jQ。

我们认为读者在阅读本篇之前,对jQuery的使用是熟悉的。

第7篇到第9篇是一个单元,在这个单元中,我们将深入jQuery内部,充分学习JavaScript的最佳设计、编程实践。


作者博客:http://blog.csdn.net/stationxp

作者微博:http://weibo.com/liuhailong2008

转载请取得作者同意



首先,预热一下语法。

1、预热语法

看下面代码:
//代码段1
(function(){
    console.log('this is a function be called immediately.')
})();
第一对小括号中是一条语句,返回一个函数,然后通过第二对小括号对这个函数直接进行调用。
运行输出:this is a function be called immediately.

可以传参数给这个参数,在JavaScript中,$和_都是合法的变量名。
//代码段2
(function(_){
    console.log(_);  //输出:window,视浏览器输出的具体内容不同
})(this);
在全局上下文中this指向window。

可以通过如下方法获得返回值。
//代码段3
var f = (function(_){
    function func(){
        console.log('i am invoked by ' + this , 'arguments:' + _ );// output : i am invoked by [object Window] arguments:param value
    }
    return func;
})('param value');
f();


也可以将需要返回的数值或方法直接附加为window的属性,达到“返回”的目的。
//代码段4
(function(){
    function func($$){
        console.log('i am invoked by ' + this );
    }
    window.func = func; // 相当于直接定义了全局函数func
    window.$$ = new func(); //相当于定义了全局变量 $$ ,在JavaScript中,$$ 是合法的变量名。
})();
func();
console.log($$.toString());// output : [object Object]

2、预期功能

我们将实现一个js代码框架,jQ,预期实现如下功能:
2.1、通过jQ('#id')可以通过id取到dom对象。
2.2、对jQ对象(即通过jQ方法返回的对象),可以使用html()方法获取其内容或者设置其内容,语法如下:
jQ('#id').html();//返回其内容
jQ('#id').html('new content');//设置其内容
2.3、可以用$$代替jQ,语法如下:
$$('#id').html();

3、实现

3.1、基于前面的语法基础,我们视图实现2.1提出的功能。

代码段5

<!DOCTYPE html>
<html>
<head>
    <title>jQ</title>
    <meta charset="utf-8">
    <script type="text/javascript" language="javascript">
        (function(){
            var jQ = function(id){
                if(!id){
                    return {}; // return empty object
                }
                if(id[0]=='#'){
                    id = id.substr(1);//remove the first letter '#'
                }
                var domEle = document.getElementById(id);
                if(!domEle){
                    return {};
                }
                return domEle;
            }
            window.jQ = jQ;
        })();


        console.log(jQ('#divTest'));
    </script>
</head>
<body>
    <div id="divTest">blabla</div>
</body>
</html>

获取到dom对象后直接返回了。这种做法不足取,需要封装一下,最好以function object(function是js中的一等公民,功能最强)的形式返回。
而且希望返回值是jQ“类”的实例。
//代码段6
 (function(){
    var jQ = function(id){
        var ret = new jQ();
        ret.innerDom = 'blabla';
        return ret;
    }


    jQ.prototype = {
        innerDom : null
    }
    window.jQ = jQ;
})();
console.log(jQ('#divTest'));

Uncaught RangeError: Maximum call stack size exceeded ,死循环了。
直接new不可用用的话,那可以用工厂方法。
//代码段7
(function(){
    var jQ = function(id){
        var ret = jQ.prototype.getInstance(id);
        return ret;
    }

    jQ.prototype = {
        innerDom : null,
        getInstance :function(id){
            //todo : init innerDom by id
            return this;     // 调用者,即jQ
        }
    }
    window.jQ = jQ;
})();
console.log(jQ('#divTest')===jQ('#divTest1')); // output :  true

上面的最后一行代码,意图构建两个不同的对象,结果返回的对象相同,这是错误的。
改正后的代码如下所示。
//代码段8
(function(){
    var jQ = function(id){
        var ret = new jQ.prototype.getInstance(id); // 增加new关键字
        return ret;
    }

    jQ.prototype = {
        innerDom : null,
        getInstance :function(id){
            //todo : init innerDom by id
            return this;     // 调用者,即jQ
        }
    }
    window.jQ = jQ;
})();
console.log(jQ('#divTest')===jQ('#divTest1')); // output :  false

根据new关键字的语义:
var ret = new jQ.prototype.getInstance(id);
等同于
var ret ={};
jQ.prototype.getInstance.apply(ret);//即通过ret调用getInstance方法,getInstance方法中的this绑定为ret
ret.__proto__ = jQ.prototype.getInstance.prototype;//指定ret的原型为getInstance的原型,这里会出问题,因为getInstance的原型是Object(几乎是空)。

为了弥补new关键字的缺憾,修正代码如下:
//代码段9
(function(){
    var jQ = function(id){
        var ret = new jQ.prototype.getInstance(id);
        return ret;
    }

    jQ.prototype = {
        innerDom : null,
        getInstance :function(id){
            //todo : umimpl init innerDom by id
            this.innerDom = 'dom by '+id;
            return this; //this调用者,即新创建的对象
        },
        html:function(){
            //todo : impl the method
            return this.innerDom;//this调用者,即新创建的对象
        }
    }
    jQ.prototype.getInstance.prototype = jQ.prototype;//新增加代码,由于是传引用,不用担心循环引用的问题
    window.jQ = jQ;
})();

console.log(jQ('#divTest').html()); //output : dom by #divTest
console.log(jQ('#divTest2').html()); //output : dom by #divTest2

3.2、现在增加2.2描述的功能:html方法

//代码段10
<!DOCTYPE html>
<html>
<head>
    <title>jQ</title>
    <meta charset="utf-8">

</head>
<body>
    <div id="divTest">blabla</div>
    <script type="text/javascript" language="javascript">
        (function(){
            var jQ = function(id){
                var ret = new jQ.prototype.getInstance(id);
                return ret;
            }

            jQ.prototype = {
                innerDom : null,
                getInstance :function(id){
                    if(id && id[0]=='#'){
                        id = id.substr(1);//remove the first letter '#'
                    }
                    if(id){
                        var elm = window.document.getElementById(id);
                        this.innerDom = elm;
                    }
                    return this;
                },
                html:function(newhtml){
                    if(arguments && arguments.length>0){
                        if (this.innerDom && this.innerDom.innerHTML){
                            this.innerDom.innerHTML = newhtml;
                        }
                    }else{
                        return this.innerDom && this.innerDom.innerHTML;
                    }
                }
            }
            jQ.prototype.getInstance.prototype = jQ.prototype;
            window.jQ = jQ;
        })();
        console.log(jQ('#divTest',window).html());  //output : blabla
        jQ('#divTest',window).html('BRAND NEW');    //页面内容随之改变
        console.log(jQ('#divTest',window).html());  //output : BRAND NEW
    </script>
</body>
</html>

3.3、通过$$引用

2.3描述的功能更简单,只需在window.jQ = jQ;后面加一句:
window.$$ = jQ;
调用的语句修改为:
console.log($$('#divTest',window).html());  //output : blabla
$$('#divTest',window).html('BRAND NEW');    //页面内容随之改变
console.log($$('#divTest',window).html());  //output : BRAND NEW

功德圆满!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值