四.一篇文章搞定JavaScript函数(上)

427 阅读6分钟

一.函数描述

  • Function对象 在JavaScript中,每个函数其实都是一个Function对象,因为它们可以像任何其他对象一样具有属性和方法。它们与其他对象的区别在于函数可以被调用。

  • return语句 如果一个函数中没有使用return语句,则它默认返回undefined。要想返回一个特定的值,则函数必须使用 return 语句来指定一个要返回的值。(使用new关键字调用一个构造函数除外)。return的作用和break类似。

  • 实参与形参调用函数时,传递给函数的值被称为函数的实参(值传递),对应位置的函数参数名叫作形参。

function func(形参1,形参2){
    //函数执行代码
}
 
func(实参1,实参2);//调用时传参
  • this指向在函数执行时,this 关键字并不会指向正在运行的函数本身,而是指向调用该函数的对象。所以,如果你想在函数内部获取函数自身的引用,只能使用函数名或者使用arguments.callee属性(严格模式下不可用),如果该函数是一个匿名函数,则你只能使用后者。

二.函数定义

2.1 函数声明与函数表达式

函数声明会在任何代码执行之前先被读取并添加到执行上下文中,这个过程叫函数声明提升

function functionName(){
     //要执行的代码
}

函数表达式必须等到代码执行到这一行,才会在执行上下文中生成函数定义。函数表达式不会提升,所以不能在定义之前调用。

 var myFunction = function name(a, b) {
        return a + b;
      };
      console.log(myFunction("蔡", "徐坤"));

2.2 匿名函数

匿名函数就是没有名称的函数,匿名函数定义了必须要使用。

function() {
        console.log("hello world");
        }
  • 匿名函数的应用场景

1 作为其他函数的参数

 function test(fn) { 
     fn();
 }
 test(function () {
     console.log("hello world");
 });

2 作为其他函数的返回值

    function test() {
        return function () {
            console.log("hello world");
        };
    }
    let fn = test(); 
    fn();

3作为一个立即执行的函数

   (function () {
        console.log("hello world");
    })()

2.3 箭头函数(ES6 中)

      let 函数名称 = (形参列表) =>{
             需要封装的代码;
         }

关于省略

/*4.1 在箭头函数中如果只有一个形参, 那么()可以省略*/
    let say = name => {
              console.log("hello  " + name);
              }
/*4.2在箭头函数中如果{}中只有一句代码, 那么{}也可以省略*/
         let say = name => console.log("hello  " + name);
         say("world");
         //这句话等价于{return  console.log("hello  " + name)}
       
       
         let say = name => {console.log("hello  " + name);}
         say("world");
         //这句话没有return返回值
  • 箭头函数特点:

1.箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。

2.箭头函数没有自己的 arguments 对象,这不一定是件坏事,因为箭头函数可以访问外围函数的 arguments 对象

3.不能通过 new 关键字调用,也没有 new.target 值。

4.由于不能使用 new 调用箭头函数,所以也没有构建原型的需求,于是箭头函数也不存在 prototype 这个属性。

5.没有 super,箭头函数没有原型,故也不能通过 super 来访问原型的属性,所以箭头函数也是没有 super 的。同this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。 >箭头函数不被使用的场景: 不应被用在定义对象的方法上
具有动态上下文的回调函数,也不应使用箭头函数
不能应用在构造函数中
避免在 prototype 上使用
避免在需要 arguments 上使用

2.4 回调函数与递归函数

回调函数是一个作为参数传给另一个 JavaScript 函数的函数。这个回调函数会在传给的函数内部执行。 为啥要回调

  • 客户端 JavaScript 在浏览器中运行,并且浏览器的主进程是单线程事件循环。如果我们尝试在单线程事件循环中执行长时间运行的操作,则会阻止该过程。从技术上讲这是不好的,因为过程在等待操作完成时会停止处理其他事件。

  • 例如,alert 语句被视为浏览器中 javascript 中的阻止代码之一。如果运行 alert,则在关闭 alert 对话框窗口之前,你将无法在浏览器中进行任何交互。为了防止阻塞长时间运行的操作,我们使用了回调。
    递归函数

递归函数就是在函数中自己调用自己, 我们就称之为递归函数
递归函数在一定程度上可以实现循环的功能
每次调用递归函数都会开辟一块新的存储空间, 所以性能不是很好

    function login() {
        // 1.接收用户输入的密码
        let pwd = prompt("请输入密码");
        // 2.判断密码是否正确
        if(pwd !== "123456"){
            login();
        }
        // 3.输出欢迎回来
        alert("欢迎回来");
    }
    login();

三.函数内部

3.1 函数的arguments对象和参数

3.1.1 函数的arguments对象

arguments,代表所有实参的集合。通过下标获取参数的每一位;通过length获取实参的个数;
集合是类数组,可以使用下标,但是没有数组中的各种方法。

//arguments 代表所有实参的集合(类数组),可以通过下标获取各个实参,通过length获取集合长度
      function args() {
        console.log(arguments);
        for (var i = 0; i < arguments.length; i++) {
          console.log(arguments[i]);
        }
      }
      args(23, 45, 999, 10.9, "蔡徐坤", "后面还有"); 
3.1.2 函数的参数(ES6)
  • 除了普通参数外,Es6新增了两个新的参数:默认参数和剩余参数。 默认参数

1.在 ES6 之前可以通过逻辑运算符来给形参指定默认值
格式: 条件 A || 条件 B
如果条件 A 成立, 那么就返回条件 A
如果条件 A 不成立, 无论条件 B 是否成立, 都会返回条件 B

      function getSum(a, b) {
        a = a || "你好";
        b = b || "JavaScript";
        console.log(a, b);
      }
      getSum(); //你好 JavaScript
      getSum("hello", "world");//hello world

2.从 ES6 开始, 可以直接在形参后面通过=指定默认值

      function getSum(a = "你好", b = "前端") {
        console.log(a, b);
      }
      getSum(); //你好 前端
      getSum("hello", "world"); //hello world

注意点: ES6开始的默认值还可以从其它的函数中获取

      function getSum(a = "音乐天才", b = getDefault()) {
       console.log(a, b);
     }
     getSum();//音乐天才 蔡徐坤
     function getDefault() {
       return "蔡徐坤";
     }

剩余参数

剩余参数语法允许将不确定数量的参数表示为数组。

      function name(a, b, c, ...arr) {
        console.log(a, b, c, arr); //1 2 3 [4, 5,6,7,78]
      }
      name(1, 2, 3, 4, 5, 6, 7, 78);

3.2 函数的this(详情见后面this指向的总结)

this取值是在函数执行是确定的
普通函数 ://window
普通函数的call方法fn.call({name:1})://{name:1}
普通函数的bind方法fn.bind({name:1})://{name:1}
         const fn2= fn1.bind({name:1})
          fn2()//bind会返回一个新的函数执行
对象的方法执行,this指向该对象 obj.say()
setTimeout(function(){console.log(this)},2000)function里面的this指向window
setTimeout(()=>{},2000)指向外面的对象
class中的指向实例本身