函数定义和调用
   定义函数,在JavaScript中,定义函数的方式如下:
      function abs(x){
        if(x >=0){
          return x;
        }else{
          return -x;
        }
      }
  上述abs() 函数的定义如下:
    function 指出这是一个函数定义;
    abs 是函数的名称;
    (x) 括号内列出函数的参数,多个参数以,分隔;
    {...}之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
  注意:函数体内部的语句在执行时,一旦执行到return 时,函数就执行完毕,并将结果返回。因此内部通过条件判断和循环可以在实现非常复杂的。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。
由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。     

      var abs = function(x){
          if(x >= 0){
            return x;
          } else {
            return -x;
           }
        }

在这种方式下,function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。
两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。
调用函数时,按顺序传入参数即可:    

    abs(10); // 返回10
    abs(-9); // 返回9

由于JavaScript 允许传入任意个参数而不受影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数。
    abs(10,'blablabla'); //返回10
    abs(-9,'haha','hehe',null) // 返回9

    传入的参数比定义的少也没有问题
    abs(); 返回NaN

    此时abs(x)函数的参数x 将收到undefined,计算结果为NaN
      function abs(x){
          if(typeof x !=='number'){
            throw 'Not a number':
          }
         if(x >=0){
            return x;
        }else{
            return -x;
        }
      }

arguments
JavaScript 还有一个免费赠送的关键字 arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。
      function foo(x){
          alert(x); // 10
          for(var i=0; i < arguments.length;++){
            alert(arguments[i]); // 10,20,30
          }
       }
      foo(10.20,30)

利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
      function abs(){
        if(arguments.length ===0){
          return 0;
      }
       var x = arguments[0]
        return x >=0 ? x : -x;
      }
      abs(); //0
      abs(10); // 10
      abs(-9) //9

实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:
    // foo(a[,b],c)
    //接受2~3 个参数,b 是可选参数,如果只要出入两个参数,b默认为null
    function foo(a,b,c){
      if(arguments.length ===2){
        // 实际拿到的参数是a 和b c 为undefined
      c = b;
      b = null; // b 变为默认值

    要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。

rest 参数
由于JavaScript 函数允许接收任意个参数,遇事我们就不得不用arguments 来获取所有的参数:
    function foo(a,b){
      var i, rest = [];
      if(arguments.length > 2){
      for(i = 2; i < arguments.length; i++){
      rest.push(arguments[i]);
      }
    }
      console.log('a =' + a);
      console.log('b = ' + b);
    console.log(rest);
  }

  为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没       有更好的方法?

ES6标准引入了rest参数,上面的函数可以改写为:

    function foo(a,b,...rest){
      console.log('a = ' + a);
      console.log('b = ' + b);
      console.log(rest);
    }
    foo(1,2,3,4,5);
    //结果
    // a = 1
    // b = 2
    // Array[3,4,5]
    foo(1)
    // 结果
    // a = 1
    // b = undefined
    // Array []

rest 参数只能写在最后,前面用... 标示,从运行结果可知,传入的参数先绑定 a , b, 多余的参数以数组形式交给变量 rest,所以,
不在需要 arguments 我们就获取了全部参数。
如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

  

return 语句
      前面我们讲到了JavaScript引擎有一个在行末自动添加分号的机制,这可能让你栽到return语句的一个大坑:、
        function foo(){
          return {name:'foo'};
        }
        foo(); // {name:'foo'}
      要注意:
      function foo(){
        return: //自动添加了分号,相当于return undefined
        {name:'foo'}; // 这行语句已经没法执行到了。
      }
    所以正确的多行写法是
    function foo(){
        return { // 这里不会自动加分号,因为表示语句尚未结束。
        name:'foo'
      }
    }

变量作用域
  在JavaScript 中,用var 声明的实际上是有作用域的。
如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不该引用该变量。
    ‘use strict':
    function foo(){
      var x = 1;
      x = x +1;
    }
  x = x +2; // RefrenceError 无法在函数体外引用该该变量x
如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:
    'use struct':
    function foo(){
      var x = 1;
      x = x +1;
    }
    function bar (){
      var x= 'A';
      x = x + 'B';
    }

由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:
    'use strict';
    function foo(){
      var x =1;
      function bar(){
      var x = 1;
    function bar(){
      var y= x +1; //bar 可以访问foo 的变量x
    }
    var z = y + 1; //RefernceError! foo 不可以访问bar 的变量y!
    }
  }

如果内部函数和外部函数的变量名重名怎么办?

    'use strict':
    function foo(){
      var x = 1;
      function bar (){
        var x = 'A';
        alert('x in bar() =' + x); // 'A'
      }
    alert('x in foo()=' +x) //1
      bar();
    }

变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
    'use strict';
    function foo(){
      var x='Hello,'+y;
      alert(x);
      var y = 'Bob';
    }
    foo();

对于上述foo()函数,JavaScript引擎看到的代码相当于:
    function foo(){
      var y; // 提升变量y的
      var x = 'Hello' + y;
      alert(x);
      y = 'Bob';
    }

由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量:
      function foo(){
        var x =1, // x 初始化为1
        y = x +1, // y 初始化为2
        z,i; // z和i 为undefined
        // 其他语句
      for(i =0; i<100; i++){
          ...
      }
    }

全局作用域
不在任何函数内定义的变量就具有全局作用域,实际上,JavaScript 默认有一个全局作用域的变量实际上呗绑定到window 的一个属性。
    ‘use strict';
    var sourse = 'Learn JavaScript';
    alert(course); // 'Learn JavaScript';
    alert(window.course); // 'Learn JavaScript'

名字空间
全局变量会绑定到window 上,不同的JavaScript 文件如果使用相同的全局变量,或者定义了相同名字的顶层函数,都会造成
命名冲突,并且很难被发现,
减少冲突的一个方法是把自己的所有的变量和函数全部绑定到一个全局变量中。
    // 唯一的曲剧变量MYAPP
    var MYAPP = {};
    //其他变量:
    MYAPP.name = 'myapp';
    MYAPP.version = 1.0;

    // 其他函数
    MYAPP.foo = function (){
      return 'foo';
    };

把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。
局部作用域
由于JavaScript 的变量作用域实际上是函数内部,我们在for 循环等语句块中是无法定义具有无法定义具有局部作用域的变量的。
    function foo(){
      for(var i = 0; i<100; i++){
        //
    }
    i+=100; // 仍然可以引用变量;
  }

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
    function foo(){
      var sum = 0;
      for(let i=0; i<100;i++){
      sum +=i;
    }
    i +=1;
    }

常量
由于var 和let 声明的变量,如果要声明一个常量,在ES6 之前是不行的,我们通常用全部大写的变量俩表示这是一个常量
不要修改他的值。
    var PI = 3.14;
    ES6标准引入了新的关键字const 来定义常量,const 与 let都具有块级作用域;
    const PI = 3.14;
    PI = 3; // 某些浏览器不报错,但是无效果。
    PI; // 3.14

JavaScript 基础(五) 函数 变量和作用域的更多相关文章

  1. javascript基础(五)函数

    原文http://pij.robinqu.me/ 通过call和apply间接调用函数(改变this) call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定 ...

  2. javascript基础语法备忘录-变量和数据类型

    //javascript基础语法备忘录-变量和数据类型 // 定义变量使用var关键字 后面跟变量名,不要使用eval 和arguments为变量名 var message = "hi&qu ...

  3. class 用法 函数变量的作用域

    函数变量的作用域 1. 函数体内声明的变量 2. 参数中的变量 没有赋值的 function fn(a){} 赋值的,值不是变量 function fn(a=45){} 赋的值为变量 function ...

  4. JavaScript基础03——函数的作用域及变量提升

    1.作用域 作用域,变量在函数内部作用的范围/区域.有函数的地方就有作用域.   2.局部作用域和全局作用域 function fn(){ var a = 1; } console.log(a); / ...

  5. JavaScript基础学习-函数及作用域

    函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容. (一)JavaS ...

  6. (Frontend Newbie)JavaScript基础之函数

    函数可以说是任何一门编程语言的核心概念.要能熟练掌握JavaScript,对于函数及其相关概念的学习是非常重要的一步.本篇从函数的基本知识.执行环境与作用域.闭包.this关键字等方面简单介绍Java ...

  7. 一步步学习javascript基础篇(2):作用域和作用域链

    作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = & ...

  8. javascript基础知识-函数

    1.javascript中函数有两种定义方式: 函数语句定义和表达式定义 //函数有定义 function test(){ console.log("This is a function&q ...

  9. javascript基础知识-命名提前,作用域

    javascript的代码存在命名提前的现象,在这里结合javascript的特殊作用域来解释. 一般很多后台语言,比如C#都是块级作用域,也就是花括号范围内定义的变量,作用域被限制在花括号以内. 而 ...

随机推荐

  1. Sturct类型装箱时会遇到的问题

    Object在拆箱时会在栈空间生成一个临时变量.所以Struct在使用时尽量将内容都声明为readonly为好 [<Struct>] type Point= val mutable X:d ...

  2. artDialog组件应用学习(四)

    一.在对话框自定义操作按钮 预览: html调用代码: var btnArray = [ { value: '同意', callback: function () { this.content('你同 ...

  3. mysql二:库操作

    一.系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信息等 performance_schema: My ...

  4. em和px

    在国内网站中,包括三大门户,以及“引领”中国网站设计潮流的蓝色理想,ChinaUI等都是使用了px作为字体单位.只有百度好歹做了个可调的表率.而 在大洋彼岸,几乎所有的主流站点都使用em作为字体单位, ...

  5. java生成实体类的工具内部是如何实现的(mysql)

    一.认识INFORMATION_SCHEMA数据库 INFORMATION_SCHEMA数据库提供了访问数据库元数据(数据的数据)的方式 该数据库中存放有数据库名.表名,列名.列的数据类型等各种数据 ...

  6. winform中 让 程序 自己重启

    private void button1_Click(object sender, EventArgs e)        {            Application.ExitThread(); ...

  7. 序列化Serializable

    public interface Serializable 类的序列化由实现java.io.Serializable接口的类启用. 不实现此接口的类将不会使任何状态序列化或反序列化. 可序列化类的所有 ...

  8. win10安装mxnet cuda9.0-gpu版

    类似于上一篇文章 Anaconda3.6    python3.6.5   cuda9.0+   cudnn7.0 安装MXNet 1.设置清华源 conda config --prepend cha ...

  9. 爬虫入门之handler与opener(三)

    1 自定义opener opener是 urllib.request.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的模块构建好的opener 但是基本的ur ...

  10. DevExpress控件水印文字提示 z

    ButtonEdit.Properties.NullValuePrompt = "提示"; ButtonEdit.Properties.NullValuePromptShowFor ...