• JavaScript随笔(二):函数只是一种对象


    上一篇随笔提到JS中有两种数据类型:原始类型和对象类型,但是我们还没有提到函数。实际上函数也是一种对象,准确地说函数应该叫做函数对象。下面我们从对象开始说起。

    1. 对象

    最简单的对象,是这样的:

    var obj = {};

    我们创建了一个空对象。说它空是因为它没有任何自定义属性,但是实际上它还是有一些默认属性的,这些属性是从它的原型对象继承来的,比如constructor、toString和valueOf等。除此之外,ECMA-262中还定义了对象的一些内置属性,这些属性对JS语言来说是不可见的,也就是说跟我们的编程无关。但是简单地了解一下这些内置属性,对我们深入理解对象的内部机制是有益的。这些属性包括:[[Prototype]]、[[Extensible]]、[[Get]]、[[Put]]、[[HasProperty]]和[[Delete]]等,具体的含义在此不提,只需要知道,只要是对象就一定有这些属性。

    2. 函数

    接下来我们说一下函数。我们经常听人说“函数是JS中的一等公民,函数可以做参数,可以做返回值”。其实原因很简单,函数也是一种对象,是一种特殊的对象。既然是对象,当然是一等公民了。它只是比普通的对象多了一些特殊的性质,所以看起来跟普通对象有所不同。那么,函数与普通对象比有哪些不同呢?

    (1) 从语言规范或者说从JS引擎的角度来看,函数除了前面提到的那些内置属性外,还多了一些内置属性,包括:

      • [[Code]]:函数的代码,即函数体里面的那些语句。
      • [[FormalParameters]]:函数的形参列表。
      • [[Scope]]:词法环境(Lexical Environment),它确定了函数执行时所处的环境。这个东西很重要,跟我们经常听说的作用域链闭包有关系。
      • [[Call]]:执行代码,即在调用此函数时执行的动作。
      • [[Construct]]:构造一个新的对象的动作。拥有这个内置属性的函数被称为构造函数,通过new操作符可以用它来产生新的对象。
      • [[HasInstance]]:用来检测一个对象是否是此函数构造的。

    为了强调函数是一种对象,我们甚至可以把函数想象成对象的形式:

    // 某个求较大值的函数的对象表示形式
    var max = {
        _callable_: true,
        _args_: ['a', 'b'],
        _code_: 'return a > b ? a : b;'
    };

    (2) 由于函数是一种特殊的以及非常重要的对象,所以JS语言专门提供了特殊的语法来创建函数,即

    // 函数声明
    function sayHello() {
        console.log('Hello');   
    }
    
    // 函数表达式
    var sayHello = function() {
        console.log('Hello');
    }

    当然,也可以用类似于创建普通对象的方式(即new+构造函数)来创建函数,即

    var sayHello = new Function("console.log('Hello');");

    是不是跟普通对象的方式很像啊:

    var data = new Date('2015/09/10');

    显然Function是一个非常特殊的构造函数,因为一般的构造函数只能创建普通对象,但是Function能创建一个函数对象。

    (3) 函数是可调用的。我们通过函数调用表达式来调用一个函数,从而完成实现某种特定的功能,例如:

    function add(x, y) {
        return x + y;
    }
    
    var z = add(3, 4);
    console.log(z); // 输出7

    这也是我们使用函数最常见的目的。

    3. 构造函数

    其实上面已经顺带把构造函数也讲了。构造函数是指可以利用 new 操作符来创建对象的函数,这个过程是通过内置属性[[Construct]]实现的。比如Object就是一个构造函数:

    var obj = new Object();

    实际上,我们在程序里使用函数声明、函数表达式或Function创建出来的函数都是即使普通函数也是构造函数。它们既可以被调用以得到返回值或产生某种效果,也可以用new操作符来创建对象。但是从本质上讲构造函数比普通函数要更特殊一些。

    另外为了进行区分,在命名时,前者通常首字母小写,后者通常首字母大写。举一个构造函数的例子:

    function Person(name, age) {
        this.name = name;
        this.age = age;    
    }

    可能有人要问了,是否存在不是构造函数的函数?当然是存在的,比如JS中的那些内置函数基本都属于这种情况。例如:

    typeof parseInt; // 结果为"function"
    parseInt('123'); // 结果为123
    new parseInt(); // 抛出TypeError异常,提示function parseInt() { [native code] } is not a constructor 

    可见parseInt可以作为一个函数来调用,但是不能作为构造函数来创建新的对象。

  • 相关阅读:
    命令用法示例
    Elastic:用Docker部署Elastic栈
    Elastic:使用Heartbeat进行Uptime监控
    Elastic:如何在一个机器上同时模拟多个node
    Elastic 使用索引生命周期管理实现热温冷架构
    Logstash:运用jdbc_streaming来丰富我们的数据
    Logstash:多个配置文件(conf)
    Logstash:处理多个input
    使用 Logstash 和 JDBC 确保 Elasticsearch 与关系型数据库保持同步
    Logstash:把MySQL数据导入到Elasticsearch中
  • 原文地址:https://www.cnblogs.com/manxisuo/p/JS-Note-2-Function-Is-Object.html
Copyright © 2020-2023  润新知