zoukankan      html  css  js  c++  java
  • Javascript进阶 (转帖)

    前言
    我的上一篇<Javascript简述>对JavaScript做了浅尝辄止的描述,并没有深入讲解其细节内容。本文则会从下面几方面的内容对JavaScript做一些整理与深入的讲解:
    1. object
    2. this & closure
    3. call & apply
    4. arguments
    深入了解这些概念将使你在JavaScript的使用上更加的游刃有余。

    一、object
    JavaScript是弱类型的脚本语言,所以声明变量时不用指定类型。
    在JavaScript中有三个基本类型boolean,number,string与特殊类型null(空/无效),undefined(无定义),引用类型则是object。
    数组和函数都是实现为object类型的对象。一般情况下在JavaScript中可以这样定义对象,类似perl中的hash:
    var functions = {
     show:function(){
      alert("Show"); },
     hide:function(){
      alert("Hide"); }
    };

    这里有两种方式调用其中的函数:
    1, functions.show();
    2, functions["show"]();
    显然用第二种方式可以让我们在程序中动态生成函数调用方式,有更大的自由性,充分体现出JavaScript动态语言的特性。
    例如:
    functions[condition?"show":"hide"](); // 根据condition条件决定调用show/hide

    在jQuery源代码中就有好几处地方使用了该方式:

    Code

    ECMAScript为object类型定义了一个内部属性prototype。在对象的属性解析过程中,会需要用到这个内部属性所引用的对象链--即原型链,原型链终止于链中原型为null的对象。
    可以通过一个公共的prototype属性,来对与内部的prototype属性对应的原型对象进行赋值或重新定义。
    例如:

    function Person(first, last) {
      
    this.first = first;
      
    this.last = last;
    }
    Person.prototype.fullName 
    = function() {
     
    return this.first + ' ' + this.last;
    }
    Person.prototype.toString 
    = function(){
        
    return '[Person: ' + this.fullName() + ']';
    };

    var simon = new Person('Simon''Willison');
    document.write(simon.fullName());

     

    二、this与闭包(closure)
    这里先从一个例子开始:

    Code

    如果大家对上述代码中this与闭包的用法有疑惑的话,可以继续往下看。

    讲到这里就不得不提及JavaScript的作用域(scope)。所有的JavaScript代码都是在一个执行环境中被执行,有自己的作用域。这部分内容相对来说比较复杂,读者有兴趣可以详细参考<Javascript 闭包>。

    JavaScript中的this就是被调用对象的引用。形象的说,是当前执行环境的上下文对象;简单的说,就是函数的拥有者Owner(这点对理解Event Handling很重要)。

    闭包并不是JavaScript特有的概念,Martin Fowler早些年就发表了一篇关于闭包的文章中文版)。
    闭包是具有闭合作用域 的匿名函数。简单来说就是在function内定义的function,內部的function可以存取外部function內定义的变量。

    现在来看看上面说的那个例子:
    1、定义了一个jx对象,由于是作为Ajax使用的,所以它提供的一些属性都是为了自定义参数使用的。
    2、我们关注它的load方法:
     this.init();    // 对XMLHttpRequest对象进行初始化
     var ths = this; // 在这里把jx对象本身保存到ths中是为了onreadystatechange函数中可以正确使用到jx对象中的属性(否则onreadystatechange内部的this指向的是http对象而不是我们要使用的jx对象)。
     this.http.onreadystatechange = function () {
        if(!ths) return;
        var http = ths.http;
        if (ths.indicator)ths.indicator.style.display='';
        if (http.readyState == 4) {//4 = document loaded.
         if (ths.indicator)ths.indicator.style.display='none';
         if(http.status == 200||http.status==0) {
          ...... 
          if(ths.callback) ths.callback(result); // process
         }
         ......
        }
       } 

    这里还要强调一下JavaScrpt的Event Handling里this的使用:
    假设Html页面上有元素<div id="prompt"">Hello World!</div>,我们可以通过两种机制给div元素添加上下面的click事件:
    // 在Html页面上定义click函数
    function fn_click(){
     this.style.color = "#cc0000"; // 此时this指向的是函数的拥有者--页面,确切说是JavaScript的window对象
    }
    1, Copying
    var divP = document.getElementById("prompt");
    divP.onclick = fn_click;
    顾名思义,Copying机制是通过把fn_click函数拷贝给div的onclick属性。因此事件执行后this指向的就是触发事件的div元素,故该函数在div点击后可以正常运行。

    【注:这里给读者提个疑问--我们应该如何更改fn_click中的this指向,使其指向的是你需要的对象上而不是触发事件的div元素?这篇文章对此有精彩的论述:JavaScript's Slippery this Reference and Other Monsters in The Closet
    2, Referring
    Referring机制则是找到引用的fn_click函数后再执行它。
    <div id="prompt" onclick="javascript:fn_click();">Hello World!</div>
    大家可以想想其结果是什么呢?

    由于其采用的是Referring机制,故fn_click函数中的this指向的是全局对象window,那么显然onclick后会弹出错误--style不是window对象的属性。
    为了解决这个问题,可以修改为:
    function fn_click(obj){
     obj.style.color = "#cc0000"; 
    }
    <div id="prompt" onclick="javascript:fn_click(this);">Hello World!</div>


    三、call与apply
    apply
    Allows you to apply a method of another object in the context of a different object (the calling object).
    call
    Allows you to call (execute) a method of another object in the context of a different object (the calling object).
    作用都是将函数绑定到另外一个对象上去运行,两者只是在定义参数方式有所区别:
    var result = fun.apply(thisArg[, argsArray]);
    var result = fun.call(thisArg[, arg1[, arg2[, ...]]]);

    这里的参数差别就决定了apply在需要传参数的应用上更有优势。

    请看下面的两个例子:
    1, 为了保证在没有window.console的情况下,仍可以输出参数,可以采用如下方法:

    function log() {
        
    if( window.console )
            console.debug.apply( console, arguments );
        
    else
            alert( [].join.apply( arguments, [
    ' '] ) );
    }

    log( 'json feed received:', json );

    2, 利用Array中的slice方法并通过call生成新的数组,简化操作:

    var args = []; // empty array
    //
     copy all other arguments we want to "pass through" 
    for(var i = 2; i < arguments.length; i++)
    {
        args.push(arguments[i]);
    }
    func.apply(obj, args);

    // 通过刚才的介绍,我们可以简化为:
    var args = [].slice.call(arguments,2);
    func.apply(obj, args);

     

    四、arguments
    在JavaScript函数代码中可以使用特殊的对象arguments来实现不定参数的效果。
    它以类数组的形式保存了当前函数调用的参数,但是它实际上并不是数组,使用arguments instanceof Array会返回"false",不过我们可以使用下标获取其值以及长度length属性(表示调用参数的数目)。此外arguments还有个非常有用的属性callee,它表示对当前调用函数对象自身的引用,特别是可以用它来调用自身的匿名函数。

    注:
    1, 网上有不少方法说明arguments不是数组,大家有兴趣可以去看看。
    2, 函数属于引用类型,有自己的属性和方法,其中length声明了函数期望的参数个数。
    函数名.length或arguments.callee.length   // 形参个数
    arguments.length  // 实参个数

    请看下面这个经典例子--与C#中String.Format()方法类似:

    String.prototype.format = function(){
     
    var args = arguments;  // 将参数保存到args中,以便于在stringobject.replace函数中被使用
     return this.replace(/\{(\d+)\}/g,
       
    function(m,s,i,t){
        
    return args[s]; // s是模式中子表达式匹配的字符串,正是{0},{1}中的0,1
       });
    }
    var formats = "{0} is {1}!";
    document.write(formats.format(
    "hans","chinese"));

    其在jQuery源代码中的使用:

    Code

    通过前面的讲解,最后再看看下面这个例子:

    var Class = {
     create : 
    function() {
      
    return function() { this.initialize.apply(this, arguments); }
     }
    };

    var vehicle = Class.create();
    vehicle.prototype 
    = {
     initialize : 
    function(type){
      
    this.type=type;
     },

     showSelf : 
    function(){
      
    return 'this vehicle is ' + this.type;
     }
    };

    var moto = new vehicle('Moto');
    log.info(moto.showSelf());

    现在,大家可以看明白这个例子吗? 

    五、References
    http://www.javascriptkit.com/jsref/
    http://www.quirksmode.org/js/this.html

    http://www.blueidea.com/tech/web/2007/4855.asp
    http://blog.csdn.net/mumuTiger/archive/2008/03/25/2217731.aspx
    http://www.cn-cuckoo.com/wordpress/wp-content/uploads/2007/08/JavaScriptClosures.html

    分类: jQuery
  • 相关阅读:
    使用 yo 命令行向导给 SAP UI5 应用添加一个新的视图
    SAP Fiori Elements 应用的 manifest.json 文件运行时如何被解析的
    SAP UI5 标准应用的多语言支持
    微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
    SAP Fiori Elements 应用里的 Title 显示的内容是从哪里来的
    本地开发好的 SAP Fiori Elements 应用,如何部署到 ABAP 服务器上?
    如何在 Cypress 测试代码中屏蔽(Suppress)来自应用代码报出的错误消息
    教你一招:让集群慢节点无处可藏
    应用架构步入“无服务器”时代 Serverless技术迎来新发展
    MySQL数据库事务隔离性的实现
  • 原文地址:https://www.cnblogs.com/zhwl/p/2362600.html
Copyright © 2011-2022 走看看