函数Function基础知识

函数的声明方法
函数的调用call
this
作用域和闭包

函数声明方法总结

  • 具名函数

    1
    2
    3
    4
    function fn(x,y){
    return x + y;
    }
    fn.name // 'fn'
  • 匿名函数

    1
    2
    3
    function (x,y) {
    return x+y;
    }
  • var fn=匿名函数

    1
    2
    3
    4
    var fn = function(x,y) {
    return x+y;
    }
    fn.name // 'fn'
  • var fn=具名函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var fn = function f2(x,y){
    return x+y
    };
    fn.name // 'f2'
    console.log(f2) // f2 is not defined
    等同于
    var fn;
    fn= function f2(x,y){
    return x+y
    }
  • var fn=new Function()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    参数和函数体都以字符串的形式
    var fn = new Function('x','y','return x+y')
    fn.name // "anonymous"
    面试题:
    var n = 3;
    var fn = new Function('x','y','return x+'+n+'+y');
    问:fn(2,4)的结果是
    A:9
    B:2n4
    C:234
    答案:9
  • ES6箭头函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var fn = (x,y) => {
    return x+y
    };
    fn(2,3); // 5
    如果函数体只有一句话,可以去掉花括号和return
    var sum = (x,y) => x+y;
    sum(4,5); // 9
    如果只有1个参数,可以简写为:
    var fn2 = n => n*n;
    fn2(4); // 16
    箭头函数的复杂写法:
    var fn = (x,y) => {
    const a=x*2;
    const b=y*3;
    return a+b;
    }
    fn(3,5) // 21

eval

eval方法可以将字符串当做代码执行。

1
eval('alert(1)') // 弹出1

eval方法一般很少会使用到。

函数的调用

1
2
3
4
fn(参数1,参数2);
等同于
fn.call(undefined,参数1,参数2);

this和伪数组arguments

this就是call的第一个参数
fn(参数1,参数2)等同于fn.call(undefined,参数1,参数2),因此fn(参数1,参数2)的this是undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
'use strict';
function fn(){
console.log(this);
console.log(arguments);
}
fn.call(1,2,3);
// this为1
//arguments为伪数组[2,3]
fn(1,2,3);
//等同于fn.call(undefined,1,2,3)
// this为undefined
//arguments为伪数组[1,2,3]

this相关面试题

  1. this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.fn ,那么fn中的this就是obj
  2. 在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window (约定俗成)
  3. 在严格模式下’use strict’,没有直接调用者的函数中的this是 undefined
  4. 使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    function f(){
    console.log(this)
    }
    f.call(1)
    // Number对象{1}
    function f1(){
    console.log(this)
    function f2(){}
    }
    var obj = {name: 'obj'}
    f1.call( obj )
    //{name: 'obj'}
    ----------
    function f(){
    'use strict'
    console.log(this)
    }
    f.call(1)
    // 1
    -------------
    function f(){
    console.log(this)
    //console.log(this === window)
    }
    f.call()
    // window
    function f1(){
    function f2(){
    console.log(this)
    }
    f2.call()
    }
    var obj = {name: 'obj'}
    f1.call( obj )
    //window
    ----------
    function f(){
    'use strict'
    console.log(this)
    }
    f.call()
    //undefined
    function f1(){
    'use strict';
    function f2(){
    console.log(this)
    }
    f2.call()
    }
    var obj = {name: 'obj'}
    f1.call( obj )
    //undefined

call stack


普通调用
嵌套调用
递归调用

作用域面试题

最重要的一步:变量提升!!!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var a = 1;
function f1(){
alert(a) // 是多少
var a = 2;// 由于函数内部有变量a了,所以不会访问外部作用域里的a
}
f1(); //undefined
-------------------
var a = 1;
function f1(){
alert(a) // 是多少
}
f1();// 1
f1内部没有变量a,因此会访问全局作用域里的a
----------------------------
var a = 1;
function f1(){
var a = 2; //f1的局部a=2
f2();
}
function f2(){
console.log(a) // 是多少
}
f1(); // 1 由于f2内部没有变量a,因此会访问全局作用域里的a
-----------------------------
var a = 1;
function f1(){
a = 2; //由于f1内部没有声明变量a,因此它赋值给的是全局作用域的a,此时全局a=2
f2();
}
function f2(){
console.log(a) // 是多少
}
f1(); // 2
----------------------
6个li
var lis = document.getElementsByTagName('li');
for(var i = 0; i<lis.length; i++){
lis[i].onclick = function(){
console.log(i) // 点击第3个 li 时,打印 2 还是打印 6?
}
}
//最终结果:6
打印出来的是for循环结束完之后的i
--------------------
var改成let
for(let i = 0; i<lis.length; i++){
lis[i].onclick = function(){
console.log(i) // 点击第3个 li 时,打印 2 还是打印 6?
}
}
//最终结果:0,1,2,3,4,5


ES6中的let

1
2
3
4
5
let a = 1;
{
let a = 2; //这里的a困在花括号内,无法逃到全局作用域里
}
consolelog(a); // 1

闭包面试题

如果一个函数,使用了它外部作用域的变量,那么(这个函数+被使用的变量)就叫做闭包。

1
2
3
4
5
var a = 1;
function f1() {
console.log(a); //访问了外部的全局作用域的变量a
}
f1(); // 1

闭包相关面试题

作业题

1
2
3
4
5
6
7
8
9
10
11
12
var a = console.log(1);
a的值是多少?
答案:undefined
因为console.log的源码是将内容打印出来后,return undefined
alert的源码结尾也是return undefined
----------------------
function f(){
return 1;
}
var a = f();
//a的值是1

逗号表达式
逗号表达式的一般形式是:表达式1,表达式2,表达式3……表达式n
逗号表达式的求解过程是:先计算表达式1的值,再计算表达式2的值,……一直计算到表达式n的值。最后整个逗号表达式的值是表达式n的值。
看下面几个例子:

1
2
3
4
5
6
7
8
9
10
11
var a = (1,2);
a的值为2
-----------
var a = (1, console.log(2));
a的值是undefined,因为console.log的返回值是undefined
x=8*2,x*4 /*整个表达式的值为64,x的值为16*/
(x=8*2,x*4),x*2 /*整个表达式的值为128,x的值为16*/
x=(z=5,5*2) /*整个表达式为赋值表达式,它的值为10,z的值为5*/
x=z=5,5*2 /*整个表达式为逗号表达式,它的值为10,x和z的值都为5*/


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function f(){
return function f2(){}
}
var a = f();
//a的值是函数f2
---------------
function f(){
return function f2(){}
}
var a = f();
var b = a();
等同于 var b = f.call().call()
又等同于 var b = f()(); //前一个括号调用后返回一个函数;后一个括号执行返回的这个函数
//a的值是函数f2
//b的值是undefined,f2没有写ruturn,则默认return undefined
f2();//f2 is not defined,因为f2无法单独执行,必须要通过f()才能执行f2
function f(){
return function f2(){
return 'hello'
}
}
var b = f.call().call();
等同于 var b = f()(); //前一个括号调用后返回一个函数;后一个括号执行返回的这个函数
//b的值为'hello'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function f1(){
console.log(this) // 第一个 this
function f2(){
console.log(this) // 第二个 this
}
f2.call()
}
var obj = {name: 'obj'}
f1.call( obj )
//第一个this为{name: 'obj'}
//第二个this为window,在'use strict'模式下为undefined
第一个this对应的call是f1.call(obj)
第二个this对应的call是f2.call();
-------------本文结束感谢您的阅读-------------