函数的length属性
函数有length属性
function test(){}// test(1);console.log(test.length);//0
function test(a, b) {}test(1);console.log(test.length);//2
函数默认值对length的影响
function test(a,b,c=1){}test(1);console.log(test.length);//2
function test(c=1,a,b){}test(1);console.log(test.length);//0
还是2,因为c=1赋予参数默认值的时候,它自己这位不算在length里面,并且后面无论赋不赋参数,都不算到length参数里面
function test(a,b,c=1,d){}test(1);console.log(test.length);//2
形参默认值与argument
argument与形参有映射关系,但不是一个东西
function test(a, b, d, e, f) {console.log(arguments);//[Arguments] { '0': 1 }}test(1);console.log(test.length);//5
function test(a, b, d, e, f) {arguments[1]=7;console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }console.log(b);//7}test(1,2,3,4,5,6);console.log(test.length);//5
arguments可以更改实参,对形参有影响
function test(a, b, d=1, e, f) {arguments[1]=7;console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }console.log(b);//2}test(1,2,3,4,5,6);//1,2,3,4,5,6是实参console.log(test.length);//2
形参、实参、argument与默认值的关系
/*a,b,d,e,f是形参,把实参赋值给形参,实参就没有什么用处了,AO中一直存在的是形参,不是实参,只不过形参的值是实参的值,* argument也不是实参,只不过与实参、形参有映射关系,但这个关系会被默认值影响,如果任何参数有默认值,即使是最后一位,*有默认值,所有形参都不再与argument有映射关系*/function test(a, b, d=1, e, f) {arguments[1]=7;console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }console.log(b);//2}test(1,2,3,4,5,6);/*1,2,3,4,5,6是实参,函数运行存入的值是实参*/console.log(test.length);//2
解构赋值与形参
形参无默认值,不传值时会报错,兼容性不好
function foo({x,y=5}){console.log(x,y);}foo({});//undefined 5foo({x:1});//1 5foo({x:1,y:2});//1 2foo({});//undefined 5foo()//TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined./*这样如果什么都不传的情况下,就会报错,代码终止运行,体验不好*/
给解构赋值的形参赋予默认值,兼容性好的写法
/*这样写,即使foo()什么都不传也不会报错了,做了兼容性处理*/function foo({x, y = 5} = {}) {console.log(x, y);}foo({});//undefined 5foo({x: 1});//1 5foo({x: 1, y: 2});//1 2foo({});//undefined 5foo()//undefined 5
这里面用到了兼容性
let x=x的探究
// var x=x;/*先不走let x;先走x=x*/let x=x;console.log(x);/*ReferenceError: Cannot access 'x' before initialization*/
解析
不是如下这样运行的,结果都不一样
let x;x=x;console.log(x);//undefined
是这样运行的,结果一样
x=x;//ReferenceError: Cannot access 'x' before initializationlet x;console.log(x);//undefined
function foo(x=x){//ReferenceError: Cannot access 'x' before initialization}foo()
调试
var x = 1;/*调用栈,函数调用栈,赋默认值*//*这个块级作用域里面x的值从里面取 x=>1=>2function foo({(let)x=1,(let)y = function () {x = 2;console.log(x);}})参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了*/function foo(x = 1, y = function () {var x = 2;console.log(x);//2}) {x = 3;y();console.log(x);}foo();//2 3console.log(x);//1
火狐浏览器
调试器,在foo上打断点
刷新浏览器

点击步进
范围就是scope
var x = 1;/*调用栈,函数调用栈,赋默认值*//*这个块级作用域里面x的值从里面取 x=>1=>2function foo({(let)x=1,(let)y = function () {x = 2;console.log(x);}})参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了*/function foo(x = 1, y = function () {x = 2;console.log(x);//2}) {x = 3;y();/* y = function () {x = 2;console.log(x);//2}其实就是在这里运行了这段代码,改变了x的值,x从哪里找,从这里找,从AO中找*/console.log(x);//2}foo();//2 2console.log(x);//1
类似于
{let x=2;{x=3;console.log(x);}console.log(x);}
this指向
见之前笔记
function foo() {console.log(this.a);// console.log(this);}var obj = {a: 2,foo: foo}obj.foo();//2window.obj.foo();//2/*因为bar接收obj.foo对象,赋予地址,没有运行,bar在window下,其实就是window调用*/var bar = obj.foo;bar();//undefinedwindow.bar();//undefinedlet bar1 = obj.foo;bar1();//undefined/*bar1的this也是window*/

箭头函数
参数是一个时可以省略,可以简写,如果函数里面只有一个return语句时,也可以简写
返回值只能有一个,因为走完第一个return函数就停止运行了,但可以返回对象,或者数组,里面有多个变量、多个函数,也可以返回函数
只有一个参数的情况
参数是一个,函数内语句只有一个return时,可以简写
// ()=>{}var f = a => a;var f = (a) => a;var f = (a) => {return a;};var f = function (a) {return a;}
参数不是是一个,不可以简写
2.参数不是一个的情况
0个参数必须写()括号
var f = () => 5;function f(){return 5;}
/*Uncaught SyntaxError: Identifier 'f' has already been declared*/// let f=(a,b)=>a+b;var f=(a,b)=>a+b;function f(a,b){return a+b;}
箭头函数表达式
说箭头函数的时候,一般说的是箭头函数表达式
说箭头函数的时候,一般说的是箭头函数表达式
/*箭头函数*/()=>{}/*想给其赋值,这样写不合法*/test()=>{}

这样写也没用
var test = (() => {})
只有给箭头函数赋值才能够保存箭头函数,之后才可以调用箭头函数
var test = () => {}
多重语句
多重语句必须写{}大括号,没有返回值,默认返回值是undefined
let f = (a,b) => {var a=3;var b=4;console.log(a+b);//7}console.log(f())//undefined
/*当语句只有一条,返回但是语句的执行结果,当只有一条return语句时,就可以省略{}大括号与return*/var f = (a,b) => a+b;/* var f = (a,b) => {return a+b;};*/console.log(f())//undefined
箭头函数应用
//通过解构赋值来结合const full = ({first, last} = {}) => first + '' + last;/* +‘’转成字符串*/console.log(full({first: 3, last: 5}));//35
/*从小到大排序,通过箭头函数可以简化代码,箭头函数具体应用,有些方法需要传入一个带有返回值的方法,* 这个时候写function a(){return。。。}就太繁琐了,直接箭头函数简写*/var arr = [12312, 31, 23, 1, 4, 124, 32, 5, 3465, 3];var arr1=arr.sort((a,b)=>a-b);console.log(arr1);
箭头函数问题
箭头函数本质上不是用function关键字定义出来的,不是new Function出来的,而是叫一个胖箭头的操作符来定义的,本质上与函数是两个东西,经常叫它箭头函数,其实它不是函数
有很多区别
var sum = (a, b) => {console.log(arguments);return a + b;}sum(1, 2);//Uncaught ReferenceError: arguments is not defined报错/*箭头函数没有arguments*/
…运算符 spread/rest 运算符
收集方式
… spread/rest 运算符;(用来展开或是收集的)
把传入的参数收集成数组
var sum = (...args) => {console.log(args);/*Array [ 1, 2 ]返回真正的数组,不是类数组*/console.log(args[0]+args[1]);//3}sum(1, 2);
展开方式
把数组展开成一个个变量
function foo(x,y,z){console.log(x,y,z);}foo(...[1,2,3]);//1,2,3foo(...[1,2,3,4,5]);//1,2,3
es5模拟
本质上,或者说用es5的方式去模拟它,怎么模拟?可以用apply实现
function foo(x, y, z) {console.log(this);console.log(x, y, z);}// foo(...[1, 2, 3]);//1,2,3// foo(...[1, 2, 3, 4, 5]);//1,2,3foo.apply(undefined, [1, 2, 3, 4, 5]);//1,2,3foo.apply(null, [1, 2, 3, 4, 5]);//1,2,3

打印window说明执行失败了,没有改变this的指向,只提取数组中的值
数组插入
es6写法
let a=[2,3,4];let b=[1,...a,5];console.log(b);//[1, 2, 3, 4, 5]
es5写法
let a=[2,3,4];// let b=[1,...a,5];console.log([1].concat(a,[5]));//[1, 2, 3, 4, 5]
可以放在最后一位,收集剩余参数
收集,收集的是剩余的所有参数 ,只能放在最后一位
let fn=(a,b,...c)=>{console.log(a,b,c);}fn(1,2,3,4,5,6,7);//1 2 [ 3, 4, 5, 6, 7 ]
放在前面会报错
rest收集,必须是最后一个参数
// SyntaxError: Rest parameter must be last formal parameterlet fn=(...c,a,b)=>{console.log(a,b,c);}fn(1,2,3,4,5,6,7);
具体应用
Array.prototype.slice.call(arguments)用…运算符代替
function sortNum(){return Array.prototype.slice.call(arguments).sort(function(a,b){return a-b;})}console.log(sortNum(12,431,21,12,1,4,135,2,35,25));
const sortNum=(...args)=>args.sort((a,b)=>a-b);console.log(sortNum(12,431,21,12,1,4,135,2,35,25));
es6,箭头函数写法,因为箭头函数没有argument,所以只能用…收集运算符号
(…a)形参与length
console.log((function (a){}).length);//1console.log((function (...a){}).length);//0 不能找到里面的length
console.log((function (b,c,d=0,...a){}).length);//2
内容不少了,消化一下
