06.函数(function)

一.函数的介绍

函数:就是将一些功能或语句进行封装,在需要的时候,通过调用的形式,执行这些语句。

  • 函数也是一个对象。
  • 使用typeof( )函数检查一个函数对象时,会返回function
  • 函数的使用包含两个步骤
    • 定义函数 —— 封装 独立的功能
    • 调用函数 —— 享受 封装 的成果

1.2 定义函数

  • 定义函数的过程是对某些功能的封装过程
  • 在之后的开发中, 我们会根据自己的需求定义很多自己的函数

1.3 调用函数

  • 调用函数是让已存在的函数为我们所用
  • 这些函数可以是刚刚自己封装好的某个功能函数
  • 当然, 我们也可以去使用JavaScript或者其他三方库定义好的函数.(拿来主义)

1.4 函数的作用

  • ==将大量重复的语句写在函数里,以后使用这些语句的时候,可以直接调用函数,避免重复劳动。==
  • ==简化编程,让编程模块化。==

1.5 函数的例子

  • 计算1+2+3+4+5+6+7......+100?

  • var sum=0;
    function sumN(){
        for(var i=1;i<=100;i++){
          sum+=i;  
        }
        return sum;
    }
    console.log(sumN(100));//5050
    

二.函数的定义和调用

2.1 函数的定义方式

2.1.1 使用==函数声明==来调用一个函数。

  1. 语法:

       function 函数名([形参1,形参2,....]){//形参是可选的,备注:语法中的中括号表示“可选”
                   语句;
       } 
    
  2. 特点

    1. function:是一个关键字,中文是“函数”,"功能".

    2. 函数名字:命名规定和变量的规定一样。==只能是字母、数字、下划线、$,不能数字开头==

    3. 参数:可选。

    4. 大括号里面,是这个函数的语句。

    5. 方法定义是,形参的类型不用写,返回值类型也不写。

    6. 方法是一个对象,如果定义名称相同的方法,会覆盖

    7. 在JS中,方法的调用只与方法的名称有关,和参数列表无关

    8. 在方法声明中有一个隐藏的内置对象(数组),arguments,封装所有的实际参数

2.2.2 使用==函数表达式==来创建一个函数.

  • 之前定义的函数被称之为函数的声明,除了声明之外,还有其他函数形式:
    • 函数表达式:==匿名函数表达式和命名函数表达式==
  • 函数的name属性:所有的函数都有一个name属性用于获取函数的名称
    • *函数声明方式的name属性:函数名
    • 命名函数表达式的name属性:函数名
    • 匿名函数表达式的name属性:变量名
image-20210515023900311

语法:

  var 函数名=function([形参1,形参2,....]){//形参是可选的
              语句;
  } 



  
    
    
    
    函数表达式写法
  

  

  
  


2.2.3 立即执行函数

 (function([形参1,形参2,....]){//形参是可选的
             语句;
           } )()
  • 类比函数表达式:==( 这个括号里面就相当于一个匿名函数)(此括号里就是传递形参)==



  
  
  函数声明和调用
  


  


2.2 函数形参和实参

function add(a,b){//a,b就是形式参数
     return a+b;
   }
   //下面的add里面的为实参
   console.log(add(10,20));//30
   console.log(add("10","20"));//1020
   console.log(add("hello","World"));//helloWorld
   console.log(add(1,2,3,4,5));//3,只有两个参数,后面多余的参数无效

2.2.1 形参

  • 可以在函数的()中来指定一个或多个形参
  • 多个形参之间使用逗号隔开,声明形参就相当于在函数的内部声明了对应的变量,但是并不赋值

2.2.2 实参

  • 在调用函数时,可以在()中指定实参
  • 实参将会赋值给函数中对应的形参
2.2.2.1 实参的类型
  • 函数的实参可以是任意的数据类型
  • 用函数时解析器不会检查实参的类型,所以需要注意,是否有可能需要对参数进行类型的额检查
2.2.2.2 实参的数量

注意:JS里不会对函数实际传入的参数进行检测。可以传值,也可以不传值,也可以任意多个值

调用函数时,解析器也不会检查实参的数量:

  • ==多余实参不会被赋值==

  • ==如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined.==

  • 例如:

    image-20201026112537049

2.2.3 arguments

可以通过arguments获取所有实际传递的参数

案例:

 var total=0;
   var sum=function(){
       console.log(arguments);
       for(var i=0;i
image-20201026114145857

三.函数返回值

function sum(a,b){
          return a+b;
     }
     sum(10,20);

return的作用是结束方法.

注意:

  • return后的值将会作为函数的执行结果,可以定义一个变量,来接收该结果

  • 在函数中的return后的语句都不会执行(函数在执行完return语句之后停止并立即退出)

  • 如果return语句后不跟任何值,就相当于返回一个undefined

  • 如果函数中不写return,则也会返回undefined

  • 返回值可以是任意的数据类型,可以是对象,也可以是函数。

    • //函数的返回值可以是函数
           function sum(a,b){
             var add=function(){
                return a+b;
             }
             return add;//返回的整个add函数
             return add();//30,这是函数的调用
           }
           console.log(sum(10,20));
      

四.==函数名、函数体和函数加载问题(重要)==

  • 函数名==整个函数

    • //函数名其实就是函数本省
           var add=function(a,b){
             return a+b;
           }
           console.log(add)==console.log(function(a,b){
             return a+b;
           });
      
  • 我们知道,当我们在调用一个函数时,通常使用函数()这种格式;但此时,我们是使用函数这种格式,它的作用相当于整个函数。

  • 函数的加载问题:JS加载函数时,只加载函数名,所以如果像使用内部的成员变量,需要调用函数。

五. ==fn( )和fn的区别【重要】==

  • fn( ):调用函数,相当于获取了函数的返回值。
  • fn:函数对象,相当于直接获取了函数对象

六. 立即执行函数

  • 什么是立即执行函数?

    • 专业名字:Immediately-Invoked Function Expression(IIFE 立即调用函数表达式)
  • 表达的含义是一个函数定义完后被立即执行

    • 第一部分是定义了一个匿名函数,这个函数有自己独立的执行上下文环境。

    • 第二部分是后面的(),表示这个函数被执行了

      image-20210515020209670
  • 这个东西有什么用?

    • ==会创建一个独立的执行上下文环境,可以避免外界访问或修改内部的变量,也避免了对内部变量的修改==
    image-20210515022804280

6.1 立即执行函数其他写法

  • 立即执行函数必须是一个表达式,不能是函数声明:

    • 下面的这种写法会报错,因为是一个函数声明,不是一个函数表达式
    • 当圆括号出现在匿名函数的末尾想要调用函数时,它会默认将函数当成是函数声明。
    image-20210515022902350
  • 当圆括号包裹函数时,它会默认将函数作为表达式去解析,而不是函数声明。
    image-20210515023031129
  • 下面是一个函数表达式,所以可以执行
    image-20210515023106491
  • 声明式函数立即执行函数的两种写法

    • (function () {
            console.log("我是声明式函数");
      })()
      
    •  (function () {
            console.log("我是声明式函数");
       }());
      

立即执行函数如下:

//立即执行函数
var result=(function(a,b){
  return a+b;  
})(10,20);
console.log(result);

七. 方法

函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存,那么我们成为这个函数是这个对象的方法。调用这个函数就说调用对象的方法(method).相比于方法,它只是名称上的区别,并没有其他的区别。

函数举例:

//调用函数
fn();

方法举例:

//调用方法
obj.fn();

我们可以这样说,如果直接使用fn(),那就说明是函数调用。如果是发现XX.fn()这种方式,那就说明是方法调用

八.this关键字

解析器在调用函数每次都会向函数内部传递一个硬汉年的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称之为函数执行的上下文对象。

==根据函数的调用方式不同,this会指向不同的对象:==

  • 1.以函数的形式调用时,this永远是window。比如fun( );相当于Window.fun( );

  • 2.以方法的形式调用时,this是调用方法的那个对象

  • 3.以构造函数的形式调用时,this是新创建的那个对象

  • 4.使用call和apply调用时,this是指定的那个对象

    举例:




  
  
  Document



  


8.1 改变this的指向

格式:

修改this的指针:
1.函数名.call(对象);
2.函数名.apply(对象);
3.bind();
  • 改变this指向有三种方式:apply,call,bind

  • apply和call的不同点在于传值不同:apply传值使用的是数组,call是直接写就可以

  • /* 
    修改this的指针:
    1.函数名.call(对象);
    2.函数名.apply(对象);
    3.bind();
     */
    var Student={
      name:"jason",
      like:function(){
       console.log(this);
       console.log(this.name+"钓鱼");
      }
    }
    //Student.like();//this指向Student对象
    var fn=Student.like;
    fn();//this指向window
    console.log(window.fn===fn);//true
    //改变this的指针
    var teacher={
      name:"老王",
    }
    //call;
    //fn.call(teacher);
    fn.apply(teacher)
    
  • image-20201027191615250

==apply,call,bind的使用案例:==




  
  
  Document
  


  


image-20201027191933284

九.arguments

在调用函数时,浏览器每次都会传递两个隐含的参数:

  • 1.函数的上下文对象 this
  • 2.封装实参的对象 arguments

例如:

var abc=function(){
   console.log(arguments);
   console.log(typeof arguments);
 }
 abc();
image-20201027134011814

arguments是一个类数组对象,它可以通过索引来操作数据,也可以获取长度。

arguments代表的是实参。在函数调用时,我们所传递的实参都会在arguments中保存,它只能在函数中使用

4.1 返回函数实参的个数:arguments.length

arguments.length可以用来获取实参的长度。

4.2 返回正在执行的函数:arguments.callee

arguments里面有一个属性叫callee,这个属性对应的函数对象,就是当前正在指向的函数对象。

在使用函数递归调用时,推荐使用arguments.callee代替函数名本身。

4.3 arguments可以修改元素

之所以说arguments是伪数组,是因为:arguments可以修改元素,但不能改变元素数组的长短。

举例:

/* 
函数的arguments对象
 */
 var abc=function(a,b,c,d){
   console.log(arguments);
   console.log(typeof arguments);//Object
   //长度
   console.log(arguments.length);//4
   console.log(arguments.callee);//
   //修改元素
   if(arguments[0]){
      arguments[0]=100;
   }
   console.log(arguments);
   console.log(a);//100,同时也修改了实参
 }
 abc(1,2,3,4);
image-20201027141502286

3.1 Function:函数(方法)对象

      //当形式参数与实际参数长度不一致时
      function fun4(a,b,c){
          //document.write(a+b+c);
          document.write(c);//当实际参数长度小于形式参数长时,形式参数默认为undefined类型
      }
      //fun4(1,2);
      
      function fun5(a,b){
         document.write(arguments[2]);//当实际参数长度大于形式参数时,在方法声明里内置对象(数组),arguments,封装所有实际参数
      }
      //fun5(1,2,3);
   ```
   //例:求不定长度的和
   
   function sum(){
       var total=0;//注意这里一定后面赋值0要加上
       for (var i = 0; i 

十.函数练习题

10.1 练习一:实现一个加法计算器

 function addCalculate() {
      var total = 0;
      for (var i = 0; i < arguments.length; i++) {
        total += arguments[i];
      }
      return total;
    }
    console.log(addCalculate(10, 30, 60));

10.2 练习二:定义一个函数,传入宽高,计算矩形区域的面积


10.3 练习三:定义一个函数,传入半径,计算圆形的面积


10.4 练习四:定义一个函数,传入n(n为正整数),计算1~n数字的和


10.5 练习五:定义一个函数,传入一个数组,对数组进行翻转


10.6 练习六:定义一个函数,传入一个数字数组,对数组中的数字进行排序


10.7 练习七:定义一个函数,传入一个数字,求对应的菲波那切数列


image-20210514160648409
image-20210514160656174

斐波那契数列递归调用
  

十二.函数的调用栈

image-20210514174712397

十三.全局变量和局部变量

  • 在JavaScript(ES5之前)中没有块级作用域的概念,但是函数可以定义自己的作用域。
  • 什么是全局变量和局部变量?
    • ==定义在函数内部的变量,被称之为局部变量。==
    • ==定义在script标签中的变量,被称之为全局变量。==
  • 在函数中,访问变量的顺序是什么呢?
    • ==优先访问自己函数中的变量,没有找到时,在全局中访问。==
image-20210515002132715



  
    
    
    
    变量作用域
  

  

  
  


十四.值传递和引用传递

1.在 JavaScript 中数据类型可以分为两类:

  • 原始数据类型值 primitive type,比如Undefined,Null,Boolean,Number,String。
  • 引用类型值,也就是对象类型 Object type,比如Object,Array,Function,Date等。

2.声明变量时不同的内存分配

  • 原始值:存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。这是因为这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 – 栈中。这样存储便于迅速查寻变量的值。
  • 引用值:存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存地址。这是因为:引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。

14.1 按值传递

 //1.值传递
     function test(n) {
      n = "kobe";
    }
    var name = 'why';
    test(name);
    console.log(name); //why 
image-20210515180954318

14.2 按引用传递

 //2.引用传递
    function func(arr) {
      arr[0] = "jason";
    }
    var array = [1, 2, 3];
    func(array)
    console.log(array); //['jason',2,3]
image-20210515182559155

你可能感兴趣的:(06.函数(function))