文章目录
一、函数默认值
1、函数形参的length
function test(a, b, c) {}
console.log(test.length); // 3
function test(a, b = 1, c) {}
console.log(test.length); // 1
- 函数形参的length等于从左到第一个有默认值的参数的个数
2、函数实参的length
function test(a, b, c) {
console.log(arguments.length); // 2
}
test(1, 2);
arguments.length
3、函数的默认值对函数的length的影响
- 更改函数参数默认值,会引起函数的属性length变化
- length根据默认值的位置确定,只包含默认值之前的参数的长度
4、函数的默认值导致形参和实参的映射关系不存在
- 函数的形参和实参是相互映射的关系
function test(a, b, c) {
arguments[1] = 3;
console.log(b); // 3
}
test(1, 2);
指定函数的默认值后:
function test(a, b = 5, c) {
arguments[1] = 3;
console.log(arguments); // [1, 3]
console.log(b); // 2
}
test(1, 2);
- 任何一个参数给了默认值后,形参跟实参的映射关系将不存在
函数内部更改实参的值,能够更改实参,但是对形参没有任何影响
5、给解构赋值一个默认值
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}); // undefined 5
foo({x: 1}); // 1 5
foo({x: 1, y: 2}); // 1 2
foo(); // 报错 因为他没有属性则没有包装类,匹配不上{},所以报错
上述不传值的解决办法:
function foo({x, y = 5} = {}) { // 解构赋值依然有默认值 {}
console.log(x, y);
}
// 参数是undefined的时候会找默认值为空对象的默认值,从而达到匹配
foo(); // undefined 5
6、fetch
// 简写方式
function fetch(
url,
{
body = "",
method = "GET",
header = {}
}
) {
console.log(method);
}
// 完整方式
function fetch(
url,
{
body: body = "",
method: method = "GET",
header: header = {}
}
) {
console.log(method); // GET
}
fetch('http://www.baidu.com', {});
调用fetch的时候,不想手动传第二个参数,那么我们就可以给他的解构赋值赋一个默认值:
function fetch(
url,
{
body = "",
method = "GET",
header = {}
} = {}
) {
console.log(method);
}
fetch('http://www.baidu.com'); // GET
7、作用域问题
var a = 1;
var a = 2; // var存在变量提升,可以重新赋值,覆盖
console.log(a); // 2
var x = x; // x声明到全局,没有赋值
console.log(x); // undefined
let b = 1;
let b = 2; // let不存在变量提升,不可以重新赋值,报错
let c = c; // c没有声明 报错 c is not defined
// x还没有定义,不可以在初始化之前调用x
function foo(x = x) { // Cannot access 'x' before initialization
}
foo();
8、默认值给一个function
- 调用栈:函数调用的时候会创建一个栈针,记录着当前的函数是在哪个地方调用的,以栈的方式存储
var x = 1;
// 当给函数默认值的时候,就已经给了一个块级作用域 let x,y
function foo(x, y = function() {
x = 2;
console.log(x); // 2
}, z = function() {
console.log(x);
}) {
var x = 3;
y(); // 2
console.log(x); // 3
z(); // 1
}
foo();
console.log(x); // 1
二、普通函数的this指向
1、默认绑定规则
- 非严格模式下默认指向:window
- 严格模式在指向:undefined
a();
function a () {
console.log(this); // window
}
a();
function a () {
'use strict';
console.log(this); // undefined
}
2、隐式绑定规则
- 谁调用,指向谁
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); // 2
var bar = obj.foo;
bar(); // window.bar(); -> window上没有,则为undefined
3、显示绑定
- call、apply、bind绑定
4、new
在new的时候将this转变成实例化的对象
- new的时候改变了this指向
5、优先级:4>3>2>1
三、箭头函数
1、箭头函数写法
- 说到箭头函数一定是箭头函数表达式(因为箭头函数没有函数名只能赋值给变量)
函数参数只有一个:括号可以省略
let f = a => {
return a;
}
// 相当于
let f = function(a) {
return a;
}
函数体只return一个表达式:大括号可以省略,return可以省略
let f = a => a;
// 相当于
let f = function(a) {
return a;
}
函数没有参数的话:括号不可以省略
let f = () => a;
// 相当于
let f = function() {
return a;
}
函数体有多条语句: 括号不可省略
- 箭头函数不指定返回值默认返回undefined
let f = function() {
let a = 1,
b = 2;
console.log(a + b);
}
2、箭头函数结合函数参数的解构赋值
// 函数参数的解构赋值
const full = ({f, l} = {}) => f + '' + l;
function full({f, l} = {}) { // 相当于
return f + '' + l;
}
console.log(full({f: 'l', l: 'yb'})); // lyb
3、箭头函数没有arguments
var sum = (a, b) => {
console.log(arguments); // arguments is not defined
}
sum();
- 证明:
=>
跟function
本质上是两个东西,不是function
的简写
4、rest运算符(展开或者收集)
- 箭头函数中arguments的替代品: …|spread|rest运算符
收集实参
// args: 随便定义,但是我们习惯使用args
var sum = (...args) => {
console.log(args); // [1, 2]
}
sum(1, 2);
- 拓展收集运算符必须是最后一位
let fn = (a, b, ...c) => {
console.log(a, b, c);
}
// let fn = (...c, a, b) => { // 报错
// console.log(a, b, c);
// }
fn(1, 2, 3, 4, 5, 6); // 1 2 [3, 4, 5, 6]
展开参数
function foo(a, b, c) {
console.log(a, b, c);
}
foo(...[1, 2, 3]); // 1 2 3
- 展开运算符实质是用apply实现的
function foo(a, b, c) {
console.log(a, b, c);
console.log(this);
}
foo.apply(null, [1, 2, 3]); // 1 2 3 window
foo.apply(undefined, [1, 2, 3]); // 1 2 3 window
- 展开数组,并合并
let a = [1, 2, 3];
let b = [0, ...a, 4];
console.log(b); // [0, 1, 2, 3, 4]
函数中使用了 … 运算符,函数的长度将不再准确
console.log((function(a){}).length); // 1
console.log((function(...a){}).length); // 0
console.log((function(a, b, ...c){}).length); // 2
console.log((function(a, b = 1, ...c){}).length); // 1