函数的length属性

函数有length属性

  1. function test(){
  2. }
  3. // test(1);
  4. console.log(test.length);//0
  1. function test(a, b) {
  2. }
  3. test(1);
  4. console.log(test.length);//2

函数默认值对length的影响

  1. function test(a,b,c=1){
  2. }
  3. test(1);
  4. console.log(test.length);//2
  1. function test(c=1,a,b){
  2. }
  3. test(1);
  4. console.log(test.length);//0

还是2,因为c=1赋予参数默认值的时候,它自己这位不算在length里面,并且后面无论赋不赋参数,都不算到length参数里面

  1. function test(a,b,c=1,d){
  2. }
  3. test(1);
  4. console.log(test.length);//2

形参默认值与argument

argument与形参有映射关系,但不是一个东西

  1. function test(a, b, d, e, f) {
  2. console.log(arguments);//[Arguments] { '0': 1 }
  3. }
  4. test(1);
  5. console.log(test.length);//5
  1. function test(a, b, d, e, f) {
  2. arguments[1]=7;
  3. console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
  4. console.log(b);//7
  5. }
  6. test(1,2,3,4,5,6);
  7. console.log(test.length);//5

arguments可以更改实参,对形参有影响

  1. function test(a, b, d=1, e, f) {
  2. arguments[1]=7;
  3. console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
  4. console.log(b);//2
  5. }
  6. test(1,2,3,4,5,6);//1,2,3,4,5,6是实参
  7. console.log(test.length);//2

形参、实参、argument与默认值的关系

  1. /*a,b,d,e,f是形参,把实参赋值给形参,实参就没有什么用处了,AO中一直存在的是形参,不是实参,只不过形参的值是实参的值,
  2. * argument也不是实参,只不过与实参、形参有映射关系,但这个关系会被默认值影响,如果任何参数有默认值,即使是最后一位,
  3. *有默认值,所有形参都不再与argument有映射关系*/
  4. function test(a, b, d=1, e, f) {
  5. arguments[1]=7;
  6. console.log(arguments);//[Arguments] { '0': 1, '1': 7, '2': 3, '3': 4, '4': 5, '5': 6 }
  7. console.log(b);//2
  8. }
  9. test(1,2,3,4,5,6);
  10. /*1,2,3,4,5,6是实参,函数运行存入的值是实参*/
  11. console.log(test.length);//2

解构赋值与形参

形参无默认值,不传值时会报错,兼容性不好

  1. function foo({x,y=5}){
  2. console.log(x,y);
  3. }
  4. foo({});//undefined 5
  5. foo({x:1});//1 5
  6. foo({x:1,y:2});//1 2
  7. foo({});//undefined 5
  8. foo()//TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
  9. /*这样如果什么都不传的情况下,就会报错,代码终止运行,体验不好*/

给解构赋值的形参赋予默认值,兼容性好的写法

  1. /*这样写,即使foo()什么都不传也不会报错了,做了兼容性处理*/
  2. function foo({x, y = 5} = {}) {
  3. console.log(x, y);
  4. }
  5. foo({});//undefined 5
  6. foo({x: 1});//1 5
  7. foo({x: 1, y: 2});//1 2
  8. foo({});//undefined 5
  9. foo()//undefined 5

这里面用到了兼容性
image.png

let x=x的探究

  1. // var x=x;
  2. /*先不走let x;先走x=x*/
  3. let x=x;
  4. console.log(x);
  5. /*ReferenceError: Cannot access 'x' before initialization*/

解析
不是如下这样运行的,结果都不一样

  1. let x;
  2. x=x;
  3. console.log(x);//undefined

是这样运行的,结果一样

  1. x=x;//ReferenceError: Cannot access 'x' before initialization
  2. let x;
  3. console.log(x);//undefined
  1. function foo(x=x){
  2. //ReferenceError: Cannot access 'x' before initialization
  3. }
  4. foo()

调试

  1. var x = 1;
  2. /*调用栈,函数调用栈,赋默认值*/
  3. /*
  4. 这个块级作用域里面x的值从里面取 x=>1=>2
  5. function foo({(let)x=1,(let)y = function () {
  6. x = 2;
  7. console.log(x);}})
  8. 参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,
  9. 如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁
  10. 即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},
  11. 之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁
  12. 也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了
  13. */
  14. function foo(x = 1, y = function () {
  15. var x = 2;
  16. console.log(x);//2
  17. }
  18. ) {
  19. x = 3;
  20. y();
  21. console.log(x);
  22. }
  23. foo();//2 3
  24. console.log(x);//1

火狐浏览器
调试器,在foo上打断点
image.png
刷新浏览器

image.png
点击步进
image.png

范围就是scope
image.png

  1. var x = 1;
  2. /*调用栈,函数调用栈,赋默认值*/
  3. /*
  4. 这个块级作用域里面x的值从里面取 x=>1=>2
  5. function foo({(let)x=1,(let)y = function () {
  6. x = 2;
  7. console.log(x);}})
  8. 参数赋予默认值,是一个运算,需要运行,产生作用域,产生运行作用域,
  9. 如上图,之后把得出来的值传给函数AO,函数需要AO中的形参来运行,之后那个块级作用域销毁
  10. 即使没有赋予默认值,只要传参了,也可以理解成{x=实参(包括undefined),y=实参},
  11. 之后把得出来的x,y传给函数的AO,之后{x,y}的块级作用域销毁
  12. 也可以理解成,不销毁继续调用,函数调用y()行成了闭包,不销毁了
  13. */
  14. function foo(x = 1, y = function () {
  15. x = 2;
  16. console.log(x);//2
  17. }
  18. ) {
  19. x = 3;
  20. y();
  21. /* y = function () {
  22. x = 2;
  23. console.log(x);//2
  24. }
  25. 其实就是在这里运行了这段代码,改变了x的值,x从哪里找,从这里找,从AO中找
  26. */
  27. console.log(x);//2
  28. }
  29. foo();//2 2
  30. console.log(x);//1

类似于

  1. {
  2. let x=2;
  3. {
  4. x=3;
  5. console.log(x);
  6. }
  7. console.log(x);
  8. }

this指向

见之前笔记

  1. function foo() {
  2. console.log(this.a);
  3. // console.log(this);
  4. }
  5. var obj = {
  6. a: 2,
  7. foo: foo
  8. }
  9. obj.foo();//2
  10. window.obj.foo();//2
  11. /*因为bar接收obj.foo对象,赋予地址,没有运行,bar在window下,其实就是window调用*/
  12. var bar = obj.foo;
  13. bar();//undefined
  14. window.bar();//undefined
  15. let bar1 = obj.foo;
  16. bar1();//undefined
  17. /*bar1的this也是window*/

image.png

箭头函数

参数是一个时可以省略,可以简写,如果函数里面只有一个return语句时,也可以简写
返回值只能有一个,因为走完第一个return函数就停止运行了,但可以返回对象,或者数组,里面有多个变量、多个函数,也可以返回函数
只有一个参数的情况

参数是一个,函数内语句只有一个return时,可以简写

  1. // ()=>{}
  2. var f = a => a;
  3. var f = (a) => a;
  4. var f = (a) => {
  5. return a;
  6. };
  7. var f = function (a) {
  8. return a;
  9. }

参数不是是一个,不可以简写

2.参数不是一个的情况
0个参数必须写()括号

  1. var f = () => 5;
  2. function f(){
  3. return 5;
  4. }
  1. /*Uncaught SyntaxError: Identifier 'f' has already been declared*/
  2. // let f=(a,b)=>a+b;
  3. var f=(a,b)=>a+b;
  4. function f(a,b){
  5. return a+b;
  6. }

箭头函数表达式

说箭头函数的时候,一般说的是箭头函数表达式

说箭头函数的时候,一般说的是箭头函数表达式

  1. /*箭头函数*/
  2. ()=>{
  3. }
  4. /*想给其赋值,这样写不合法*/
  5. test()=>{
  6. }

image.png

这样写也没用

  1. var test = (() => {
  2. })

只有给箭头函数赋值才能够保存箭头函数,之后才可以调用箭头函数

  1. var test = () => {
  2. }

多重语句

多重语句必须写{}大括号,没有返回值,默认返回值是undefined

  1. let f = (a,b) => {
  2. var a=3;
  3. var b=4;
  4. console.log(a+b);//7
  5. }
  6. console.log(f())//undefined
  1. /*当语句只有一条,返回但是语句的执行结果,当只有一条return语句时,就可以省略{}大括号与return*/
  2. var f = (a,b) => a+b;
  3. /* var f = (a,b) => {
  4. return a+b;
  5. };*/
  6. console.log(f())//undefined

箭头函数应用

  1. //通过解构赋值来结合
  2. const full = ({first, last} = {}) => first + '' + last;/* +‘’转成字符串*/
  3. console.log(full({first: 3, last: 5}));//35
  1. /*从小到大排序,通过箭头函数可以简化代码,箭头函数具体应用,有些方法需要传入一个带有返回值的方法,
  2. * 这个时候写function a(){return。。。}就太繁琐了,直接箭头函数简写*/
  3. var arr = [12312, 31, 23, 1, 4, 124, 32, 5, 3465, 3];
  4. var arr1=arr.sort((a,b)=>a-b);
  5. console.log(arr1);

箭头函数问题

箭头函数本质上不是用function关键字定义出来的,不是new Function出来的,而是叫一个胖箭头的操作符来定义的,本质上与函数是两个东西,经常叫它箭头函数,其实它不是函数
有很多区别

  1. var sum = (a, b) => {
  2. console.log(arguments);
  3. return a + b;
  4. }
  5. sum(1, 2);//Uncaught ReferenceError: arguments is not defined报错
  6. /*箭头函数没有arguments*/

…运算符 spread/rest 运算符

收集方式

… spread/rest 运算符;(用来展开或是收集的)
把传入的参数收集成数组

  1. var sum = (...args) => {
  2. console.log(args);/*Array [ 1, 2 ]返回真正的数组,不是类数组*/
  3. console.log(args[0]+args[1]);//3
  4. }
  5. sum(1, 2);

展开方式

把数组展开成一个个变量

  1. function foo(x,y,z){
  2. console.log(x,y,z);
  3. }
  4. foo(...[1,2,3]);//1,2,3
  5. foo(...[1,2,3,4,5]);//1,2,3

es5模拟

本质上,或者说用es5的方式去模拟它,怎么模拟?可以用apply实现

  1. function foo(x, y, z) {
  2. console.log(this);
  3. console.log(x, y, z);
  4. }
  5. // foo(...[1, 2, 3]);//1,2,3
  6. // foo(...[1, 2, 3, 4, 5]);//1,2,3
  7. foo.apply(undefined, [1, 2, 3, 4, 5]);//1,2,3
  8. foo.apply(null, [1, 2, 3, 4, 5]);//1,2,3

image.png
打印window说明执行失败了,没有改变this的指向,只提取数组中的值

数组插入

es6写法

  1. let a=[2,3,4];
  2. let b=[1,...a,5];
  3. console.log(b);//[1, 2, 3, 4, 5]

es5写法

  1. let a=[2,3,4];
  2. // let b=[1,...a,5];
  3. console.log([1].concat(a,[5]));//[1, 2, 3, 4, 5]

可以放在最后一位,收集剩余参数

收集,收集的是剩余的所有参数 ,只能放在最后一位

  1. let fn=(a,b,...c)=>{
  2. console.log(a,b,c);
  3. }
  4. fn(1,2,3,4,5,6,7);//1 2 [ 3, 4, 5, 6, 7 ]

放在前面会报错
rest收集,必须是最后一个参数

  1. // SyntaxError: Rest parameter must be last formal parameter
  2. let fn=(...c,a,b)=>{
  3. console.log(a,b,c);
  4. }
  5. fn(1,2,3,4,5,6,7);

具体应用

Array.prototype.slice.call(arguments)用…运算符代替

  1. function sortNum(){
  2. return Array.prototype.slice.call(arguments).sort(function(a,b){
  3. return a-b;
  4. })
  5. }
  6. console.log(sortNum(12,431,21,12,1,4,135,2,35,25));
  1. const sortNum=(...args)=>args.sort((a,b)=>a-b);
  2. console.log(sortNum(12,431,21,12,1,4,135,2,35,25));

es6,箭头函数写法,因为箭头函数没有argument,所以只能用…收集运算符号

(…a)形参与length

  1. console.log((function (a){}).length);//1
  2. console.log((function (...a){}).length);//0 不能找到里面的length
  1. console.log((function (b,c,d=0,...a){}).length);//2

内容不少了,消化一下