zoukankan      html  css  js  c++  java
  • javascript进阶笔记(1)

    学习js已经有一段时间了,大大小小还是能够做出一些东西来。不过觉得可惜的是,还是对js本身这门语言不是很熟悉,总有一点雾里看花的感觉,看得见,但是看不清楚。最近发现有一本关于js的叫做《忍者秘籍》的书刊,听说是jQuery作者写的,可以让初级者进阶,哇啦啦,打怪兽,加经验升级,多好的事情。于是,就有了此篇文章及其后续。闲话休谈,正事要紧!

     javascript是一门函数式语言(functional language)。最重要的,在js中,函数第一型对象(first-class object),也就是说,函数可以共处,可以将其视为其他任意类型的javascript对象。就像普通的js数据类型,函数可以被任意变量进行引用,或声明成对象字面量,甚至可以将其作为函数参数进行传递。

     函数的第一型对象体现在:

    1、它们可以通过字面量进行创建;

    2、它们可以赋值给变量、数组或其他对象的属性;

    3、它们可以作为参数传递给函数;

    4、它们可以作为函数的返回值进行返回;

    5、它们拥有动态创建并赋值的属性。

    函数除了以上的功能外,它还包含一个功能,它们可以被调用。千万不要小瞧了函数的调用!因为不同的调用机制会产生不同的功效,特别是针对函数的this关键字。

    当我们定义了一个函数,以便其他一些代码在适当的时候回头调用它,我们可以称之为回调。回调是高效利用js必不可少的一部分。

    js函数是使用函数字面量(function literal)进行声明从而创建函数值的。例如:

    function method(){}

    一个函数的创建,由四个部分组成:

    1、function 关键字;

    2、函数名称,为可选。没有名称的函数称为匿名函数;

    3、圆括号包含的一个以逗号分隔的参数列表,该参数列表可以为空,但是圆括号必须存在;

    4、大括号包含的函数体。函数体可以为空,但大括号必须存在。

    所有的函数都有一个name属性,该name属性值是该函数名称的字符串。没有名称的函数也有name属性,只是该属性值为空字符串。

    //该函数的name属性值为Method
    function Method(){}
    
    //通过匿名函数赋值的情况,该函数的name属性值为空字符串,因为function关键字后面没有函数名称
    var method=function(){};
    
    //该函数的name属性值为method,因为该函数声明中,包含了函数名称
    var fun=function method(){}

    当我们声明一个函数时,我们不仅要关注该函数可用的作用域,还要关注该函数自身所创建的作用域,以及函数内部的声明是如何影响这些作用域的。

    js不同于其他面向对象语言,在js中,作用域是由function进行声明的,而不是代码块。或许有的变量或函数声明于代码块,但不终结于该代码块。例如:

    function method(value){
        //虽然变量i在for代码块中声明,但是变量i的作用域离开了该for代码块也存在,一直到method函数体结尾,下面在if代码块中声明的变量a也是一个道理
        for(var i=0;i<10;i++){
            
        }
        alert(i);//10    
        
    alert(a);//undefined
    a=2;
    alert(a);//2 if(true){ var a=1; } alert(a);//1 }

    关于变量和函数声明的作用域:

    1、变量声明的作用域开始于声明的地方,结束于所在函数的结尾,与代码嵌套无关。值得注意的是,只要在该函数中,变量在其声明之前,还是可以通过对其赋值进行调用,如果不对其进行赋值,那么该变量值为undefined,列子如上面method函数中的变量a;

    2、命名函数的作用域是指声明该函数的整个函数范围,与代码嵌套无关。说的就是函数声明提升机制。

    3、对于作用域声明,全局上下文就像一个包含页面所有代码的超大型函数。

    每个声明项的作用域不仅取决于它的声明,还取决于它是变量还是函数。

    在编写js代码时,我们都是称调用js函数,但是,能否应该停下来想一想,函数被调用时,到底发生了什么?

    事实证明,函数调用的方式对其函数内部的代码是如何执行的,有着巨大的影响,尤其是针对this参数,这是非常重要的。

    实际上,有四种不同的方式可以进行函数调用,每种方式都有它们自己细微的差别:

    1、作为一个普通函数进行调用,这是最简单的形式。如:method();

    2、作为一个对象的方法进行调用,支持面向对象编程。如:person.setName();

    3、作为构造器进行调用,创建一个新对象。如:new Person();

    4、通过apply()或call()方法进行调用。如:[].slice.call(argument,0,3)。

    在研究函数调用之前,我们先来看函数的参数传递。当一个参数列表作为函数调用的一部分时,这些参数会按照函数声明里的形参声明顺序,将参数值分别赋给这些形参。第一个参数赋值给第一个形参,第二个参数赋值给第二个形参,以此类推。

    如果传入的参数与形参的个数不一致,怎么办?别担心,山人自有妙计:

    1、如果实际传递的参数数量大于函数声明的形参数量,超出的参数则不会配给形参;

    2、如果实际传递的参数数量小于形参数量,则没有对应参数的形参会被赋值为undefined。

    在参数传递的时候,有一个非常有趣且非常有用的现象,所有的函数调用都会传递两个隐式参数:arguments和this。所谓的隐式,也就意味着两个参数不会显示在函数签名里,但是它们默默地传递给函数并存在于函数的作用域内。在函数内部,它们可以像其他显示命名的参数一样使用。

    arguments参数:这是传递给函数的所有参数的一个集合。该集合拥有length属性,length值为全部参数的个数。我们可以通过for循环遍历出每个参数值,也可以像访问数组一样通过索引去获取其中的某个参数值。例如argument[0]就是获取第一个参数值。在这里,请注意,arguments不是数组!arguments不是数组!arguments不是数组!重要的事情说三遍。它就像一个类数组结构。

    this参数:一个函数被调用时,除了传入函数的显示参数外,名为this的隐式参数也被传入了函数。this参数引用了与该函数调用进行隐式关联的一个对象,被称之为函数上下文(function context)。请注意,js中的this依赖于函数的调用方式。

    如果一个函数作为普通函数进行调用,也就是例如method()这种,一个函数名称加上圆括号的样式。以这种方式进行调用时,函数的上下文是全局上下文,也就是说隐式传入的this是window对象。

    如果将一个函数作为对象的方法进行调用,例如person.setName()这种,则该person对象就变成了setName函数的上下文。也就是说一个方法所属的对象在该方法体内可以以this的形式进行引用。说得通俗一点,传入该对象方法的this是当前调用该方法的对象,也就是person。

    注意:相同的函数,其函数上下文(this)会随着函数调用方式的变化而变化,而不是取决于函数是怎样声明的。因为一个函数,可以被当做普通函数调用,也可以赋值给一对象的方法。

    将函数作为一个构造器进行调用,其实它并没有什么特别的地方。只是,构造器函数的声明和其他函数有点不大一样,不同的地方是在于如何调用该函数。将函数作为构造器(constructor)进行调用,我们要在函数名称前使用new关键字,例如:new Person()。

    将函数作为构造器进行调用,是js的一个超级特性,因为构造器调用时,会发生如下行为:

    1、创建一个新的空对象;

    2、将该新的空对象当做this参数传递给构造器函数,从而成为该构造器的函数上下文(this);

    3、如果该构造器函数没有显示的返回值,则新创建的对象就会作为构造器的返回值进行返回。

    请注意:构造器的目的是要创建一个新对象并对其进行设置,然后将其作为构造器的返回值进行返回。任何干扰或者不存在这种意图的函数,都不适合作为构造器函数。

    我们可以用以下代码来测试:

    //声明一个构造器函数
    function Person(){
        this.showSelf=function(){return this;};
    }
    
    //创建一个对象
    var p=new Person();
    
    if(p===p.showSelf())
        alert("OK!");
    else 
        alert("Fail!");
    
    //OK!
    
    //解析以上代码
    //首先声明一个构造器函数Person
    //接着,用new调用构造器函数Person,并创建一个对象p
    //当构造器函数Person被调用时: //1.创建一个新的空对象 //2.将新创建的对象当做this参数隐式传递给构造器函数Person。然后在Person内部,this新增了一个方法showSelf //3.将该新创建的对象当做返回值,并赋值给p变量
    //p对象和p.showSelf方法返回的this指向的是同一个对象,因此它们真相等!

    由于构造器的编码和使用方式不同于其他函数,除了作为构造器调用之外,通常它们也不是全部都那么有用,因此命名约定的出现是为了区别构造器和其他普通函数的方法。一般函数的命名以动词开头,比如setName、getName之类的。而构造器的名称通常是由一个描述所构造对象的名词来命名,如Person。

    在函数调用的时候,js为我们提供了一种方式,就是可以显示指定任何一个对象作为其函数上下文。js中的每个函数都有apply()和call()方法。使用其中一个方法,我们都可以实现这种功能。有的同学会迷惑,为啥函数也有它们自己的方法呢?因为作为第一型对象(透个底,它是由Function()构造器创建的),函数可以像其他任何类型的对象一样,拥有属性和方法。

    通过函数的apply()方法来调用函数,我们要给apply()传递两个参数:第一个是函数上下文,也就是this参数,另外一个是作为函数参数所组成的数组。call()方法与此非常类似,唯一不同的就是,给函数传入的参数是一个参数列表,而不是单个数组。如以下代码所示:

    function sum(){
        var result=0;
        for(var i=0;i<arguments.length;i++)
            result+=arguments[i];
        this.result=result;
    }
    
    var obj1={},obj2={};
    sum.call(obj1,1,2,3,4);
    sum.call(obj2,5,6);
    
    alert(obj1.result);//10
    alert(obj2.result);//11
    
    //其实函数调用apply或call方法,就是显示指定传给函数的this和arguments参数

    使用apply()和call()方法,我们可以选择任意对象作为函数的上下文(this)。

    我们可以通过apply()或call()方法,给回调函数强制指定函数上下文,也就是this参数。如下代码所示:

    //给callback强制指定其this参数为list数组的每个迭代的元素,arguments为当前迭代元素的索引
    function forEach(list,callback){
        for(var i=0;i<list.length;i++)
            callback.call(list[i],i);  
    }
    
    var names=['小明','小花','小萌'];
    
    //回调函数的this参数就是names数组的单个元素
    forEach(names,function(index){
        console.log("大家好,我是"+this);
    });
    
    
    //大家好,我是小明
    //大家好,我是小花
    //大家好,我是小萌
  • 相关阅读:
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    JAVA-蓝桥杯-算法训练-字符串变换
    Ceph:一个开源的 Linux PB 级分布式文件系统
    shell 脚本监控程序是否正在执行, 如果没有执行, 则自动启动该进程
  • 原文地址:https://www.cnblogs.com/williamwsj/p/7155674.html
Copyright © 2011-2022 走看看