2.函数

函数和方法的区别:

  • 函数:是可以执行的JavaScript代码块,由JavaScript程序定义或JavaScript实现预定义。
  • 方法:是通过对象调用的JavaScript函数。方法也是函数,只是比 较特殊的函数。

实际比较起来,函数和方法差别不大。

2.1 定义函数

以定义绝对值函数为例:

// 定义方法一
function abs(x){
        if(x>0){
            return x;
        }else{
            return -x;
        }
    }
// 定义方法二
var abs = function(x){
        if(x>0){
            return x;
        }else{
            return -x;
        }
    }
// 调用方法
> abs(10)
> abs(-5)

JavaScript 可以传任意个参数也可以不传参数!JS 不会验证传递进来的参数个数是否等于函数定义的参数个数!!

> abs()
NaN  // 不传参数也不会报错,返回NaN
> abs(-1, 2, -3, 4, -5)
1    // 传多个参数时,只作用于第一个参数

参数问题

参数传进来是否存在的问题?如果不存在参数,如何规避?

手动抛出异常!!

var abs = function(x){
        if (typeof x !== 'number'){
            throw 'NaN';
        }
        if(x>0){
            return x;
        }else{
            return -x;
        }
    }

arguments 类数组对象

是一个JavaScript免费赠送的关键字,JS把所有传进来的参数都存储在arguments 里面,以数组的形式。

function show() {
        console.log(arguments);
    }

> show(1, 2, 3, 4, 5)

注:arguments对象不是一个数组。只是类似于array,但除了length属性和索引元素之外没有任何array属性。

// 参数的相加(无论传入多少个参数都可以)
function add() {
        var len = arguments.length,
            sum = 0;
        for(;len--;){
            sum += arguments[len];
        }
        return sum;
    }

由于 arguments 包含传进来的所有参数,当我们只想要对多余参数进行操作时怎么办?

rest (ES6)获取除了已经定义的参数之外的所有参数

function show(a, b, ...rest) {
        console.log('a+>'+a);
        console.log('b+>'+b);
        console.log(rest);
    }
// 调用
> show(1, 2, 3, 4, 5, 6)
a+>1
b+>2
(5) [3, 4, 5, 6, 7]

2.2 变量的作用域

在JavaScript中, var定义的变量实际是有作用域的。

  • 在函数体中声明的变量,函数体外不可以使用(报错)
function show() {
        var x =1;
        x = x+1;
    }
    x = x+2;  // 报错
  • 如果两个函数使用了相同的变量名,只要在函数内部就不冲突
// 内部函数变量重名,没有影响
function aaa() {
        var x = 1;
        x = x + 1;
    }
    function bbb() {
        var x = 'A';
        x = x + 1;
    }

// 内部函数可以访问内部函数的成员,反之不行
function aa() {
        var x = 1;
        function bb() {
            var y = x+1;
        }
        z = y +1;    // aa() 报错: y is not defined
    }
  • 假设内部函数变量与外部函数重名
function aa() {
        var x = 1;
        function bb() {
            var x = 'A'
            console.log('inner>'+x);
        }
        console.log('outer>'+x);
        bb()
    }
    aa()

// 结果
outer>1
inner>A

总结:在 JavaScript 中,函数查找会从自身开始,由内向外查找。假设函数内部存在这个同名变量,则内部函数会屏蔽外部函数的变量。

提升变量的作用域

JavaScript 执行引擎自动提升变量声明,但是不会提升变量的赋值

function aa() {
      var x = 'x' + y;
      console.log(x);
      var y = 'y';
  }
aa()
// 结果:xundefined

养成规范1:所有变量的申明和赋值放在代码头部!!先申明后赋值最后调用!!!

全局变量

// 全局变量
var x = 1; 
// 默认所有的全局变量都会自动绑定带window对象中
 var x = 'aaa';
    alert(x);
    alert(window.x); // 弹出两次aaa

JavaScript 实际上只有一个全局作用域,任何变量(函数也可视为变量)加入没有在函数范围内找到,就会向外查找;如果函数外也没有找到,就会报错:Reference Error。

由于所有变量都会自动绑定到window上。容易出现不同的JavaScript文件使用了相同的全局变量,导致冲突。

规范2:把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名的冲突,避免绑定到window上

var Only = {};
   Only.name = 'cianbei';
   Only.add = function (a,b) {
       return a+b;
   }

> Only.name
"cianbei"
> Only.add(1,2)
3

局部作用域 建议使用 let 定义局部变量

// var定义全局变量
function show() {
       for(var i=0; i<100; i++){
           console.log(i)
       }
       console.log(i+1);  // 打印101
   }
// let定义局部变量
function show() {
       for(let i=0; i<100; i++){
           console.log(i)
       }
       console.log(i+1);    // 报错:i is not defined
   }

常量 const

const pi = 3.14; 
   pi = 3.15;   // 重新赋值会报错

2.3 方法

定义方法

对象只有两个东西:属性和方法。把函数放进对象里就是方法!!

var show = {
       // 属性
       name: 'xiuer',
       birth: 2005,
       // 方法
       age: function () {
           var now = new Date().getFullYear()
           return now-this.birth;
       }
   }

> show.name
"xiuer"
> show.birth
2005
> show.age
ƒ () {
           var now = new Date().getFullYear()
           return now-this.birth;
       }
> show.age()   // 调用一定要加括号()
16

this 默认指向调用他所在方法的那个对象

function getage() {
        var now = new Date().getFullYear();
        return now-this.birth;
    }

   var show = {
       name: 'xiuer',
       birth: 2005,
       age: getage
    }
   
> show.age()
16
> getage()
NaN
> getage.apply(show,[])   // apply 控制 this 指向
16