一、参数默认值


1没有传入实参时,形参默认值为undefined
2可以在函数定义时,设置默认值(ES6写法)

image.png
1 undefined
image.png
1 2
image.png
1 2
image.png
1 2
arguments可能是undefined,a的默认值也有可能是undefined,谁不是undefined就取谁,都是undefined就是undefined
没有特地赋予默认值就是undefined

test(1,2)是给arguments[0]=1,argument[1]=2赋值,arguments和实参a,b是影射关系,就对比啊a、b、argument[0]、argumet[1]的值,对比实参、arguments的值
主要取决于arguments的值,怎么给arguments

  1. function test(a = 1, b) {
  2. console.log(a); // 1
  3. console.log(b); // undefined
  4. }
  5. test();
  1. function test(a = 1, b) {
  2. console.log(a); // 1
  3. console.log(b); // undefined
  4. }
  5. test(2,3);

2,3

  1. function test(a = 1, b) {
  2. console.log(a); // 2
  3. console.log(b); // 3
  4. arguments[0]=1;
  5. console.log(a)//2
  6. console.log(arguments[0])//1
  7. a=6;
  8. console.log(arguments[0]);//1
  9. }
  10. test(2,3);

是映射关系,只有在函数传实参时是映射关系,之后再函数内部改a,b,argumets就没用了
因为a、b都是形参,函数里面的ab都是形参,test(2,3) 2,3是实参,argumets与实参有关与形参无关,argumentes与实参有对应关系

错了有映射关系,但默认参数影响了

  1. function test(a , b) {
  2. console.log(a); // 2
  3. console.log(b); // 3
  4. arguments[0] = 5;
  5. console.log('a',a); //5
  6. console.log(arguments[0]); //5
  7. a = 6;
  8. console.log(arguments[0]); //6
  9. }
  10. test(2, 3);
  11. console.log('-----------')
  12. function test2(a=1 , b) {
  13. console.log(a); // 2
  14. console.log(b); // 3
  15. arguments[0] = 5;
  16. console.log('a',a); //2
  17. console.log(arguments[0]); //5
  18. a = 6;
  19. console.log(arguments[0]); //5
  20. }
  21. test2(2, 3);
  1. function test(a, b, c) {
  2. arguments[0]=6;
  3. console.log(a)//6
  4. a = 3;
  5. c = 5;
  6. console.log(arguments[0]); // 3
  7. console.log(arguments[2]); // undefined
  8. }
  9. test(1, 2);

设置默认值的方法

给形参直接赋值(a=1)是es6的写法,低版本浏览器可能不兼容
1.ES6写法。
2.使用typeof操作符检测某个参数是否等于undefined,如果是则意味着没有传入这个参数,那就给它赋一个值。
3.使用arguments对象判断是否传入实参:

  1. function test1(a, b) {
  2. ///var a=a||2; //不推荐这么写,因为与实参是一一对应的
  3. var a = arguments[0] || 2;
  4. var b = arguments[1] || 3
  5. console.log(a + b);
  6. }
  7. test(); // 5
  8. function test2(a, b) {
  9. var a = typeof(arguments[0]) === 'undefined' ? 2 : arguments[0];
  10. var b = typeof(arguments[1]) === 'undefined' ? 3 : arguments[1];
  11. console.log(a + b);
  12. }
  13. test2(); // 5

二、递归


1找出规律。
2找出递归出口。
image.png
先找规律,再找出口,避免无限循环
image.png
return1结果不是1,因为有队列
image.png
当fact(1)有确定值1时,fact(2)的值确定,之后fact345…
image.png
递归慎用,for循环更好
image.png
image.png

三、预编译

处理代码过程

1 检查通篇的语法错误

语法分析也叫语义分析,语法分析他是通篇执行的一个过程,比如我写了好多行代码,这些代码在执行的时候他是解释一行执行一行,但是在执行之前系统执行的第一步它会扫描一遍,看看有没有低级的语法错误,比如少些个符号,带个特殊字符之类的,它会通篇扫描一遍,但是不执行,这个通篇扫描的过程叫语法分析,通篇扫描之后它会预编译,然后在解释一行执行一行,也就是解释执行。

  1. console.log(a);
  2. console.log(a);//中文的; 不是英文的
  3. console.log(a);

打印Uncaught ReferenceError: a is not defined

  1. console.log(a);
  2. // console.log(a);//中文的; 不是英文的
  3. console.log(a);

打印Uncaught ReferenceError: a is not defined

结论:

先检查语法错误,如果有语法错误 ,先暴露出来问题 ,不执行接下来的步骤

未定义变量不属于语法层面的错误,属于语法应用错了,语法应用的错误不会在一开始执行报错,语法应用的错误会阻碍另一个语法错误的执行 。

短路原则:

当有语法错误时,发现第一个语法错误时,打印发现的错误, 之后的语法错误不检查。

原因:假设代码很长,错误很多,如果一开始就有错误,之后再检查或执行所有代码的那就太蠢了,看到结果的速度会很慢,并且结果并不会改变,也造成了能源的浪费,费电费、费cpu。

1.5 预编译的过程
2 解释一行 执行一行

什么是预编译?
预编译打个比方就像对代码就行初步的加工,在就行处理执行。

过程

ao
1 先寻找并提取变量声明(变量声明包括形参)
2再把实参的参数值赋值给行参
3再寻找函数体声明,赋值函数体
4 再执行函数
go
1找变量
2找函数声明
3执行

简化
Ao
形参声明、变量声明
形参赋值
函数声明

Go
变量声明
函数声明

ao多了形参声明、形参赋值

预编译过程

1.通篇的检查语法错误
1.5 预编译的过程
2.解释一行执行一行

2. 函数执行之前进行的步骤

  1. 创建 AO对象 -> AO activation object 活跃对象, 函数上下文 =>环境
    2. 寻找函数中的形参和变量声明
    3. 将实参赋值给形参
    4. 寻找函数体内函数声明 赋值函数体
    5. 执行(赋值等操作)

    3. 全局上下文 =>环境

  2. 创建 GO对象 -> 全局上下文 ===window
    2. 寻找变量声明
    3. 寻找函数声明
    4. 执行(赋值等操作)

    精简

    ao:形参声明 赋值,变量、函数声明
    go:变量、函数声明

ao:1形参声明 赋值 2变量声明 3函数声明
go:1变量声明 2函数声明
有先后顺序

预编译分析

  1. function test(a) {
  2. console.log(a); // function a() {}
  3. var a = 1;
  4. c=2
  5. console.log(a); // 1
  6. function a() {}
  7. console.log(a); // 1
  8. var b = function () {};
  9. console.log(b); // function() {}
  10. function d() {}
  11. }
  12. test(2);

分析1

执行前

1 先寻找并提取变量声明寻找形参和变量声明

GO={test:func}

看见test函数执行了 test(2) 所以有了AO,通过test(a)得到a变量,var b得到b变量,写了c=2也不算,只有通过var出来的才是
AO={
a:undefine
b:undefine
}

2 再把实参的参数值赋值给行参

通过test(2)得知
AO{
a:undefine->2
b:undefine
}

3.再寻找函数体声明,赋值函数体

  1. 找函数声明,只有function 变量(){}才是,var b = function () {};不是<br /> AO{<br /> a:undefine->2-> function a(){}<br /> b:undefine<br /> d:function d(){}<br /> }

执行后

再执行函数:
执行函数从上往下依次执行,执行经过预编译的代码,函数声明相当于提到最前面声明了,原来地方就没有了,相当于源代码没有写
c=2因为没有写var所以,不是声明,不参与预编译,执行函数时才执行,c=2是在函数内部写的,没有写var提升到全局GO里

GO={func:test,c:2}

AO={
a:undefine->2-> function a(){}->1
b:undefine->function()
d:function d(){}
}

简化1

Undo
GO={test:func}
AO={a:u->2->func,b:u,d:func}

do
GO={test:func,c:2}
AO={a:u->2->func->1,b:u->func,d:func}

简化2

GO={test:func,(do)c:2}
AO={a:u->2->func->(do)1,b:u->func,d:func}

GO={test:func,c:2}
AO={a:u->2->func->1,b:u->func,d:func}

代码分析

  1. test(); //1
  2. function test() {
  3. console.log(1);
  4. }
  5. console.log(a); //u
  6. var a;
  7. console.log(a);//u
  8. a = 2;
  9. console.log(a);//2

结果1 undefined undefined 2

undo

GO={a:u,test:func}

do

GO={a:u->2,test:func}

GO={a:u->func a->(do)2}

  1. console.log(a, b); // function a() {} undefined
  2. function a() {}
  3. var b = function () {};

GO={b:u->(d)func,a:func}

  1. function test() {
  2. var a = (b = 1);
  3. console.log(a); // 1
  4. }
  5. test();

undo
GO={test:func}
AO={a:u}
do
GO={test:func,(do)b->1}
AO={a:u->b->1}

var a = b = 1; 可以拆分成var a=b;b=1;
a从undefine到b,当b取值为1时确定下来为1

  1. var b = 3;
  2. console.log(a); // function a(a) {}
  3. function a(a) {
  4. console.log(a); // function a() {}
  5. var a = 2;
  6. console.log(a); // 2
  7. function a() {}
  8. var b = 5;
  9. console.log(b); // 5
  10. }
  11. a(1);

undo GO={b:u,a:func a(a){…}}
AO={a:u->func a(){},b:u}

do GO={b:u->3,a:func a(a){…}}
AO={a:u->1->func a(){}->2,b:u->5}

  1. a = 1;
  2. function test() {
  3. console.log(a); // undefined
  4. a = 2;
  5. console.log(a); // 2
  6. var a = 3;
  7. console.log(a); // 3
  8. }
  9. test();
  10. var a;
  11. console.log(a)//1

GO={test:func,a:u}
AO={a:u}

do GO={test:func,a:u->1}
AO={a:u->2->3}

  1. function test() {
  2. console.log(b); // undefined
  3. if (a) {
  4. var b = 2;
  5. }
  6. c = 3;
  7. console.log(c); // 3
  8. }
  9. var a;
  10. test();
  11. a = 1;
  12. console.log(a); // 1

undo
GO={test:func test(){…},a:u}
AO={b:u}
do
GO={test:func test(){…},a:u->1,c->3}
AO={b:u}

有if预编译也会直接看if里面的,if表达式预编译优先级很高,

预编译执行if里面的语句

作业

  1. function test() {
  2. // 遇到return直接返回
  3. return a;
  4. a = 1;
  5. function a() {}
  6. var a = 2;
  7. }
  8. console.log(test()); // function a() {}

AO={a:u->func a(){}}

return 直接终止函数运行,相当于return后面的没有写

  1. function test() {
  2. a = 1;
  3. function a() {}
  4. var a = 2;
  5. return a;
  6. }
  7. console.log(test()); // 2

undo

GO={test:func}

AO={a:func a}

do

GO={test:func,a->1}

AO={a:func a->2}

题目

  1. a = 1;
  2. function test(e) {
  3. function e() {}
  4. console.log(e); // func
  5. arguments[0] = 2;
  6. console.log(e); // 2
  7. // 此时变量a的值为undefined,不执行if语句内容
  8. if (a) {
  9. var b = 3;
  10. }
  11. var c;
  12. a = 4;
  13. var a;
  14. console.log(b); // undefined
  15. // 暗示全局变量
  16. f = 5;
  17. console.log(c); // undefined
  18. console.log(a); // 4
  19. }
  20. var a;
  21. test(1);
  22. console.log(a); // 1
  23. console.log(f); // 5

undo GO={test:func,
a:u}
AO={e:u->1->func e,
b:u,
c:u,
a:u}

do GO={test:func,
a:u->1,
f->5}
AO={e:u->1->func e->2,
b:u,
c:u,
a:u->4}
image.png

面试题

  1. // Number(false) -> 0
  2. var a = false + 1;
  3. console.log(a); // 1
  4. //----------------------------------
  5. // Number(false) -> 0
  6. var b = false == 1;
  7. console.log(b); // false
  8. //------------------------------------
  9. /**
  10. * typeof(a) -> 'undefined'
  11. * (-true) -> Number(-true) -> -1
  12. * (+undefined) -> Number(+undefined) -> NaN
  13. * -1 + NaN + '' -> 'NaN'
  14. * 'undefined' && 'NaN' -> 'NaN'
  15. * Boolean('NaN') -> true
  16. */
  17. if (typeof(a) && (-true) + (+undefined) + '') {
  18. console.log('通过了'); // 执行
  19. } else {
  20. console.log('没通过');
  21. }
  22. //-----------------------------------------------------------------
  23. /**
  24. * 5 * '3' -> 5 * Number('3') -> 15
  25. * 1 + 15 === 16 -> true
  26. */
  27. if (1 + 5 * '3' === 16) {
  28. console.log('通过了'); // 执行
  29. } else {
  30. console.log('未通过');
  31. }
  32. //----------------------------------------------------------------
  33. /**
  34. * Boolean(' ') -> true
  35. * Boolean(') -> false
  36. * Boolean(false) -> false
  37. * true + false - false || '通过了'
  38. * Number(true) + Number(false) - Number(false) || '通过了'
  39. * 1 + 0 - 0 || '通过了'
  40. * 1 || '通过了'
  41. * 1
  42. */
  43. console.log(!!' ' + !!'' - !!false || '通过了'); // 1