专栏首页水击三千JavaScript函数(二)

JavaScript函数(二)

在前面我们已经对函数作了简单的介绍,比如函数的定义、函数的声明、函数的调用和函数的传参等。本节将进一步介绍函数的应用,深度理解函数的各种使用。

函数是一个对象,每个函数时Function类型的一个实例,与其他引用类型一样有属性和方法。由于函数时对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是函数声明语法定义的。

function sum(x,y){
                    return x+y;
                }

上面使用函数声明语法定义的。

var sum=function(a,b){
                    return a+b;
                };

上面使用函数表达式声明了一个函数。定义了变量sum,并将其初始化为一个函数。在使用函数表达式定义函数时,没有必要使用函数名。通过变量sum可以引用函数,另外函数的末尾有个分号,与普通的变量定义一样。

另外可以使用Function构造函数来定义函数。Function构造函数可以定义任何数量的参数,最后一个函数被看成是函数体。

var sum= new Function("a","b","return a+b");
function sum(a,b){
                    return a+b;
                }
                var anotherSum=sum;
                console.log(sum(1,2));
                sum=null;
                console.log(anotherSum(2,3));

上面定义了函数sum,用于求两个数之和。定义了变量anotherSum,并将sum赋值给anthorSum。这样anotherSum与sum指向了同一个指针。最后调用的时候,即使将sum=null,依然可以调用anotherSum。

var sum=function(a,b){
                    return a+b;
                }
                sum=function(a,b){
                    return a*b;
                }
                console.log(sum(2,4));//输出8

上面的代码可以清楚地看出函数时没有重载的。后定义的sum将前面的sum覆盖。

JavaScript解析器在执行环境时,对于函数声明和函数表达式定义的函数并不是一视同仁的。解析器会先调用函数的声明,在执行其他代码之前可用。函数表达式,只有当函数执行到当前行,才会被解释执行。

console.log(sum(2,3));//输出5
                function sum(a,b){
                    return a+b;
                }
                console.log(subtract(2,3));//报错,subtract is not function
                var subtract=function(a,b){
                    return a*b;
                }

上面的代码可以看出区别。函数的声明在调用前已经添加到执行环境中,会将函数声明添加到顶部环境中。而通过函数表达式定义的函数,在声明变量前,就调用会发生错误。经过上面的比较,不管是函数声明,还是函数表达式,我们都要养成先定义,再使用的习惯。

JavaScript函数本身就是变量,所以函数可以作为值来使用。函数不仅可以作为参数来传递,而且可以将函数作为另一个函数的结果返回。

function callFunction(func,num){
					return func(num);
				}
				function sum(num){
					return num+10;
				}
				console.log(callFunction(sum,10));

  上面的代码就是将函数作为另一个函数的结果返回,输出20.

函数内部包含一个子函数,并且返回子函数,这就是所谓的函数闭包。闭包的好处就是可以缓存数据。

function closeTest(){
                    var n=1;
                    Add=function(){
                        n=n+1;
                    }
                    return function F(){
                        return n+1;
                    }
                }
                var result = closeTest();
                console.log(result());
                Add();
                console.log(result());

上面的代码就是一个闭包函数。在闭包函数内部可以使用函数的内部变量。第一个调用result,返回2.第二次调用result输出3,因为前面已经调用了add方法,将n+1,所以最好输出的结果是3.

var name = "The Window";
              var object = {
                name : "My Object",
                getNameFunc : function(){
                  return function(){
                    return this.name;
                  };
                }
              };
            var  result=object.getNameFunc();
              console.log(result());//undefined,this的指向是window

通过上面的代码可以看清楚,调用result方法的时候,this指向了window,this.name为undefined

var name = "The Window";
              var object = {
                name : "My Object",
                getNameFunc : function(){
                  return function(){
                    return this.name;
                  }.bind(this);
                }
              };
            var  result=object.getNameFunc();
              console.log(result());//My Object

这个代码我们加了bind方法,bind函数用于改变this的指向。this.name指向的是object对象,所以result有输出值。bind函数并不会立即执行,当调用该函数的时候才会执行,同时bind函数可以给函数绑定参数。

var substract=function(a,b){
                return a*b;
            };
                var sum=function(a,b){
                    var that=this;
                    console.log(that);
                    return a+b;
                }.bind(substract,3,4);
                console.log(sum(1,2));//输出7

上面的代码使用bind函数改变了sum函数的this指向,this指向了substract函数,同时为sum添加了两个参数3,4.虽然我在调用的时候又传递了参数1,2,但是我们bind的参数值是在前面的,所有输出7.arguments[2]=1,arguments[3]=2。传递的参数通过arguments依然可以访问到。

函数还有两个常用的方法apply和call。apply和call两个方法的效果是改变函数的指向,并能传递参数,但是立即执行。apply第一个参数是对象,用于改变函数的this指向;第二个参数是数组,是传递给函数的值。call的第一个参数与apply一样,但是call的第二个参数不是数组,与bind类似,参数是一个一个传递的。

function sayHello(str){
                    console.log(str);
                }
                sayHello.bind(this,"bind");
                sayHello.call(this,"call");
                sayHello.apply(this,["apply"]);

上面的代码,我们比较了函数的bind、call和apply方法的不同。最后我们看输出的值为 call apply。但是bind并没有输出,所以说bind并不能让函数立即调用。函数调用bind方法之后,函数依然是一个函数。

sayHello.bind(this,"bind")();这个代码会输出“bind”

apply方法和call方法还可以在函数内部进行调用,并能改变this的指向。

function Super(){
                    this.a="10";
                }
                function Sub(){
                    Super.call(this);
                    this.b="20";
                }
                var sub = new Sub();
                console.log(sub.a);
                console.log(sub.b);

上面的代码有点面向对象继承的意思。通过在sub内部调用super的call方法,让sub也拥有了super的属性。最后的输出结果是 10 20。

函数还拥有一些属性可以使用。如果让我们写一个阶乘函数,大多数人都会这样写:

function factorial(n){
                    if(n<1){
                        return 1;
                    }
                    else{
                        return n*factorial(n-1);
                    }
                }

阶乘算法会用到函数的递归,上面的方法将函数名在函数内部再次调用,增加了函数的耦合。我们可以使用函数的属性callee来解耦。callee是函数的属性,它是一个指针,指向拥有这个函数名的函数。

上面的代码我们可以使用arguments.callee替换函数。

function factorial(n){
                    if(n<1){
                        return 1;
                    }
                    else{
                        return n*arguments.callee(n-1);
                    }
                }
                console.log(factorial(10));//3628800

 闭包可以减少全局变量的使用。

(function() {
                
                    window.oEvent=window.oEvent||{};
                    var addEvent = function() { /*代码的实现省略了*/ };

                    function removeEvent() {}

                    oEvent.addEvent = addEvent;
                    oEvent.removeEvent = removeEvent;
                })(window);
                console.log(oEvent.addEvent());

上面的代码只定义了一个全局变量

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript函数

    JavaScript中通过function来声明函数,后面是函数名、参数、函数体。 function sum(a,b){ return a+b; } var r...

    水击三千
  • 浅谈JavaScript的面向对象程序设计(四)

      本文继续讲解JavaScript的面向对象程序设计。继承是面向对象语言中的一个基本概念,面向对象语言支持两种继承实现方式:接口继承和实现继承。接口继承只继承...

    水击三千
  • JavaScript变量作用域

    执行环境是JavaScript中比较重要的概念。执行环境定义了变量或者函数有权访问的其他数据决定了他们各自的行为,每个执行环境都有一个与之关联的变量,环境中定义...

    水击三千
  • Python之装饰器

    从上面的例子可以看出,调用函数时只需要函数名后面加‘()’即可。如果不加,则返回函数内存地址。

    py3study
  • python学习笔记 函数

    在python中,函数是一等对象。编程语言理论家把“一等对象”定义为满足以下条件的程序实体:

    py3study
  • 目测新浪的一个 js 被替换了,是内鬼还是被黑?

    http://tech.sina.com.cn/it/2018-04-19/doc-ifzihnep8570976.shtml 原文链接在这

    砸漏
  • 图插值激活提高数据高效深度学习的自然精度和鲁棒精度

    原文标题:Graph Interpolating Activation Improves Both Natural and Robust Accuracies ...

    Jarvis Cocker
  • PHP高效率写法(详解原因)

    1.尽量静态化:  如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时...

    Java架构师必看
  • 关于setTimeout和setInterval的函数参数问题

    mcq
  • 大数据视角下的春运迁徙图 来看看你的城市的迁徙半径

    今年春节期间,百度做了一个可视化很高的专题【百度迁徙】,讲春运期间各地区的人口迁徙情况。动态图,图很漂亮,也很直观。前两天我在微博分享了9张主要地区的迁徙图,反...

    小莹莹

扫码关注云+社区

领取腾讯云代金券