1.函数参数的默认值
ES6之前,不能为函数的参数设置默认值,只能在代码中进行判断
//原来写法
function show(a, b) {
if (typeof b === "undefined") {
b = 0;
}
console.log(a, b);//1 0
}
show(1);
//ES6写法
function show(a, b=0) {
console.log(a, b);//1 0
}
show(1);
//ES6写法错误写法 设置默认值的参数应该在函数的最后面,否则默认值设置是无效的。
function show(a=0,b ) {
console.log(a, b);//1 undefined
}
show(1);
上述代码为什么不是输出0 undefined 呢?
设置默认值的参数应该在函数的最后面,否则默认值设置是无效的。
因为1传给了形参a,发现a=0,但是a=0没有生效 ,仍然输出 a为1
函数的length属性为函数的参数个数。若设置了默认值,length的计数中是不计算设置了默认值的参数的。
function show(a,b) {
console.log(show.length);//2
}
show(3,6);
function show(a,b=0) {
console.log(show.length);//1
}
show(3,6);
上述形参设置默认值,就不计入函数的参数所以为1,当你设置a=0时,函数的参数个数为0
作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。
等到初始化结束,这个作用域就会消失。
var a = 1;
function fn(a,b = a){
console.log(b);//2
}
fn(2)
运行过程:传进去了一个参数2,这时括号里的a就为2, 因为(a,b = a)在同一个作用域,所以b=a=2
因为(a,b = a)在同一个作用域,所以它不会去外部继续寻找a的值
let a = 1;
function fn(b = a){
let a = 2;
console.log(b);
}
fn();//1
上述函数调用中,(b=a)是一个单独的作用域,a变量不存在,则会去外部寻找。
2.rest参数…
function sum(a, b) {
return a + b;
}
alert( sum(1, 2, 3, 4, 5) );
虽然不会报错,但是多余的参数也不会起任何作用,
函数只会返回前俩个参数相加的结果。
Rest参数的操作符表示为3个点 … ,直白地讲,它的意思就是“把剩余的参数都放到一个数组中
举个例子,我们需要把所有的参数都放到数组args中:
function sumAll(...args) {
//数组变量名为args
let sum = 0;
for (let arg of args) {
//for of 是遍历的一种方式
sum += arg;
}
return sum;
}
alert(sumAll(1)); //1
alert(sumAll(1, 2)); //3
alert(sumAll(1, 2, 3));//6
2.1 基本用法
// 原来写法
function fn(){
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);//1 3 4
}
}
fn(1,3,4)*/
//==============================
//rest写法
function fn(...v){
for (var i = 0; i < v.length; i++) {
console.log(v[i]);//1 3 4
}
}
fn(1,3,4)
rest参数必须是最后一个正式参数。
//错误写法
function fn(...v,a){
for (var i = 0; i < v.length; i++) {
console.log(v[i]);
}
}
fn(1,3,4)
//报错:Rest parameter must be last formal parameter (Rest参数必须是最后一个形式参数)
2.2 rest参数和arguments对象的区别
arguments对象不是一个数组,只是一个类似数组的对象。不能使用数组的方法。
<script>
function sort(...v){
// return arguments.sort(); 报错 arguments.sort is not a function
return v.sort()
}
console.log(sort(3,1,4,8));
</script>
Spread操作符(展开操作符)
let arr = [2, 3, 4, 5, 7, 8];
console.log(...arr);
// 输出的是一个一个的值 2, 3, 4, 5, 7, 8
比如,内建函数 Math.max 会返回参数中最大的值:
alert( Math.max(3, 5, 1) ); // 5
假如我们已有数组 [3, 5, 1],我们该如何用它调用 Math.max 呢?
直接把数组“原样”传入是不会奏效的,因为 Math.max 期待你传入一系列的数值型参数,而不是单一的数组:
let arr = [3, 5, 1];
alert( Math.max(arr) ); // NaN
这个时候我们就可以用…来解决
let arr = [3, 5, 1];
alert( Math.max(...arr) ); // 5(Spread 操作符把数组转为参数列表)
当我们在代码中遇到 “…” 时,它不是 Rest 参数就是 Spread 操作符。
我们可以使用下列方法区分二者:
-
若 … 出现在函数的参数列表,那它表示的就是 Rest
参数,它会把函数多余的实参收集到一个数组中。 -
若 … 出现在函数调用或类似的表达式中,那它就是 Spread 操作符,它会把一个数组展开为逗号分隔的元素列表。
————————————————
详细解法在收藏es6res参数里面
数组去重(面试题):
不适用es6的方式:
数组去重
let arr = [1, 1, 2, 3, 4, 4, 5]
let res = []
for(let i = 0; i < arr.length; i++){
//第一种
if(res.indexOf(arr[i]) == -1){
res.push(arr[i])
}
第二种
if(arr.indexOf(arr[i]) != arr.lastIndexOf(arr[i])){
arr.splice(i, 1);
i--
}
}
使用es6 去重
new Set() 集合的特点(元素是唯一的,没有顺序,接收的参数是数组),所以可以去重
但是去重后是一个set集合,不是我们想要的,转换为一个数组
- 可以用…res参数,将其展开为一个一个的参数,然后套个数组[]
let arr = [1, 1, 2, 3, 4, 4, 5]
let res = [...new Set(arr)]
console.log(res); //[1, 2, 3, 4, 5]
- 也可以,用 Array.from方法将集合转换为数组
let arr = [1, 1, 2, 3, 4, 4, 5]
let res = (new Set(arr));
let yi = Array.from(res);
console.log(yi);// [1, 2, 3, 4, 5]
3.箭头函数
3.1 定义
箭头函数是对于匿名函数表达式的一种简写方法。
3.2 语法
//普通匿名函数
var a = function (a, b) {
console.log(a);//1
}
a(1);
//箭头函数
//()形参的位置
//=> 箭头函数的标志
//{
} 函数代码块
var a = (a)=> {
console.log(a); }//1
a(1);
用法的区别:
var fn = function(a,b){
console.log(a+b);//30
console.log("我是普通匿名函数");
}
fn(10,20);
var fn2 = (a,b)=>{
console.log(a+b);//30
console.log("我是箭头函数");
}
fn2(10,20);
3.3 其他写法
如果箭头函数只有一个形参,则可以省略小括号。
var fn = a =>{
console.log(a);
}
如果只包含一个语句,则省略{}和return。
var fn = a => a*a;
console.log(fn(10));//100
箭头函数中没有arguments实参对象。
var fn = a => {
console.log(arguments.length);//报错 arguments is not defined
}
3.4 箭头函数中this指向
console.log(window.console.log() == console.log());//true
其实console.log()是window在调用
箭头函数内部的this是由上下文确定的。
它会找到自身定义的位置中的this值,作为自身的this。
<body>
<div>1</div>
</body>
<script>
let div = document.querySelector("div");
/ div.onclick = function(){
console.log(this);//div
}/
//=============================================================
// div.onclick = ()=>{
console.log(this);}//window
console.log(this);//window
//可以理解为在这个代码块外面写一个this console.log(this);这里面this指向谁,箭头函数中this就指向谁
//===========================================================
div.onclick = function(){
/ let fn = function(){
console.log(this);//window
}
fn();}/其实是window.fn()
//---------------------------------------------------
let fn = ()=>{
console.log(this);//div
}
// 因为 console.log(this);//div所以上述箭头函数this指向为
fn();
}
//================================================
let obj = {
name:"亚索",
fn:function(){
console.log(this);//obj
},
fun:()=>{
console.log(this);//window
}
}
obj.fn();
obj.fun();*/
</script>
自执行函数
自执行函数:IIFE 在定义时立即执行的函数
1.声明一个函数
2.立刻调用。
函数分为两个阶段:
1.定义阶段
2.调用阶段
写法:
(function(形参){
})(实参)
(function(形参){
}(实参))
自执行函数的作用:
解决全局变量的污染
示例普通函数
<!-- <script>
function arr(){
alert("今天是个好日子")
}
arr();
</script> -->
<!-- <script>
// 一种表示方法
( function arr(){
alert("今天是个好日子")
}());
</script>
<script>
//二种表示方法
( function arr(){
alert("今天是个好日子")
})();
</script> ```
有参数的函数
<!-- <script>
function arr(a){
alert("方法执行了" + a);
}
arr(1);
</script> -->
<!-- <script>
( function (a) {
alert("方法执行了一" + a)}(1));
</script> -->
<script>
var x = -function(a){
return a;
}(123);
console.log(x);//-123
</script>
例子:需求,点击每一个就返回每一个的下标
<body>
<ul>
<li>这是第1个li</li>
<li>这是第2个li</li>
<li>这是第3个li</li>
<li>这是第4个li</li>
<li>这是第5个li</li>
<li>这是第6个li</li>
</ul>
</body>
<!-- <script>
var lis = document.querySelectorAll("li");
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
console.log(i);//点击每次都是6,这不是我们想看到的
//解决方法:将var换成let
}
}
</script> -->
<script>解决方法二
var lis = document.querySelectorAll("li");
for (var i = 0; i < lis.length; i++) {
(function(i){
lis[i].onclick = function () {
console.log(i);//点击第几个就会返回这个的下标
}
})(i);
}
</script>