==========================函数参数默认值======================= es6使用参数的默认值, 在书写的时候,直接给形参赋值,赋的值就是默认值 例如: function add( a = 1, b = 2 , c){ retrun a + b + c; } add(undefined,undefined, 2 ) // 5 add(1,2,3) // 6 默认参数不一定只可以是字面量, 可以是对象, 任何有意义的赋值都可以, 函数, 对象, 数组,正则等 参数默认值对arguements的影响? 严格模式下 "use strict" , 形参与arguements是脱离的 非严格格式下, 形参与arguements是统一的 只要给函数加上参数默认值, 该函数就会自动变成严格模式下, 就是形参与arguements脱离 留意暂时性死区? 形参和ES6中的let或者const声明一样, 具有作用域,并且根据形参的声明顺序,存在暂时性死区 例如: function test(a, b= a){ console.log(a, b) } 第一次调用: test(1, 2) // 1 2 第二次调用: test(1) // 1 1 但是如果test方法是如下的写法: function test(a = b, b){ console.log(a, b) } 第一次调用 test(undefined, 2) // 报错, 报暂时性死区的错误 得出结果: 在函数里面,定义变量尽量不要和形参同名 =====================es6剩余参数======================== 以前使用的是arguements, arguements的缺陷: 1. 如果和形参配合使用, 容易导致混乱, 严格模式形参与arguements还相脱离 2. 从语义上使用arguements获取参数,由于参数缺少,无法从函数定义上无法理解函数的意图 es6的剩余参数: 专门用于收集末尾的所有参数,将其放置到一个形参数组中 使用方法: 形参前面加上三点 function(...形参名){ } 细节: 1. 一个函数,仅能出现一个剩余参数 2. 一个函数,如果有剩余参数, 剩余参数必须是最后一个参数 =====================展开运算符=============================== 如下面的例子: <script> /** * @description: * @param : arg 剩余参数 * @return: 函数的和 */ function sum(...arg) { let res = 0; arg.forEach(item => { res += item; }) return res; } /** * @description: 获取指定长度的数组 * @param : length 长度 * @return: 结果 */ function getRandomNumbers(length) { let res = []; for (let i = 0; i < length; i++) { res.push(Math.random()); } return res; } </script> let arr = getRandomNumbers(10); sum(arr) // 此时传入的是一个数组, 但是剩余参数哪里打印 arg会得到一个二维数组 所以数组需要展开 es6 提供对数组展开: ...需要展开的数组 es7 提供对对象展开: ...需要展开的对象 所以上面的例子就可以使用 sum(...arr); 就可以求和了。 使用 ... 还可以实现下面的操作, 1. 一个数组克隆到另一个数组(浅克隆) 如: const arr = [1,2,3,4]; const arr2 = [...arr1]; 2. 一个对象克隆到另一个对象(浅克隆), 如 const obj1 = {name: 1, age: 2}; const obj2 = {...obj1, sex: male} /** * @description: 柯里化 用户固定某个函数前面的参数,得到一个新的函数,新函数调用时候,接受剩余参数 * @param : * @return: */ function curry(fn, ...args) { return function (...subArgs) { const allArgs = [...args, ...subArgs]; // 参数够了 if (allArgs.length >= fn.length) { return fn(...allArgs); } else { // 参数不够,继续固定 curry(fn, ...allArgs); } } } =========================es6函数的双用途===================== 函数可以当作普通函数, 也可以当作构造函数 例如: function Person(firstName, lastName){ // 严格模式需要判断是否使用new 来判断 // 过去的判断方式 if(!(this instance of Person)){ throw new Errow(" 该函数没有使用new 来调用") } //es6判断, 完美判断 if(new.target === undefined){ throw new Errow(" 该函数没有使用new 来调用") } this.firstName = firstName; this.lastName = lastName; this.fullName = `${firstName}${lastName}` } const p1 = new Person("成", "都"); console.log(p1) // 要给构造函数对象 const p2 = Person("成", "都"); console.log(p2) //undefined 过去的那种方法会存在弊端, 如果有人强制传递this是person,但是又不是new如下: const p3 = Person.call(new Person("成","都"),"成","都"); console.log(p3) // undefined 现在es6提供一个特殊的api, 可以使用该API在函数的内部,判断函数是否使用了new来调用 语法: new.target // 该表达式得到的是:如果没有使用new来调用函数,返回的是undefined, 如果使用new来调用,则得到的是new关键字后面的函数本身 ===============es6箭头函数=================================== 解决this的指向问题 this指向: 1. 通过对象调用函数,this指向那个调用者 2. 直接调用函数, this指向的是window 3. 如果通过new调用函数, this指向新创建的对象 4. 如果通过 apply, call, bind调用函数, this指向指定的数据 5. 如果是DOM时间函数, this指向事件源 存在的问题 : 例如: const obj = { count: 0, start: function(){ // 这里的this指向的是调用者, 就是obj setInterval(function(){ // 这里的这个this 指向的是全局的window this.count++; },1000) }, regEvent: function(){ windwo.onclick = function(){ // this 指向的是事件源 } } } obj.start(); obj.regEvent(); 箭头函数解决this的指向问题: 语法: 箭头函数是一个函数表达式,理论上任何使用函数表达式的场景,都可以使用箭头函数 (参数1,参数2,...) => {} 如果参数只有一个,可以省略小括号 参数 => {} 如果箭头函数里面只有一条语句并且还是返回的,那么可以省略大括号和return 例如: const isOdd = num => num%2 !== 0; // 返回值是一个对象,需要用小括号括起来 const sum = (a,b) => ({ a: a, b: b, sum: a + b; }) 细节: 1. 箭头函数的的函数体中的this,取决于箭头函数定义的位置的this指向,而于调用无关 2. 箭头函数, 不存在this, arguments, new.target, 如果使用了,那就是使用的是外层函数的 3. 箭头函数没有原型, 箭头函数占用的内存空间小,因为没有原型 4. 箭头函数不能当作构造函数, 没有原型 应用场景: 1. 临时性使用的函数,并不会调用它, 比如: 1. 事件处理函数 2. 异步处理函数, setTimeOut等 3. 其他临时性函数 2. 为了绑定外层this的函数 3. 数组方法中的回调函数 4. 在不影响其他代码的情况下,保持代码的简洁