Es6 复阅(9-1)(部分是非es6的) --函数的扩展 (形参解构赋值,reset,箭头函数)

1.可以给函数设置默认值

	function testFn(x, y = '默认y') {
	    console.log(x);//undefined
	    console.log(y);//默认y
	}
	testFn()

设置默认值在某些时候是十分有用的,当这个变量的值基本是固定的,只有特殊的几个不同时候,只要将特殊的调用的时候进行传值就可以啦

	function printTem(name = '打印'){}

2.将默认值与结构赋值结合使用

	function testFn({x,y}){
		console.log(x);//参数x
		console.log(y);//参数y
	}
	testFn({x:'参数x',y:'参数y'})

但是这样写与有点危险,一旦这个参数我们忘记传了,就会报错:

	Cannot destructure property `x` of 'undefined' or 'null'.

所以,上面的写法,还要再改进一点:

	function testFn({x,y} = {}){
		console.log(x);//undefined
		console.log(y);//undefined
	}
	testFn();

终极写法:(双重默认值)

	function testFn({x = '默认x',y = '默认y'} = {}){
	}

这样子就算我们忘记传参也不会报错啦,而且x,y 都回有值

同时,如果是非尾部的参数位需要默认值,而尾部参数又需要传参,可以显示地传入 undefined:

	function testFn(x = '默认x',y = '默认y'){
		console.log(x);//默认x
		console.log(y);//传入的y
	}
	testFn(undefined,'传入的y')

hhhhhh,如果是对象形式的,不传这个需要默认值的参数就好啦,默认就是undefined的:

	function testFn({ x = '默认x', y = '默认y' } = {}) {
	    console.log(x); //默认x
	    console.log(y); //传入的y
	}
	// testFn({ x: undefined, y: '传入的y' })
	testFn({ y: '传入的y' })

利用这个默认值,将不可缺省的参数进行抛错处理:

	function mustTip(mustParams) {
	    throw new Error(mustParams + ' params is required')
	}
	
	function testFn(mustParams = mustTip('mustParams')) {
	    console.log(mustParams)
	}
	testFn();//mustParams params is required

throw new Error 是个有意思的好东西

3.函数的length (返回没有默认值的参数的个数)

	function testFn(x,y,z,u){}
	console.log(testFn().length);//4

现在返回的是3?现在返回的是0

	function testFn(x = 1,y,z,u){}
	console.log(testFn().length);//0

现在该返回3了吧?是的

	function testFn(x ,y,z,u = 1){}
	console.log(testFn().length);//0

arguments的区别:

	function testFn(w,x,y,z){
		console.log(arguments.length);//0
	}
	testFn();

arguments 是函数的参数列表,传入的参数个数,决定了它的长度

	function testFn(w,x,y,z){
		console.log(.length);//6
	}
	testFn(1,2,3,4,5,6)

尽管5,6没有办法与具体的形式参数对应,但是通过arguments 可以拿到,可以用来与形参比对,以及对应参数位上的传值是否正确

4.奇怪的作用域

	var x = '全局的x'
	function testFn(x,y = x){
		console.log(x);//全局的x
		console.log(y);//全局的x
	}
	testFn();
	var x = '全局的x'
	function testFn(x,y = x){
		//此时这个形参x与全局的x 是互不相干的 
		console.log(x);//传入的x
		console.log(y);//传入的x   此时就相当于把x 的值给了 y 做默认值
	}
	testFn('传入的x');
	function testFn(x,y = x){
		console.log(x);//undefined
		console.log(y);//undefined
	}
	testFn();

会报错:

	// x is not defined  这两个x 的作用域不一样
	function testFn(y = x) {
	    let x = 1;
	}
	testFn()

5.酷炫的reset

ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中 , 看着就十分酷炫
对比一下 arguments 与 reset

	function testFn1(value) {
	    console.log(value);//1
	    console.log(arguments);//[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
	    console.log(arguments[0]);//1
	}
	testFn1(1, 2, 3, 4, 5)
	
	function testFn(...value) {
	    console.log(value);// [1,2,3,4,5];
	    console.log(value[0]);//1
	}
	testFn(1, 2, 3, 4, 5)

这样一看是不是没有太大区别,再来一次:

	function testFn1(x, y) {
	    console.log(x); //1
	    console.log(y); //2
	    console.log(arguments); //[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
	}
	testFn1(1, 2, 3, 4, 5)
	
	function testFn(x, y, ...value) {
	    console.log(x); //1
	    console.log(y); //2
	    console.log(value); //[3,4,5]
	}
	testFn(1, 2, 3, 4, 5)

这样,是不是就看出区别了,当有多个参数的时候,使用这个reset 可以将剩余参数收集到数组中,很明显的看到,也不会影响当前形参位置上的值

6.函数的name

	//函数绑定之后的name
	let foo = { bar: 'likeB' }
	function testFn() {
	    console.log(this);
	}
	testFn.bind(foo).name ;//bound testFn
	
	//Function 构造函数的函数实例
	(new Function).name  ;//anonymous  -- 匿名的
	let str = 'return' + '`I am ${name}!`' 
	let fn = new Function('name', str);
	fn('最好')
	
	//将匿名函数赋值给一个变量
	let testFn = function () {}
	testFn.name;//testFn

7.箭头函数

this指向问题一直都很头疼,似乎除了绑定就没有其他的好办法来留住我们真正想要的this,箭头函数的出现无疑是解决了这个问题,因为箭头函数没有自己的this,箭头函数中所使用的this来自于函数作用域链

  1. 使用箭头函数优化代码
	const words = ['hello', 'WORLD', 'Whatever'];
	const downcasedWords = words.map(word => word.toLowerCase());
	//hello world whatever
  1. 与父级别的this保持一致
/**使用 forEach 循环,箭头函数能够保持 this 来自于父级,让他们非常直观
类似的,当用 forEach 来替换传统 for循环的时候,实际上箭头函数会直观的保持 this来自于父一级
*/
	//浏览器中
	let arr = [1,2]
	console.log(this);//window
	arr.forEach((item,index)=>{
		console.log(this);//window
	})
  1. 管理异步代码
	this.doSomethingAsync().then((result) => {
		//在promise的回调里,需要用到上层this或操作上层函数
	 	this.storeResult(result);
	});
  1. 封装对象转换

mapState 辅助函数,生成计算属性,辅助函数主场

	import { mapState } from 'vuex'
	export default {
	  computed: {
	    ...mapState({
	      results: state => state.results,
	      users: state => state.users,
	    });
	  }
	}
  1. 简化回调函数
	let fn = a=> a+'tem';//只用写一行,返回值也一目了然
  1. 用在定时器,延时器中
	function Timer(a) {
        this.a = a;
        console.log(this)
        setInterval(() => {
            console.log(this); //{a:a}
        }, 1000)
        setInterval(function() {
            console.log(this);//window
        }, 5000)
    }
    let timer = new Timer('a');
  1. 箭头函数可以让this指向固定化,这种特性很有利于封装回调函数

  2. 嵌套的箭头函数 (大神的例子

  3. 改写 λ 演算 (太牛逼,这里只做记录,不做探索)

但箭头函数也有许多雷区

  1. 对于需要使用**object.method()**方式调用的函数,使用普通函数定义,不要使用箭头函数。对象方法中所使用的this值有确定的含义,指的就是object本身。
	let obj = {
        foo: 'foo',
        bar: 'bar',
        fn: function() {
            console.log(this)
        }
    }
	
    let obj1 = {
        foo: 'foo',
        bar: 'bar',
        fn: () => {
            console.log(this)
        }
    }//这里使用箭头函数就把自己坑了
    
    //以在火狐浏览器中为例
    obj.fn();//Object { foo: "foo", bar: "bar", fn: fn()}
    obj1.fn();//Window
  1. 在原型上定义函数
	//以在火狐浏览器中为例
	function Person(name) {
	    this.name = name;
	}
	Person.prototype.SayName = () => {
	    return this.name
	}
	let fn = new Person('最好');
	
	console.log(fn.SayName());//undefined
	
	//使用function 
	function Person(name) {
	    this.name = name;
	}
	Person.prototype.SayName = function() {
	    return this.name
	}
	let fn = new Person('最好');
	
	console.log(fn.SayName());//最好
  1. 动态上下文中的回调函数
	btnNode.addEventListener('click', function() {
        this.innerHTML = 'pppppp';//正确  此时的this是这个按钮实例
    })
    btnNode.addEventListener('click', ()=> {
        this.innerHTML = 'pppppp';//没得反应  此时的this是window
    })
  1. 构造函数中
	let Person = (name)=>{
		this.name = name;
	};
	let fn = new Person();//Person is not a constructor

箭头函数连this都没有,怎么做构造函数

  1. 多人开发时,难以理解

  2. 箭头函数中不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

	let fn = (...value) => {
        console.log(value); //[1,2,3,4,5]
    }
    fn(1, 2, 3, 4, 5);

    let fn2 = (value) => {
        console.log(arguments); //test3.html:69 Uncaught ReferenceError: arguments is not defined
    }
    fn2(1, 2, 3, 4, 5)
  1. 不可以使用yield命令,因此箭头函数不能用作 Generator 函数,详解Generator 函数(后续)

注:es6箭头函数没出现之前,this的指向不是函数被创建时绑定,而是被怎么样的方式调用时绑定的。而箭头函数刚好相反,箭头函数的this指向是函数被创建时绑定的,它的指向就是当前词法作用域中的this,并且不会因为被怎么样的方式调用改变绑定

发布了50 篇原创文章 · 获赞 4 · 访问量 1252

猜你喜欢

转载自blog.csdn.net/weixin_43910427/article/details/105318160