JavaScript 基础(五) 函数 变量和作用域

函数定义和调用
   定义函数,在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

时间: 2024-10-24 18:10:44

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

js基础--javascript基础概念之变量与作用域

js基础--javascript基础概念之变量.作用域 javascript按照ECMA-262 的定义,变量与其他语言变量有所不同.js变量时松散的,不需要事先定义变量类型的.这使得他只是一个保存特定值的一个名称.变量与其数据类型可以在脚本的生命周期内改变. 还有明白几点: JavaScript的变量作用域是基于其特有的作用域链的,JavaScript没有块级作用域. 基本类型和引用类型的值 ECMAScript 的变量有两种不同的数据类型:分别是 基本数据类型值 和 引用类型值 : 基本数据

javascript学习日记之变量的作用域

``` 很显然第一个弹出框并没有如我所想弹出的global而是undefined 这是为什么呢? 其实由于函数作用域特性 函数域始终优于全局域 同名的局部变量会覆盖掉全局变量 而第一次调用alert的时候scope还没正式定义 所以为undefined 以上代码可以理解为: ``` function f(){ var scope; alert(scope); var scope ="local"; alert(scope); }; f(); //等价与函数内变量的声明'提前'至函数体顶

JavaScript基础知识(变量/引用/转换/函数)

-------------------------------------------- 变量 全局变量:在函数体外声明,全局可以使用 局部变量:通过关键字var来声明 变量类型 1 <script type="text/javascript"> 2 var a; 3 // 十进制 4 a = 1; 5 a = 1.2; 6 a = -23; 7 a = .23e4; 8 a = 3e-2; 9 // 十六进制 10 a = 0xABCDE; 11 a = 0Xff; 12

javascript 闭包与函数变量作用域

浏览器事件循环工作原理 浏览器有一个事件循环用于检查事件队列,处理延时的事件.UI事件(例如:点击,滚动等),ajax回调,以及提供给setTimeout()和setInterval()的回调,都会依次被事件循环处理. 因此,当调用setTimeout()函数时,即使延迟的时间被设置为0,提供的回调也会被排队 回调会呆在队列中,直到指定的时间用完后,引擎开始执行动作(如果它当前不执行其他动作) 因此,即使setTimeout()回调被延迟0ms,它仍然会被排队,并且直到函数中其他非延迟的语句被执

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

作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = "李四"; } alert(str);//弹出值是? 问题二. function add(num1, num2) { var sum = num1 + num2; } add(1,2); alert(sum) //弹出值是? 问题三. var str1 = "张三"; v

JavaScript学习笔记—— 4. 变量、作用域和内存问题

ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值,其中基本类型值是简单的数据段,而引用类型值指的是那些可能由多个值构成的对象: 对于5种基本类型数据:undefined, null,boolean,number和string,采用按值访问,因为可以操作保存在变量中的实际的值: 对于引用类型的值而言,JavaScript并不能直接访问内存中的位置,也就是说不能直接操作对象的内存空间,在操作对象时,实际上是在操作对象的引用而非实际的对象. 在从一个变量向另一个变量复制基本

JavaScript 基础回顾——函数

在JavaScript中,函数也是一种数据类型,属于 function 类型,所以使用Function关键字标识函数名.函数可以在大括号内编写代码并且被调用,作为其他函数的参数或者对象的属性值. 1.命名函数的创建和使用 <script type="text/javascript"> function 函数名 (形参列表) { //执行语句 return 返回值; } </script> 2.函数的参数和返回值 与C#,java等语言相比,JavaScript函

JavaScript基础之函数和变量作用域

函数:封装一项任务的步骤清单的代码段,再起一个名字 ( js中函数也是一个引用类型的对象,函数名其实也是引用函数对象的普通变量.) 函数对象:内存中专门存储一个函数定义的存储空间 函数定义的存储位置在window之外. 何时使用:一项任务可能反复使用时,就仅需要在函数中封装一次,反复调用函数即可. 如何声明函数: function 函数名([参数1,参数2,...]){ 步骤清单 return 返回值 } 参数:专门接受函数调用时,必要数据的变量 如何使用参数:在函数内,参数变量的使用和普通变量

Python基础(五):变量、函数和类

现在的编程思想的核心都是面向对象,而变量.函数和类就是面向对象的基础, 类 类是一些具有相似属性和功能的对象集合,如果我们把类比作制作手机的模具,那么通过这个模具,我们可以生产出大批量具有相同功能和属性的手机. 定义类的关键字:class 所有的class默认继承于object,我们来写一个手机类, class Phone(object): pass 注意:括号里的object可以省略. 那么如何通过类创建一个实例对象呢?如下: phone_01 = Phone() 函数 函数是一个功能点的具体