目录
2、形参默认值
1、函数参数的默认值
ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
function log(x, y) {
y = y || 'World';
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello World
上面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。
为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值。
if (typeof y === 'undefined') {
y = 'World';
}
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
2、形参默认值
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
可以看到,ES6 的写法比 ES5 简洁许多,而且非常自然。下面是另一个例子。
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
const p = new Point();
p // { x: 0, y: 0 }
3、rest 参数--剩余参数
将传递函数的所有实参打包到一个数组中,只能写在形参列表的最后
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
上面代码的add函数是一个求和函数,利用 rest 参数,可以向该函数传入任意数目的参数。
4、name 属性
函数的name属性,返回该函数的函数名
function foo() {}
foo.name // "foo"
这个属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准。
5、箭头函数
箭头函数其实和以前的函数没有什么太大的区别,无非就是省略了 function 这个关键字:
语法:const/let 函数名 = 参数 => 函数体
原函数:
function add(){}
箭头函数:
()=>{}
但是不难发现这样写箭头函数的话便无法调用,所以我们可以采用匿名函数的形式:
const add = ()=>{}
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
<script>
const add = (x, y) => {
return x + y;
};
console.log(add(1, 1));
</script>
注意:
- 普通函数/方法中的this,谁调用就是谁
- 箭头函数中认为是不存在 this 的,因为箭头函数中的this,是父作用域的this,不是调用者(箭头函数中的 this 指向箭头函数所在作用域的 this)
- 箭头函数中,不存在 arguments
a. 如果箭头函数中只有一个参数,那么圆括号是可以省略不写的
<script>
//写法1
const add = (x) => {
return x + 1;
}
//写法2
// const add = x => {
// return x + 1;
// };
console.log(add(1));
</script>
b.如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
c.如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回
var sum = (num1, num2) => { return num1 + num2; }
d.由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
e.箭头函数的一个用处是简化回调函数
// 正常函数写法
[1,2,3].map(function (x) {
return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);
f. 单行函数体可以同时省略 {} 和 return
<script>
//方式1
const add = (x, y) => {
return x + y;
};
//方式2
const add = (x, y) => x + y;
console.log(add(1, 1));
</script>
多行函数体不能再化简
<script>
const add = (x, y) => {
const sum = x + y;
return sum;
};
</script>
单行对象
<script>
//方式1
const add = (x, y) => {
return {
value: x + y
};
};
//方式2
const add = (x, y) => ({
value: x + y
});
</script>
注意: 如果箭头函数返回单行对象,可以在 {} 外面加上 (),让浏览器不再认为那是函数体的花括号
单行数组:
<script>
const add = (x, y) => [x, y];
console.log(add(1, 1));
</script>
箭头函数有几个使用注意点:
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
- 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
this对象的指向是可变的,但是在箭头函数中,它是固定的。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
6、不适用箭头函数的场景
a.作为构造函数
箭头函数没有 this
<script>
const Person = () => {};
new Person();
</script>
b.需要 this 指向调用对象的时候
<script>
document.onclick = function() {
console.log(this);
};
document.addEventListener(
'click',
() => {
console.log(this); //window
},
false
);
</script>
c.需要使用 arguments 的时候
箭头函数中没有 arguments
<script>
//一般函数
// function add() {
// console.log(arguments);
// }
// add(1, 2, 3, 4, 5);
const add = () => console.log(arguments);
add();
</script>
7、综合案例
<style>
body {
padding: 50px 0 0 250px;
font-size: 30px;
}
#btn {
width: 100px;
height: 100px;
margin-right: 20px;
font-size: 30px;
cursor: pointer;
}
</style>
<button id="btn">开始</button>
<span id="result">0</span>
<script>
const btn = document.getElementById('btn');
const result = document.getElementById('result');
// const timer = {
// time: 0,
// start: function () {
// // this
// var that = this;
// // var self = this;
// btn.addEventListener(
// 'click',
// function () {
// setInterval(function () {
// console.log(this);
// // this.time++;
// // result.innerHTML = this.time;
// that.time++;
// result.innerHTML = that.time;
// }, 1000);
// },
// false
// );
// }
// };
const timer = {
time: 0,
start: function() {
// this
btn.addEventListener(
'click',
() => {
// this
setInterval(() => {
console.log(this);
this.time++;
result.innerHTML = this.time;
}, 1000);
},
false
);
}
};
timer.start();
</script>
8、箭头函数和普通函数的区别
普通函数/方法中的this, 谁调用就是谁
function demo() {
console.log(this); // Window
}
demo();
// window.demo();
箭头函数中的this, 是父作用域的this,不是调用者:
示例1:
let p = {
name: "lnj",
say: function() {
console.log(this); // {name: "lnj", say: ƒ}
},
// 因为没有将箭头函数放到其它的函数中, 所以箭头函数属于全局作用域
// 在JS中只有定义一个新的函数才会开启一个新的作用域
hi: () => {
console.log(this); // Window
}
}
p.say();
p.hi();
console.log(this); // Window
示例2:
function Person() {
this.name = "lnj";
this.say = function() {
console.log(this); // Person
}
// 因为将箭头函数放到其它的函数中, 所以箭头函数属于其它函数(当前的其它函数就是构造函数)
// 既然箭头函数属于构造函数, 所以箭头函数中的this就是构造函数的this
this.hi = () => {
console.log(this); // Person
}
}
let p = new Person();
p.say();
p.hi();
示例3:
function Person() {
this.name = "lnj";
this.say = function() {
console.log(this); // {name: "zs"}
}
this.hi = () => {
console.log(this); // Person
}
}
let p = new Person();
p.say.call({
name: "zs"
});
// 注意点: 箭头函数中的this永远都只看它所属的作用域的this
//无法通过bind/call/apply来修改
p.hi.call({
name: "zs"
});