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来自于函数作用域链,
- 使用箭头函数优化代码
const words = ['hello', 'WORLD', 'Whatever'];
const downcasedWords = words.map(word => word.toLowerCase());
//hello world whatever
- 与父级别的this保持一致
/**使用 forEach 循环,箭头函数能够保持 this 来自于父级,让他们非常直观
类似的,当用 forEach 来替换传统 for循环的时候,实际上箭头函数会直观的保持 this来自于父一级
*/
//浏览器中
let arr = [1,2]
console.log(this);//window
arr.forEach((item,index)=>{
console.log(this);//window
})
- 管理异步代码
this.doSomethingAsync().then((result) => {
//在promise的回调里,需要用到上层this或操作上层函数
this.storeResult(result);
});
- 封装对象转换
mapState 辅助函数,生成计算属性,辅助函数主场
import { mapState } from 'vuex'
export default {
computed: {
...mapState({
results: state => state.results,
users: state => state.users,
});
}
}
- 简化回调函数
let fn = a=> a+'tem';//只用写一行,返回值也一目了然
- 用在定时器,延时器中
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');
但箭头函数也有许多雷区
- 对于需要使用**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
- 在原型上定义函数
//以在火狐浏览器中为例
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());//最好
- 动态上下文中的回调函数
btnNode.addEventListener('click', function() {
this.innerHTML = 'pppppp';//正确 此时的this是这个按钮实例
})
btnNode.addEventListener('click', ()=> {
this.innerHTML = 'pppppp';//没得反应 此时的this是window
})
- 构造函数中
let Person = (name)=>{
this.name = name;
};
let fn = new Person();//Person is not a constructor
箭头函数连this都没有,怎么做构造函数
-
多人开发时,难以理解
-
箭头函数中不可以使用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)
- 不可以使用yield命令,因此箭头函数不能用作 Generator 函数,详解Generator 函数(后续)
注:es6箭头函数没出现之前,this的指向不是函数被创建时绑定,而是被怎么样的方式调用时绑定的。而箭头函数刚好相反,箭头函数的this指向是函数被创建时绑定的,它的指向就是当前词法作用域中的this,并且不会因为被怎么样的方式调用改变绑定