• 函数


    函数对于任何语言来说都是一个核心的概念。ECMAScript中的函数使用function关键字来声明,后跟一组参数以及函数体。

    创建函数的两种方式:1.函数声明;2.函数表达式

    1.函数声明的语法:

    1 function functionName(arg0, arg1, arg2) {
    2     //函数体
    3 }
    //Firefox、Safari、Chrome和OPera都给函数定义了一个非标准的name属性,通过这个属性可以访问到函数指定的名字
    alert(functionName.name); //"functionName"

    2.函数表达式的语法:

    1 var functionName = function(arg0, arg1, arg2) {
    2     //函数体
    3 };

    注:使用函数声明的方式创建函数,会存在函数声明提升(function declaration hoisting)的现象。意思是在执行代码之前会先读取函数声明。即可以把函数声明放在调用它的语句后面:

    1 sayHi();
    2 function sayHi() {
    3     alert("Hi !");
    4 }

    但是函数表达式不存在函数提升。

    理解函数的参数

    ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递进来多少个参数,也不在乎传进来参数的数据类型。意思是说,当你定义一个只接收两个参数的函数,在调用这个函数的时候,可以传递一个,两个、三个甚至不传递参数。

    原因是ECMAScript中函数的参数在内部是用一个数组来表示的。函数接收的始终是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

    arguments对象是一个类数组对象(并不是Array的实例),因为可以使用方括号语法访问它的每一个元素,使用length属性来确定传递进来多少个参数。

     1 function sayHi() {
     2     alert("Hello " + arguments[0] + ", " + arguments[1]);
     3 }
     4 
     5 function howManyArgs() {
     6     alert(arguments.length);
     7 }
     8 
     9 howManyArgs("string", 45);  //2
    10 howManyArgs();  //0

    arguments对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数个数决定的。没有传递值的命名参数将被自动赋予undefined值,这跟定义了变量但又没有初始化一样。

     1 function doAdd1(num1, num2) {
     2     if(arguments.length == 1) {
     3         alert(num1 + 10);
     4     } else if(arguments.length == 2) {
     5         alert(arguments[0] + num2);
     6     }
     7 }
     8 
     9 //如果只给doAdd1()函数传递了一个参数,则num2中就会保存undefined值
    10 
    11 //arguments对象可以与命名参数一起使用
    12 
    13 function doAdd2(num1, num2) {
    14     arguments[1] = 20;
    15     alert(arguments[0] + num2);
    16 }
    17 
    18 //如果doAdd()只传入了一个参数,那么为arguments[1]设置的值不会反映到命名参数中。

    注:ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数

    没有重载

    ECMAScript函数不能像传统意义上那样实现重载。而在其他语言中(如Java),可以为一个函数编写两个定义,只要这两个定义的签名(接收的参数类型和数量)不同即可。ECMAScript函数没有签名,因为其参数是由包含零或多个值的arguments对象来表示的。而没有函数签名,真正的重载是不可能做到的。

     如果在ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。

    1 function addSomeNumber(num) {
    2     return num + 100;
    3 }
    4 
    5 function addSomeNumber(num1, num2) {
    6     return num1 + 200;
    7 }
    8 
    9 var result = addSomeNumber(200);//300

    Function 类型

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

    由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说一个函数可能会有多个名字。

     1 function sum(num1, num2) {
     2     return numm1 + num2;
     3 }
     4 alert(sum(10, 10));  //20
     5 
     6 var anotherSum = sum;
     7 alert(anotherSum(10, 10));  //20
     8 
     9 sum = null;
    10 alert(anotherSum(10, 10));  //20

    函数内部属性

    在函数内部,有两个特殊的对象:argumentsthis。arguments是一个类数组对象,包含着传入函数中的所有参数。arguments对象有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数

     1 function factorial1(num) {
     2     if(num <= 1) {
     3         return 1;
     4     } else {
     5         return num * factorial(num-1);
     6     }
     7 }
     8 
     9 //使用arguments.callee重写factorial()函数
    10 function factorial2(num) {
    11     if(num <= 1) {
    12         return 1;
    13     } else {
    14     return num * arguments.callee(num-1);
    15     }
    16 }
    17 
    18 //这种写法消除了这个函数的执行与函数名factorial紧紧耦合在一起的现象。
    19 
    20 var trueFactorial = factorial2;
    21 
    22 factorial2 = function() {
    23     return 0;
    24 };
    25 
    26 alert(trueFactorial(5)); //120
    27 alert(factorial2(5));  //0

    函数内部的另一个特殊对象是this。this引用的是函数据以执行的环境对象。

    ECMAScript5中规范化了另一个函数的属性caller。这个属性中保存着调用当前函数的函数的引用。如果是在全局作用域中调用当前函数,它的值为null。

     1 function outer() {
     2     inner();
     3 }
     4 
     5 function inner() {
     6     alert(inner.caller);
     7 }
     8 
     9 outer();  //警告框中显示outer()函数的源代码。
    10 
    11 function inner() {
    12     alert(arguments.callee.caller);
    13 }

    函数属性和方法

    每个函数都包含两个属性:lengthprototype。其中,length属性表示函数希望接收的命名参数的个数

     1 function sayName(name) {
     2     alert(name);
     3 }
     4 
     5 function sayHi() {
     6     alert("hi");
     7 }
     8 
     9 function sum(num1, num2) {
    10     return num1 + num2;
    11 }
    12 
    13 alert(sayName.length);  //1;
    14 alert(sayHi.length);  //0;
    15 alert(sum.length);  //2

    对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。换句话说,诸如toString()和valueOf()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。

    每个函数包含两个非继承而来的方法:apply()cal()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

    apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array实例,也可以说是arguments对象。

    call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于call()方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。

    ECMAScript 5还定义了一个方法:bind()。这个方法创建一个函数的实例,其this值会被绑定到传给bind()方法的值。

    1 window.color = "red";
    2 var o = {color: "blue"};
    3 
    4 function sayColor() {
    5     alert(this.color);
    6 }
    7 
    8 var objectSayColor = sayColor.bind(o);
    9 objectSayColor();  //blue
  • 相关阅读:
    spring boot所有配置
    Hibernate validator的一些额外特性
    相似序列搜索
    时间序列异常检测
    基于结构的距离度量
    jupyterlab的启动404error问题
    爬虫-Chrome-问题1
    厘清重要概念的内涵与外延
    六)定时任务持久化
    公钥私钥
  • 原文地址:https://www.cnblogs.com/sparkler/p/13732381.html
Copyright © 2020-2023  润新知