ES6(4)函数

189 阅读6分钟

默认参数

解决问题:

  1. 必填项不填报错

  2. 有些参数没有传参时给默认值

ES6 之前,不能直接为函数的参数指定默认值,ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面

//es5   
function ajax(url,method,dataType) {
    if(typeof url === 'undefined') throw Error('url不能为空');
    method=method?method:'GET';
}

//es6
function ajax(url=Error('url不能为空'),method='GET',dataType='json') {
    console.log(url);
    console.log(method);
    console.log(dataType);
}
ajax('/user')
/*
/user
GET
json
*/
//上面的写法编译为es5
function ajax() {
  var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Error('url不能为空');
  var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'GET';
  var dataType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'json';
  console.log(url);
  console.log(method);
  console.log(dataType);
}

1、参数变量是默认声明的,所以不能用let或const再次声明

下面代码中,参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。

function foo(x = 5) {
  let x = 1; // 报错
  const x = 2; // 报错
}

2、使用参数默认值时,函数不能有同名参数

// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}

3、参数默认值不是传值的,而是每次都重新计算默认值表达式的值

let x = 99;
function foo(p = x + 1) {
  console.log(p);
}

foo() // 100

x = 100;
foo() // 101

解构赋值的运用

基础版:不传会报错

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // 报错 TypeError: Cannot read property 'x' of undefined

完整版:不传也不报错

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

foo() // undefined 5

完整版的两种写法:(一般用写法一)

写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值

写法二函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值

// 写法一
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]

// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

非尾部的参数设置默认值,这个参数是没法省略的

有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非在不想传参的参数的对应位置显式输入undefined(传null不行)

参数对应undefined,会触发默认值,null不会触发默认值

// 例一
function f(x = 1, y) {
  return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]

// 例二
function f(x, y = 5, z) {
  return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
function foo(x = 5, y = 6) {
  console.log(x, y);
}

foo(undefined, null)
// 5 null

剩余运算符运用

//arguments利用 剩余运算符
function fn(context,...arg){
    //获取传递值中的第一个和剩下的
    console.log(context)
    console.log(arg)   //arg 是数组 ,而arguments是类数组

}
var obj={name:'aaa'}
fn(obj,10,20)

展开运算符运用

let arr=[12,23,34];
let fn=function(a,b,c){
    console.log(a,b,c)
}
//fn(arr)    //arr  undefined   undefined
fn(...arr)    //=>fn(12,23,34)  => 打印 12 23  34

箭头函数

1、箭头函数中没有arguments,可以使用剩余运算符(...arg)代替而且arg是一个数组

箭头函数中没有执行主体,就是没有this

2、在箭头函数中,this固定的,不会变的

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

4、在箭头函数中的this都是直接找上下文中的this来使用(上级作用域中的this,而非上级代码块{}、或者说不是上级json对象)

箭头函数中的this跟执行的时候前面有没有点没关系了,因为他没有执行主体,在箭头函数中的this都是直接找上下文中的this来使用(上级作用域中的this,而非上级代码块{}、或者说不是上级json对象)

5、不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

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

let fn=(x,y)=>{

}
fn(10,20)

7、只有一个形参可以省略小括号

let fn= x =>{

}
fn(10)

8、如果函数体中只有一句操作,并且是return 的,我们可以省略大括号和return

箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。

let fn= function(x,y){
	return x+y;
}
fn(10,20)

let fn=(x,y)=>x+y;
console.log(fn(10,20))  //30

let fn=(x=0,y=0)=>x+y;    //给形参设置默认值
console.log(fn(10,20))  //30
let fn= x => y => x+y
/*
相当于   let fn= x =>( y => x+y)
*/
let fn=function(x){
	return function(y){
		return  x+y;
	}
}

let fn =(...arg)=>{
	//arg就是全部参数,并且arg为数组
}
fn(10,20,30)

9、如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

// 报错
let getTempItem = id => { id: id, name: "Temp" };

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
//在箭头函数中的this都是直接找上下文中的this来使用(上级作用域中的this,而非上级代码块{}、或者说不是上级json对象)
let obj={
    name:'aaa',
    fn:()=>{
        console.log(this.name)
    }
}
let obj2={
    name:'bbb',
    fn:obj.fn
}
obj.fn();       //undefined
obj2.fn();      //undefined

例题

例1、让obj.fn的this变为window

let obj={
	fn:(function(){
		//this:window
		return function(){
			console.log(this)
		}
	})()
}
obj.fn();      //this:obj

//1、
obj.fn.call(window)


//2、
let obj={
	fn:(function(){
		//this:window
		var _this=this;
		return function(){
			console.log(_this)
		}
	})()
}

//3、
let obj={
	fn:(function(){
		//this:window
		return ()=>{
			//this:window
			console.log(this)
		}
	})()
}
obj.fn();      //this:window

例2、

考点:自执行函数中的this 为window

let obj={
    name:'aaa',
    fn:function(){
        var self=this;
        console.log(this.name);
        console.log(self.name);
        ~function() {
            console.log(this.name)
            console.log(self.name)
        }()
    }
}
obj.fn()  


//aaa
//aaa
//undefined
//aaa

考点:箭头函数中的this是定义时所在作用域的this

let obj={
    name:'aaa',
    fn:function(){
        var self=this;
        console.log(this.name);
        console.log(self.name);
        (()=> {
            console.log(this.name)
            console.log(self.name)
        })()
    }
}
obj.fn()

//aaa
//aaa
//aaa
//aaa

考点:自执行函数中的this 为window;箭头函数中的this是定义时所在作用域的this,let定义的与window无关

let name='全局';
let obj={
    name:'aaa',
    fn:(function(){
        var self=this;
        console.log(this.name);
        console.log(self.name);
        return ()=> {
            console.log(this.name)
            console.log(self.name)
        }
    })()
}
obj.fn()
//undefined
//undefined
//undefined
//undefined

考点:自执行函数中的this 为window;箭头函数中的this是定义时所在作用域的this

let obj={
    name:'aaa',
    fn:(function(){
        var self=this;
        console.log(this.name);
        console.log(self.name);
        return function(){
            console.log(this.name)
            console.log(self.name)
        }
    })()
}
obj.fn()

//undefined
//undefined
//aaa
//undefined

以下情况不能使用箭头函数:

1、定义函数的方法,且该方法内部包括this

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

2、 需要动态this的时候,也不应使用箭头函数