JavaScript函数

释放双眼,带上耳机,听听看~!

函数的定义和调用

函数简介

  • 代码设计的一个原则:可重复利用,即执行相同功能的代码应该只定义一次

  • JS中的alert()、parseInt()、console.log()、document.write()等。

  • 函数:完成特定功能的一段代码(主要要实现可重用性,因此对于函数中的代码越多,那么所完成的功能就越多,重用率也就越低,此外要实现任务分解,将一个大的行为,分解成不同的事件函数)

函数的三要素:(函数名,函数参数,函数返回值)

  • 函数名:如alert、 parseInt 、……

  • 函数的参数:传递给函数名的值,代表将被函数处理的数据,如alert ( ‘hello’ )

  • 函数的返回值:函数执行的返回结果,如confirm(),其返回值为true或false

注意:

(1)函数可以有return,也可以没有return,其中有return返回代表着返回return后面的值,没有return代表返回的是一个undefined值。

(2)函数的参数可以有多个,也可以没有。没有则代表undefined,有则存放在arguments类数组对象中

函数的定义

  • 通过函数声明的形式来定义(要有函数名)

  • 通过函数表达式的形式来定义(可以是没有函数名的匿名函数,有名的话方便调用栈追踪)

  • 通过Function构造函数实例化的形式来定义(JS中函数也是对象,函数对象)

JavaScript函数


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1// 函数的定义方式(三种)
2
3// 第一种:通过函数的声明的方式进行定义
4function max(a, b) {
5    return a > b ? a : b;
6};
7max(2, 3) // 3
8
9// 第二种:函数表达式的形式来表现
10var max = function(a, b) {
11    return a > b ? a : b;
12};
13max(2, 3); // 3
14
15// 第三种:使用new Function()构造函数的方法
16var max = new Function('a', 'b', 'return a>b?a:b'); // 函数参数和函数体
17max(2,3);
18console.log(Function instanceof Function); // true
19console.log(Function instanceof Object); // true
20
21

补充:具名函数和匿名函数

  • 具名函数


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

虽然这种技术可以解决一些问题,但是它并不理想,因为会导致一些额外的问题。首先, 必须声明一个具名函数 foo() ,意味着 foo 这个名称本身“污染”了所在作用域(在这个例子中是全局作用域)。其次,必须显式地通过函数名(foo())调用这个函数才能运行其中的代码。如果函数不需要函数名(或者至少函数名可以不污染所在作用域),并且能够自动运行, 这将会更加理想。

  • 匿名函数


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

函数会被当作函数表达式而不是一个标准的函数声明来处理。 function如果出现在声明中第一个词的位置,就是函数声明 函数表达式意味着函数被直接绑定在作用域中,意味着foo只能再被自己代表的位置被调用,不会污染全局作用域。
匿名函数的缺点在于

  1. 忽略了代码可读性
  2. 在栈追踪中不会显示有意义的函数名,造成调试困难因为没有函数名,所以函数在调用自己时,必须使用过期的argument.callee

函数的调用

  • 作为函数直接调用(非严格模式下this为全局对象,严格模式下为undefined)

  • 作为方法调用(this为调用此方法的对象)

  • 通过call()和apply()间接调用(this为函数对象的call/apply方法的首个参数,移花接木)

  • 作为构造函数调用(this为实例化出来的对象)

JavaScript函数


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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
1// 第一种:直接调用
2function test(){
3   console.log(this);
4}
5test();// window
6
7// 第二种:作为对象的方法使用
8var x = 45;
9var test = function() {
10    console.log(this.x);
11}
12var obj = { x: 23 };
13obj.test = test;
14obj.test(); // 此时的this指代的是当前对象,因此返回的是23
15test(); // test是window下的方法,因此返回的是45
16
17// 对象的方法是嵌套定义的
18var x = 45;
19var obj = {
20    x: 23,
21    test: function() {
22        function foo() {
23            console.log(this.x);
24        }
25        foo();
26    }
27};
28obj.test(); // 此时的this指代的是window,因此返回的是45
29
30var fun1 = function() {
31    return function fun2() {
32        return this.x; //若改为 return this;
33    }
34};
35obj.fun3 = fun1;
36obj.fun4 = fun1();
37/* fun3是一个函数,就是fun1
38    function() {
39      return function fun2() {
40          return this.x; //若改为 return this;
41    }
42    fun4是fun1的返回结果
43    function fun2() {
44        return this.x; //若改为 return this;
45    }
46*/
47console.log(obj.fun3()); //  fun3() 是fun1的返回结果
48console.log(obj.fun3()()); // fun3()() 是this.x this是嵌套函数,指代的是window对象,因此为45
49console.log(obj.fun4()); // fun4() 是this.x this指代的是obj对象,因此为23
50
51// 方法三:通过call() apply()方法
52var obj1 = { name: 'obj1' };
53var obj2 = { name: 'obj2' };
54obj1.foo = function() {
55    console.log(this.name);
56}
57obj1.foo();// obj1
58obj1.foo.call(obj2);// obj2
59obj1.foo.apply(obj2);// obj2
60
61// call apply 综合应用
62var fish = {
63    name: "fish",
64    swim: function(m, n) {
65        console.log("i'm " + this.name + " i cam swim ___", m, n);
66    }
67};
68var bird = {
69    name: "polly",
70    fly: function(m, n) {
71        console.log("i'm:" + this.name + " i can fly ___", m, n);
72    }
73};
74var me = {
75    name: "ABC"
76};
77
78bird.fly(5, 6);
79fish.swim.call(me, 3, 4); // call在参数传递的时候是散列的传递
80bird.fly.apply(me, [7, 8]); // apply在参数传递的时候是数组的形式传递
81var name = 11;
82bird.fly.apply(null, [7, 8]); // null 指向的是全局主体,就是全局下进行bird.fly方法的调用
83
84

函数的参数和返回值

函数的参数的数量问题

JS函数调用时实参数量可以与形参不一致

  • 实参数量大于形参的情况(通过函数对象属性arguments获得所有实参、类数组对象)

  • 实参数量小于形参的情况(少的参数值为undefined、可使用||来给出默认值)

JavaScript函数


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
1// 实参数大于形参数
2function test() {
3    console.log(arguments);// arguments.callee可以看出调用的函数是谁
4    console.log(test.arguments==arguments);//false
5    console.log(arguments.length);// arguemnts.length可以展示参数的个数
6   console.log(typeof arguments);
7   console.log(arguments instanceof Array);//false
8   console.log(arguments instanceof Object);
9    console.log(Array.prototype.slice.call(arguments));// 可以将参数转化为数组的形式
10    var s = "";
11    for (var i = 0; i < arguments.length; i++) {
12        s += arguments[i];
13    }
14    return s;
15}
16test("hello,", "world!");//"hello,world!"
17
18
19//实参数小于形参数
20var sum = function(a,b,c){
21    b = b||4;
22    c = c||5;
23    return a+b+c;
24};
25console.log(sum(1,2,3));// 6
26console.log(sum(1,2));// 8
27console.log(sum(1));// 10
28conosle.log(sum());// undefined + 4 + 5 NaN
29
30

参数类型与传递方式(值、引用)

值传递

实参为基本数据类型时,形参改变不影响实参(值传递)

JavaScript函数

引用传递

实参为引用类型时,形参改变影响实参(引用传递)

JavaScript函数

函数的返回值

  • 返回值可以直接赋予变量或用于表达式中

  • return语句表示结束当前函数的执行,return语句可以不带表达式(例如:return;),return语句不带表达式时仍会返回值,该值为undefined

  • 函数中可以不出现return语句,仍会返回值,该值为undefined

函数对象

函数对象的基本概念

  • JS中的函数也是对象,JS中每个函数都是作为对象来维护和运行的,即函数对象(既有属性也有方法)

  • 可以将函数(函数对象)赋值给一个变量,或将函数作为参数进行传递

  • 函数对象对应的类型是Function(类似于数组对象对应于Array、日期对象对应于Date)

  • 如果变量是函数(函数对象)时,typeof此对象,返回function,而非object

  • 内置的函数对象(Array、Function、Date等),内置的非函数对象(Math、JSON)


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
1function foo() {} //创建了一个函数对象
2console.log(foo); // 输出函数的内容
3console.log(typeof foo); // function
4console.log(foo instanceof Object); // true
5console.log(foo instanceof Function); // true
6console.log(foo === window.foo); // true
7
8console.log(typeof Function); //function
9console.log(typeof Array); //function
10console.log(typeof Date); //function
11console.log(typeof Error); //function
12console.log(typeof Math); //Object
13console.log(typeof JSON); //Object
14
15// 思考题:
16console.log(typeof new Function()); // function
17console.log(typeof new new Function()); // object
18console.log(typeof new Array()); // object
19console.log(typeof new Date()); // object
20
21// 练习:
22var Person = new Function();
23Person = function(name) {
24    console.log(this.name);
25}
26console.log(Person instanceof Function); // true
27console.log(Person instanceof Object); // true
28var a = new Person('jake');
29console.log(a instanceof Function); // false
30console.log(a instanceof Object); // true
31
32

函数对象的属性

  • length、arguments(隐藏的局部变量):判断传入的实参数量是否和形参数量一致


1
2
3
4
5
6
7
8
9
10
11
12
1// length 属性表示形参的个数,arguments.length表示实参的个数
2function checkVarCount(a, b) {
3    if (checkVarCount.length !== arguments.length) {
4        console.log("The count of the parameters you passed into the function doesn't match the function definition.");
5    } else {
6        console.log("Successfully call the function");
7    }
8}
9checkVarCount(1,2);
10checkVarCount(1);
11
12
  • caller、callee(arguments的属性,常用于递归调用)


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
1// caller属性代表着追踪是谁调用了该函数,如果该函数.caller == null表示是window下的函数或者没有被调用
2
3// example 1
4function test() {
5    if (test.caller == null) {
6        console.log("test is called from the toppest level");
7    } else {
8        console.log("test is called from the function:");
9        console.log(test.caller.toString()); // 将函数转换为字符串的形式,不加.toString()会将这个函数输出
10    }
11}
12console.log("没有调用的情况下test.caller为:", test.caller); // null
13test();  // 最高层次的调用
14function testOuter() {
15    test();
16}
17testOuter();
18
19// example2
20var obj = {
21    foo1: function() {
22        console.log(this.foo1.caller);
23    },
24    foo2: function abc() {
25        this.foo1();
26    }
27};
28obj.foo1(); // null 表示没有调用者
29obj.foo2(); // foo2()函数
30
31//callee函数 返回正在被执行的function对象,即指定的 Function 对象的正文 -->递归; callee 属性是 arguments 对象的一个成员
32//该属性仅当相关函数正在执行时才可用。通常这个属性被用来递归调用匿名函数
33var func = function(n) {
34    if (n <= 0)
35        return 1;
36    else
37        return n * func(n - 1);//return n * arguments.callee(n - 1);
38};
39console.log(func(4));
40
41(function func(n){
42    if(n<=0){
43        return 1;
44    }else{
45        return n*arguments.callee(n-1);
46    }
47})(4);
48
49
  • prototype:获取对象的原型。每一个构造函数都有一个prototype属性,指向另一个原型对象。这个原型对象的所有属性和方法,都会被构造函数的实例继承。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1function Man(name, age) {
2    this.name = name;
3    this.age = age;
4}
5Man.prototype.sex = "M";
6Man.prototype.sayHi = function() {
7    console.log("Hi,i'm", this.name);
8};
9var li = new Man("Leo", 10);
10li.sayHi(); //调用原型的方法 Hi,i'm Leo
11console.log(li.sex); //M
12Man.prototype.isStrong = true; //原型上添加一个属性isStrong
13console.log(li.isStrong); //true
14
15

函数对象的方法

  • call、apply:移花接木,吸星大法,call是散列传递,apply是数组传递

  • bind:bind 绑定,给函数对象绑定调用的对象实体

  • toString、valueOf


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
1// bind 绑定,给函数对象绑定调用的对象实体
2var x = 45;
3var obj = {
4    x: 23,
5    test: function() {
6        function foo() {
7            console.log(this.x);
8        }
9        foo.bind(this)(); // 23 var fee = foo.bind(this); fee(); 此时的this指向的是obj对象,因此就给foo中的this绑定成obj对象调用
10        foo();// 递归调用this指向的是window 因此为45
11    }
12};
13obj.test();
14
15var check = function(value) {
16    if (typeof value !== 'number')
17        return false;
18    else
19        return value >= this.minimum && value <= this.maximum;
20};
21var range = { minimum: 10, maximum: 20 };
22var bindCheck = check.bind(range); // 给check这个函数中的this绑定给了range对象,并把函数赋值给bindcheck这个函数对象 绑定的结果是一个函数对象
23var result = bindcheck(12); //把bindcheck的结果给了result 相当于range.check(12)
24console.log(result); //true
25
26// 该绑定函数将 bind 方法中指定的参数用作第一个参数和第二个参数。在调用该绑定函数时,指定的任何参数将用作第三个、第四个参数(依此类推)
27var displayArgs = function(val1, val2, val3, val4) {
28    console.log(val1 + " " + val2 + " " + val3 + " " + val4);
29};
30var emptyObject = {};
31var displayArgs2 = displayArgs.bind(emptyObject, 12, "a");
32displayArgs2("b", "c"); // Output: 12 a b c
33
34

高阶函数

高阶函数是指至少满足下列条件之一的函数

  • 函数作为参数被传递(最常见的形式:回调函数)

  • 函数作为返回值输出(与闭包有紧密联系)


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
1// part1 函数作为参数被传递
2function add(x, y, f) {
3    return f(x) + f(y);
4}
5add(2, 3, function(z) { return z * z; }); // 13
6add(2, -3, Math.abs); // 5
7add(2, 3, Math.sqrt); //2的开平方加3的开平方
8练习使用高阶函数实现下述公式,要求函数复用
9z = 2*(x+1)-3*y*y;
10c = 2*a*a-3*(b-1);
11k = 2*(i+1)-3(j-1);
12function foo(x,y,c1,c2){
13    return 2*c1(x)-3*c2(y);
14}
15function f1(x){
16    return x+1;
17}
18function f2(x){
19    return x-1;
20}
21function f3(x){
22    return x*x;
23}
24foo(1,1,f1,f3);//1
25foo(1,1,f3,f2);//2
26foo(1,1,f1,f2);//4
27
28var word_2 = "do another thing.";
29var function_1 = function(callback) {
30    this.word_1 = "do something.";
31    console.log(this); // 全局下的函数 window
32    console.log(this.word_1);
33    (callback && typeof(callback) === "function") && callback();
34};
35var function_2 = function() { console.log(this.word_2) }; //function2是一个函数对象
36function_1(function_2); // 把函数对象作为参数传入function1函数
37function pow(x) {
38    return x * x;
39}
40var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
41arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81] map相当于映射
42
43//filter 数组过滤 ,返回为false的将被过滤掉
44var arr = [1, 2, 4, 5, 6, 9, 10, 15];
45var r = arr.filter(function(x) {
46    return x % 2 !== 0;
47});
48r; // [1, 5, 9, 15]
49
50// part2:函数作为返回值输出
51var x = 12;
52var obj = {
53    x: 34,
54    fun2: function() {
55        console.log(this.x, this);
56    }
57};
58var fun1 = function() {
59    return function fun2() {
60        return this.x; //若改为 return this;
61    }
62};
63obj.fun3 = fun1; // fun3就是一个函数对象,fun3的内容就是fun1的内容
64obj.fun4 = fun1(); // fun4也是一个函数对象,fun4的内容是fun1的return的结果
65
66

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C++异常

2022-1-11 12:36:11

安全技术

5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq

2022-1-11 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索