函数进阶(箭头函数、默认参数)(前端进阶1.4)

265 阅读4分钟

函数参数的解构赋值

function foo([a,b]) { 
  console.log(a+b); // 3 
} 
foo([1,2]); 

function bar({c,d}) { 
  console.log(c+d); // 7 
} 
bar({c:3,d:4}); 

函数默认参数

基本方式

function foo(a,b=10) { 
  console.log(a+b); // 1+10=11 => 11 
} 
foo(1); 

function bar([a,b=10]) { 
  console.log(a+b); // 3+10=13 => 13 
} 
bar([3]);

function fn({a,b=10}) { 
  console.log(a+b); // 5+10=15 => 15 
} 
fn({a:5}); 

可以预设实参

function bar([a,b=10] = [20]) { 
  console.log(a+b); // 20+10=30 => 30 
} 
bar(); 

function fn({a,b=10} = {a:20}) { 
  console.log(a+b); // 20+10=30 => 30 
} 
fn(); 

预设实参的覆盖

但如果传入实参,那么就会把预设的覆盖。

function bar([a,b=10] = [20]) { 
  console.log(a+b); 
} 
bar([100]); // 100+10 => 110 
bar([100, 200]); // 100+200 => 300 

function fn({a,b=10} = {a:20}) { 
  console.log(a+b); 
} 
fn({a:100}); // 100+10 => 110 
fn({a:100,b:200}); // 100+200 => 300 

默认值可以是函数

function getB() {
  return 10
}; 
function foo(a,b=getB()) { 
  console.log(a+b); // 1+10=11 => 11 
} 
foo(1); 

箭头函数

语法:参数=>函数体

  • 单行语句可以省略花括号,如果还是return语句,还可以省略return关键字。
  • 多行语句不可以省略花括号。
  • 一个参数可以省略圆括号,多个参数不可以省略圆括号。
// 传统写法(无参数) 
let fn = function() {return 1;} 
// 箭头函数写法 
let fn = ()=>(1); 
let fn = ()=>1; 

// 传统写法(一个参数) 
let bar = function(a) {return 2}; 
// 箭头函数写法 
let bar = (a)=>2; 
let bar = a=>2; 

// 传统写法(多个参数) 
let fn = function(a,b) {return a+b}; 
// 箭头函数写法 
let fn = (a,b)=>a+b; 

// 多行语句时不可省略花括号 
let br = function(a,b) { 
  let res = a+b; 
  return res; 
} 
let br = (a,b)=>{ 
  let res = a+b; 
  return res; 
} 

箭头函数的特点

箭头函数内的this固定化

函数体内的this对象是固定的,就是定义时所在的对象,而不是使用时所在的对象。

  • 普通函数内的this情境
var id = 10; 
let obj = { 
  id: 15, 
  fn: function(){ 
	setTimeout(function(){ 
	  alert(this.id); // 10 
	},1000)
  } 
} 
obj.fn(); 

分析: 1秒后执行window.setTimeout()this 指向 window,因此返回的结果是全局下的id:10。

如果想要获取obj内的id,一般采用_this = this的办法。

var id = 10; 
let obj = { 
  id: 15, 
  fn: function(){ 
    _this = this; // 调用后,这里的this指向obj 
    setTimeout(function(){ 
      alert(_this.id); // 15 
    },1000) 
  } 
} 
obj.fn(); 
  • 箭头函数内的this情境(1)
var id = 10; 
  let obj = { 
  id: 15, 
  fn: function(){ 
    setTimeout(()=>{ 
      alert(this.id); 
    },1000) 
  } 
} 
obj.fn(); // 15 
obj.fn.call({id:123}); // 123 

分析: setTimeout()中用了箭头函数,因此箭头函数内的 this 对象就固定在父级作用域下的this上(这里就是函数fn)。

也就是说,fn函数内的this指向了谁,箭头函数的this就指向了谁。

当被obj调用时,fn函数的this指向了obj,所以返回obj下的id:15;当被对象{id:123}调用时,fn函数的this指向了{id:123},所以返回该对象下的id:123。

  • 箭头函数内的this情境(2)
var id = 10; 
let obj = { 
  id: 15, 
  fn: ()=>{ 
  	setTimeout(()=>{ alert(this.id); },1000) 
  } 
} 
obj.fn(); // 10 
obj.fn.call({id:123}); // 10 

分析: 当obj下的fn方法也用箭头函数,那么就会沿着作用域链往上找它的父级作用域的this,这里找到的是全局window。 于是this就固定在了window上,不管谁去调用它,它都只会返回window下的id:10

箭头函数没有arguments对象

普通函数在初始化的过程中,会产生一个 arguments 对象用来保存实参。 但是在箭头函数中是不存在的,如果要使用实参列表,那么用 rest 参数来代替。

// 普通函数
let fn = function(a,b,c) {
      console.log(arguments);
}
fn(1,2,3); //Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]

// 箭头函数let 
bn = (...args)=> {
      console.log(args);
}
bn(1,2,3); //[1, 2, 3]

箭头函数不可以用new实例化

let Person = (name)=> {
      this.name = name;
}
let p = new Person('mm'); // TypeError: Person is not a constructor

箭头函数不可以使用yield命令

不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

箭头函数的使用场景

  • 当我们要维护一个this上下文环境时,就可以用箭头函数
var id = 10;let obj = {
    id: 15,
    fn: function(){
        setTimeout(()=>{
              alert(this.id); 
         },1000)
    }
}
obj.fn(); // 15
  • 定义对象方法,且要用到this时,不要用箭头函数!
let person = {
    name: 'mm',
    say: ()=>{
        console.log(this.name); // 'gg' ,this 指向 Window
    }
}
var name = 'gg';
person.say();
  • 监听DOM事件时,不要用箭头函数!
let box = document.getElementById('box');
box.addEventListener('click', function(){
    if(this.classList!='red') {
          this.classList = 'red';
    }else {
          this.classList = 'green';
    }
    console.log(this); // box
});

box.addEventListener('click', ()=>{
    if(this.classList!='red') {
          this.classList = 'red';
    }else {
          this.classList = 'green';
    }
    console.log(this); // window
})

总结

  1. 函数参数也可以解构赋值。
  2. 函数参数可以设置默认值,可以预设实参。
  3. 函数参数的默认值可以是函数调用。
  4. 箭头函数的语法:参数=>函数体
  5. 箭头函数的this是固定的,指向了父级作用域的this。
  6. 箭头函数没有arguments,可以用rest参数代替。
  7. 箭头函数不可以new实例化。
  8. 箭头函数不可以使用yield命令