JavaScript高级编程

JavaScript是以对象为基础、函数为模型、原型为继承的基于对象的开发模式。JavaScript不是面向对象的编程语言,在ECMAScript 6规范之前,JavaScript没有类的概念,仅允许通过构造函数模拟类,通过原型实现继承。ECMAScript 6新增类和模块功能,提升了JavaScript高级编程的能力。

1、构造函数

构造函数(constructor)也称类型函数或构造器,功能类似于对象模板,一个构造函数可以生成任意多个实例,实例对象拥有相同的原型属性和行为特征。

1.1、定义构造函数

在语法和用法上,构造函数与普通函数没有任何区别。定义构造函数的方法如下:

    function  类型名称( 配置参数 ) {
        this.属性1 = 属性值1;
        this.属性2= 属性值2;this.方法1 = function(){
            //处理代码
        };//其他代码,可以包含return语句
    }

提示,建议构造函数的名称首字母大写,以便与普通函数进行区分。

注意:构造函数有两个显著特点:

  • 函数体内可以使用this,引用将要生成的实例对象。当然,普通函数内也允许使用this,指代调用函数的对象。
  • 必须使用new命令调用函数,才能够生成实例对象。如果直接调用构造函数,则不会直接生成实例对象,此时与普通函数的功能相同。

【示例】演示定义一个构造函数,包含两个属性和1个方法:

    function Point(x,y){                    //构造函数
        this.x = x;                         //私有属性
        this.y = y;                         //私有属性
        this.sum = function(){              //方法
            return this.x + this.y;
       }
    }

在上面代码中,Point是构造函数,它提供模板,用来生成实例对象。

1.2、调用构造函数

使用new命令可以调用构造函数,创建实例,并返回这个对象。

【示例】使用new命令调用构造函数,生成两个实例,然后分别读取属性,调用方法sum():

    function Point(x,y){                    //构造函数
        this.x = x;                         //私有属性
        this.y = y;                         //私有属性
        this.sum = function(){              //私有方法
            return this.x + this.y;
        }
    }
    var p1 = new Point(100,200);            //实例化对象1
    var p2 = new Point(300,400);            //实例化对象2
    console.log(p1.x);                      //100
    console.log(p2.x);                      //300
    console.log(p1.sum());                  //300
    console.log(p2.sum());                  //700

提示:构造函数可以接收参数,以便初始化实例对象。如果不需要传递参数,可以省略小括号,直接使用new命令调用,下面两行代码是等价的。

    var p1 = new Point();
    var p2 = new Point;

如果不使用new命令,直接使用小括号调用构造函数,这时构造函数就是普通函数,不会生成实例对象,this就代表调用函数的对象,在客户端指代window全局对象。

为了避免误用,最有效的方法是在函数中启用严格模式,这样在调用构造函数时,就必须使用new命令,否则将抛出异常。

    function Point(x,y){                           //构造函数
        'use strict';                              //启用严格模式
        this.x = x;                                //私有属性
        this.y = y;                                //私有属性
        this.sum = function(){                     //私有方法
            return this.x + this.y;
        }
    }

或者使用if对this进行检测,如果this不是实例对象,则强迫返回实例对象。

    function Point(x,y){                                        //构造函数
        if(!(this instanceof Point)) return new Point(x, y);    //检测this是否为实例对象
        this.x = x;                                             //私有属性
        this.y = y;                                             //私有属性
        this.sum = function(){                                  //私有方法
            return this.x + this.y;
        }
    }

1.3、构造函数的返回值

构造函数允许使用return语句。如果返回值为简单值,则将被忽略,直接返回this指代的实例对象;如果返回值为对象,则将覆盖this指代的实例,返回return语句后面的对象。

【示例】在构造函数内部定义return返回一个对象直接量,当使用new命令调用构造函数时,返回的不是this指代的实例,而是这个对象直接量,因此当读取x和y属性值时,与预期的结果是不同的:

    function Point(x,y){                       //构造函数
        this.x = x;                            //私有属性
        this.y = y;                            //私有属性
        return { x : true, y : false }
    }
    var p1 = new Point(100,200);               //实例化对象1
    console.log(p1.x);                         //true
    console.log(p1.y);                         //false

1.4、引用构造函数

在普通函数内,使用arguments.callee可以引用函数自身。如果在严格模式下,是不允许使用arguments.callee引用函数的,这时可以使用new.target访问构造函数。

【示例】在构造函数内部使用new.target指代构造函数本身,以便对用户操作进行监测,如果没有使用new命令,则强制使用new实例化:

    function Point(x,y){                                                //构造函数
        'use strict';                                                   //启用严格模式
        if(!(this instanceof new.target)) return new new.target(x, y);  //检测this是否为实例对象
        this.x = x;                                                     //私有属性
        this.y = y                                                      //私有属性
    }
    var p1 = new Point(100,200);                                        //实例化对象1
    console.log(p1.x);                                                  //100

注意:IE浏览器对其支持不是很完善,使用时要考虑兼容性。

1.5、使用this

this是由JavaScript引擎在执行函数时自动生成,存在于函数内的一个动态指针,指代当前调用对象。具体用法如下:

    this[.属性]

如果this未包含属性,则传递的是当前对象。

下面简单总结this在5种常用场景中的表现,以及应对策略:

1.普通调用

【示例1】演示函数引用和函数调用对this的影响:

    var obj = {                    //父对象
        name : "父对象obj",
        func : function(){
            return this;
        }
    }
    obj.sub_obj = {                //子对象
        name : "子对象sub_obj",
        func : obj.func            //引用父对象obj的方法func
    }
    var who = obj.sub_obj.func();
    console.log(who.name);         //返回子对象sub_obj,说明this代表sub_obj

如果把子对象sub_obj的func改为函数调用:

    obj.sub_obj = {
        name : "子对象sub_obj",
        func : obj.func()        //调用父对象obj的方法func
    }

则函数中的this所代表的是定义函数时所在的父对象obj:

    var who = obj.sub_obj.func;
    console.log(who.name);       //返回父对象obj,说明this代表父对象obj

2.实例化

【示例2】使用new命令调用函数时,this总是指代实例对象:

    var obj ={};
    obj.func = function(){
        if(this == obj) console.log("this = obj");
        else if(this == window) console.log("this = window");
        else if(this.constructor == arguments.callee) console.log("this = 实例对象");
    }
    new obj.func;                    //实例化

3.动态调用

【示例3】使用call和apply可以绑定this,使其指向参数对象:

    function func(){
        //如果this的构造函数等于当前函数,则表示this为实例对象
        if(this.constructor == arguments.callee) console.log("this = 实例对象");
        //如果this等于Window,则表示this为Window对象
        else if (this == window) console.log("this = window对象");
        //如果this为其他对象,则表示this为其他对象
        else console.log("this == 其他对象 \n this.constructor = " + this.constructor );
    }
    func();                          //this指向Window对象
    new func();                      //this指向实例对象
    func.call(1);                    //this指向数值对象

在上面示例中,直接调用函数func()时,this代表Window。当使用new命令调用函数时,将创建一个新的实例对象,this就指向这个新创建的实例对象。

使用call方法执行函数func()时,由于call方法的参数值为数字1,则JavaScript引擎会把数字1强制封装为数值对象,此时this就会指向这个数值对象。

4.事件处理

【示例4】在事件处理函数中,this总是指向触发该事件的对象:

    <input type="button" value="测试按钮" />
    <script>
    var button = document.getElementsByTagName("input")[0];
    var obj ={};
    obj.func = function(){
        if(this == obj) console.log("this = obj");
        if(this == window) console.log("this = window");
        if(this == button) console.log("this = button");
    }
    button.onclick = obj.func;
    </script>

在上面代码中,func()所包含的this不再指向对象obj,而是指向按钮button,因为func()是被传递给按钮的事件处理函数之后才被调用执行的。

如果使用DOM 2级标准注册事件处理函数,代码如下:

    if(window.attachEvent){                                //兼容IE模型
        button.attachEvent("onclick", obj.func);
    } else{                                                //兼容DOM标准模型
        button.addEventListener("click", obj.func, true);
    }

在IE浏览器中,this指向Window和button,而在DOM标准的浏览器中仅指向button。因为,在IE浏览器中,attachEvent()是Window对象的方法,调用该方法时,this会指向Window。

为了解决浏览器的兼容性问题,可以调用call或apply方法强制在对象obj身上执行方法func(),以避免不同浏览器对this的解析不同:

    if(window.attachEvent){
        button.attachEvent("onclick", function(){     //用闭包封装call方法强制执行func()
            obj.func.call(obj);
        });
    }
    else{
        button.addEventListener("click", function(){
            obj.func.call(obj);
        }, true);
    }

当再次执行时,func()中包含的this始终指向对象obj。

5.定时器

【示例5】使用定时器调用函数:

    var obj ={};
    obj.func = function(){
        if(this == obj) console.log("this = obj");
        else if(this == window) console.log("this = window");
        else if(this.constructor == arguments.callee) console.log("this = 实例对象");
        else console.log("this == 其他对象 \n this.constructor = " + this.constructor );
    }
    setTimeout(obj.func, 100);

在IE中this指向Window和Button对象,具体原因与上面讲解的attachEvent()方法相同。在符合DOM标准的浏览器中,this指向Window对象,而不是Button对象。

因为方法setTimeout()是在全局作用域中被执行的,所以this指向Window对象。解决浏览器兼容性问题,可以使用call或apply方法来实现。

    setTimeout(function(){
        obj.func.call(obj);
    }, 100);

1.6、绑定函数

绑定函数是为了纠正函数的执行上下文,把this绑定到指定对象上,避免在不同执行上下文中调用函数时,this指代的对象不断变化。

    function bind(fn, context) {                       //绑定函数
        return function() {
            return fn.apply(context, arguments);       //在指定上下文对象上动态调用函数
        };
    }

bind()函数接收一个函数和一个上下文环境,返回一个在给定环境中调用给定函数的函数,并且将返回函数的所有的参数原封不动地传递给调用函数。

注意:这里的arguments属于内部函数,而不属于bind()函数。在调用返回的函数时,会在给定的环境中执行被传入的函数,并传入所有参数。

函数绑定可以在特定的环境中为指定的参数调用另一个函数,该特征常与回调函数、事件处理函数一起使用:

    <button id="btn">测试按钮</button>
    <script>
    var handler = {                                 //事件处理对象
        message : 'handler',                        //名称
        click : function(event) {                   //事件处理函数
            console.log(this.message);              //提示当前对象的message值
        }
    };
    var btn = document.getElementById('btn');
    btn.addEventListener('click', handler.click);   //undefined
    </script>

在上面示例中,为按钮绑定单击事件处理函数,设计当单击按钮时,将显示handler对象的message属性值。但是,实际测试发现,this最后指向了DOM按钮,而非handler。

解决方法:使用闭包进行修正:

    var handler = {                             //事件处理对象
        message : 'handler',                    //名称
        click : function(event) {               //事件处理函数
            console.log(this.message);          //提示当前对象的message值
        }
    };
    var btn = document.getElementById('btn');
    btn.addEventListener('click', function(){   //使用闭包进行修正:封装事件处理函数的调用
        handler.click();
    });                                         //'handler'

改进方法:使用闭包比较麻烦,如果创建多个闭包可能会令代码变得难于理解和调试,因此使用bind()绑定函数就很方便:

    var handler = {                                               //事件处理对象
        message : 'handler',                                      //名称
        click : function(event) {                                 //事件处理函数
            console.log(this.message);                            //提示当前对象的message值
        }
    };
    var btn = document.getElementById('btn');
    btn.addEventListener('click', bind(handler.click, handler));  //'handler'

1.7、使用bind

ECMAScript 5为Function新增bind原型方法,用来把函数绑定到指定对象上。在绑定函数中,this对象被解析为传入的对象。具体用法如下:

    function.bind(thisArg[,arg1[,arg2[,argN]]])

参数说明:

  • function:必需参数,一个函数对象。
  • thisArg:必需参数,this可在新函数中引用的对象。
  • arg1[,arg2[,argN]]]:可选参数,要传递到新函数的参数列表。

bind方法将返回与function函数相同的新函数,thisArg对象和初始参数除外:

【示例1】定义原始函数check,用来检测传入的参数值是否在一个指定范围内,范围下限和上限根据当前实例对象的min和max属性决定。然后使用bind方法把check函数绑定到对象range身上。如果再次调用这个绑定后的函数check1,就可以根据该对象的属性min和max确定调用函数时传入值是否在指定的范围内:

    var check = function (value) {
        if (typeof value !== 'number')   return false;
        else  return value >= this.min && value <= this.max;
    }
    var range = { min : 10,  max : 20 };
    var check1 = check.bind(range);
    var result = check1 (12);
    console.log(result);                                  //true

【示例2】在上面示例基础上,为obj对象定义两个上下限属性,以及一个方法check。然后,直接调用obj对象的check方法,检测10是否在指定范围,则返回值为false,因为当前min和max值分别为50和100。接着,把obj.check方法绑定到range对象,则再次传入值10,则返回值为true,说明在指定范围,因为此时min和max值分别为10和20:

    var obj = {
        min: 50,
        max: 100,
        check: function (value) {
            if (typeof value !== 'number')
                return false;
            else
                return value >= this.min && value <= this.max;
        }
    }
    var result = obj.check(10);
    console.log(result);                                  //false
    var range = { min: 10, max: 20 };
    var check1 = obj.check.bind(range);
    var result = check1(10);
    console.log(result);                                 //true

【示例3】演示利用bind方法为函数两次传递参数值,以便实现连续参数求值计算:

    var func = function (val1, val2, val3, val4) {
        console.log(val1 + " " + val2 + " " + val3 + " " + val4);
    }
    var obj = {};
    var func1 = func.bind(obj, 12, "a");
    func1("b", "c");                                //12 a b c

2、原型

在JavaScript中,所有函数都有原型,函数实例化后,实例对象可以访问原型属性,实现继承机制。

2.1、定义原型

原型实际上就是一个普通对象,继承于Object类,由JavaScript自动创建并依附于每个函数身上。使用点语法,可以通过function.prototype访问和操作原型对象。

【示例】为函数P定义原型:

    function P(x){                     //构造函数
        this.x = x;                    //声明私有属性,并初始化为参数x
    }
    P.prototype.x = 1                  //添加原型属性x,赋值为1
    var p1 = new P(10);                //实例化对象,并设置参数为10
    P.prototype.x = p1.x               //设置原型属性值为私有属性值
    console.log(P.prototype.x);        //返回10

2.2、访问原型

访问原型对象有3种方法,简单说明如下:

  • obj.proto
  • obj.constructor.prototype。
  • Object.getPrototypeOf(obj)。

其中,obj表示一个实例对象,constructor表示构造函数。proto(前后各一条下画线)是一个私有属性,可读可写,与prototype属性相同,都可以访问原型对象。Object.getPrototypeOf(obj)是一个静态函数,参数为实例对象,返回值是参数对象的原型对象。

注意:__proto__属性是一个私有属性,存在浏览器兼容性问题,以及缺乏非浏览器环境的支持。使用obj.constructor.prototype也存在一定风险,如果obj对象的constructor属性值被覆盖,则obj.constructor.prototype将会失效。因此,比较安全的用法是使用Object.getPrototypeOf(obj)。

【示例】创建一个空的构造函数,然后实例化,分别使用上述3种方法访问实例对象的原型:

    var F = function(){};                       //构造函数
    var obj = new F();                          //实例化
    var proto1 = Object.getPrototypeOf( obj );  //引用原型
    var proto2 =  obj.__proto__;                //引用原型,注意,IE暂不支持
    var proto3 = obj.constructor.prototype;     //引用原型
    var proto4 = F.prototype;                   //引用原型
    console.log( proto1 === proto2 );           //true
    console.log( proto1 === proto3 );           //true
    console.log( proto1 === proto4 );           //true
    console.log( proto2 === proto3 );           //true
    console.log( proto2 === proto4 );           //true
    console.log( proto3 === proto4 );           //true

2.3、设置原型

设置原型对象有3种方法,简单说明如下:

  • obj.proto = prototypeObj。
  • Object.setPrototypeOf(obj,prototypeObj)。
  • Object.create(prototypeObj)。

其中,obj表示一个实例对象,prototypeObj表示原型对象。注意,IE不支持前面两种方法。

【示例】简单演示原型对象的3种方法,为对象直接量设置原型:

    var proto = { name:"prototype"};        //原型对象
    var obj1 = {};                          //普通对象直接量
    obj1.__proto__ = proto;                 //设置原型
    console.log( obj1.name);
    var obj2 = {};                          //普通对象直接量
    Object.setPrototypeOf(obj2, proto);     //设置原型
    console.log( obj2.name);
    var obj3 = Object.create(proto);        //创建对象,并设置原型
    console.log( obj3.name);

2.4、检测原型

使用isPrototypeOf方法可以判断该对象是否为参数对象的原型。isPrototypeOf是一个原型方法,可以在每个实例对象上调用。

【示例】简单演示检测原型对象:

    var F = function(){};                           //构造函数
    var obj = new F();                              //实例化
    var proto1 = Object.getPrototypeOf( obj );      //引用原型
    console.log( proto1.isPrototypeOf(obj) );       //true

提示:可以使用下面代码检测不同类型的实例:

    var proto = Object.prototype;
    console.log( proto.isPrototypeOf({}) );             //true
    console.log( proto.isPrototypeOf([]) );             //true
    console.log( proto.isPrototypeOf(/ /) );            //true
    console.log( proto.isPrototypeOf(function(){}) );   //true
    console.log( proto.isPrototypeOf(null) );           //false

2.5、原型属性

原型属性可以被所有实例访问,而私有属性只能被当前实例访问。

【示例】定义一个构造函数,并为实例对象定义私有属性:

    function f(){                //声明一个构造类型
        this.a = 1;              //为构造类型声明一个私有属性
        this.b = function(){     //为构造类型声明一个私有方法
            return this.a;
        };
    }
    var e =new f();              //实例化构造类型
    console.log(e.a);            //调用实例对象的属性a,返回1
    console.log(e.b());          //调用实例对象的方法b,提示1

构造函数f中定义了两个私有属性,分别是属性a和方法b()。当构造函数实例化后,实例对象继承了构造函数的私有属性,此时可以在本地修改实例对象的属性a和方法b():

    e.a = 2;
    console.log(e.a);
    console.log(e.b());

如果给构造函数定义了与原型属性同名的私有属性,则私有属性会覆盖原型属性值。

如果使用delete运算符删除私有属性,则原型属性会被访问。在上面示例基础上删除私有属性,则会发现可以访问原型属性。

2.6、原型链

在JavaScript中,实例对象在读取属性时,总是先检查私有属性,如果存在,则返回私有属性值,否则就会检索prototype原型。如果找到同名属性,则返回protoype原型的属性值。

protoype原型允许引用其他对象。如果在protoype原型中没有找到指定的属性,则JavaScript将会根据引用关系,继续检索protoype原型对象的protoype原型,以此类推。

【示例】演示对象属性查找原型的基本方法和规律:

    function a(x){              //构造函数a
        this.x = x;
    }
    a.prototype.x = 0;          //原型属性x的值为0
    function b(x){              //构造函数b
        this.x = x;
    }
    b.prototype = new a(1);     //原型对象为构造函数a的实例
    function c(x){              //构造函数c
        this.x = x;
    }
    c.prototype = new b(2);     //原型对象为构造函数b的实例
    var d = new c(3);           //实例化构造函数c
    console.log(d.x);           //调用实例对象d的属性x,返回值为3
    delete d.x;                 //删除实例对象的私有属性x
    console.log(d.x);           //调用实例对象d的属性x,返回值为2
    delete c.prototype.x;       //删除c类的原型属性x
    console.log(d.x);           //调用实例对象d的属性x,返回值为1
    delete b.prototype.x;       //删除b类的原型属性x
    console.log(d.x);           //调用实例对象d的属性x,返回值为0
    delete a.prototype.x;       //删除a类的原型属性x
    console.log(d.x);           //调用实例对象d的属性x,返回值为undefined

原型链能够帮助用户更清楚地认识JavaScript面向对象的继承关系,如下图所示:
在这里插入图片描述

3、类

3.1、定义类

在ECMAScript 5版本中,JavaScript是没有类这个概念的,其行为最接近的是创建一个构造函数,并在构造函数的原型上添加方法,这种方法也被称为自定义类型。

ECMAScript 6引入了Class(类)的概念,作为对象的模板,通过class关键字,可以定义类。class关键字必须小写,后面跟类名

【示例】演示定义Person类,并为其添加一个属性和一个方法:

    class Person{                    //等效于Person()构造函数
        constructor(name) {          //类的构造函数,constuctor关键字小写
            this.name = name;        //设置属性
        }
        sayName() {                  //设置方法,等效于 Person.prototype.sayName
            console.log(this.name);
        }
    }

constructor()是类的默认方法,通过new命令生成实例时,会自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,默认会添加一个空的constructor()方法。constructor()方法默认会返回实例对象(this),也可以返回另一个指定对象。

ECMAScript 6为new命令引入了一个new.target属性,返回new命令作用于构造函数。如果构造函数不是通过new命令调用的,new.target将返回undefined。因此,在Class内部可以通过调用new.target访问当前Class。当子类继承父类时,new.target会返回子类。

提示:ECMAScript 6中的class类只是对ECMAScript 5中的构造函数做了一次封装,其语法格式与Java编程语言的类相似。

实例化类的方法与构造函数的实例化方法相同,都是使用new关键字。例如:

    let person = new Person("小张");
    person.sayName();                //输出“小张”

注意:关于类的定义和实例化,需要注意以下几点:

  • 类声明和函数定义不同,类的声明是不会被提升的。类声明的行为与let比较相似。
  • 类的所有方法都是不可枚举的,这与自定义类型相比是不同的,因为后者需要使用Object.defineProperty()才能定义不可枚举的方法。
  • 所有方法都不能使用new调用。
  • 不能使用new调用类的构造函数,必须使用类的实例化方式调用构造函数。
  • 不允许在类的方法内部重写类名,因为在类的内部,类名是作为一个常量存在的。

3.2、继承

在Class中通过extends关键字可以实现继承,子类会继承父类的属性和方法。

【示例】定义两个类Father、Son,通过extends关键字让Son继承Father:

    class Father{                          //父类
        constructor(name){                 //构造函数
            this.name = name;
        }
        sayName(){                         //本地方法
            console.log(this.name);
        }
    }
    class Son extends Father{              //子类,extents后面指定要继承的类型
        constructor(name, age){            //构造函数
            super(name);                   //相当于以前的Father.call(this, name);
            this.age = age;
        }
        sayAge(){                          //子类的私有方法
            console.log(this.age);
        }
    }
    var son1 = new Son("李四", 30);        //实例化
    son1.sayAge();                         //调用本地方法
    son1.sayName();                        //调用继承的方法
    console.log(son1 instanceof Son);      //返回true
    console.log(son1 instanceof Father);   //返回true

super()作为函数时,指向父类的构造函数。super作为对象时,指向父类的原型对象。

super代表父类的构造函数,但是返回的是子类的实例,即super内部的this指的是子类,因此super()相当于A.prototype.constructor.call(this)。

使用super()时要注意以下几点:

  • 只能在子类的构造函数中使用super(),否则将抛出异常。
  • 必须在构造函数的起始位置调用super(),因为它会初始化this,任何在super()之前访问this的行为都会造成错误,即super()必须放在构造函数的首行。因为子类实例的构建,是基于对父类实例的加工,只有super()方法才能返回父类实例。
  • 在类的构造函数中,唯一能避免调用super()的办法是返回一个对象。

提示:ECMAScript 5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ECMAScript 6的继承机制完全不同,实质是先创造父类的实例对象this,所以必须先调用super()方法,然后再用子类的构造函数修改this。如果子类没有定义constructor()方法,这个方法会被默认添加。

3.3、静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类调用,也被称为静态方法。父类的静态方法,可以被子类继承。

【示例】为类定义静态方法:

    class Father{                         //父类
      static foo(){                       //定义静态方法
          console.log("我是父类的静态方法");
      }
    }
    class Son extends Father{             //子类,继承自Father
    }
                                          //子类继承了父类的静态方法

在子类身上调用父类的静态方法与直接通过父类名调用是一样的。

4、模块

JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。当开发大型的、复杂的项目时,会非常麻烦。

在ECMAScript 6之前,主要使用CommonJS和AMD模块加载方案,前者用于服务器,后者用于浏览器。ECMAScript 6实现了模块功能,主要由两个命令构成,简单说明如下:

  • export命令:显式指定输出的代码,用于用户自定义模块,规定对外接口。
  • import命令:用于输入其他模块提供的功能,同时创造命名空间(namespace),防止函数名冲突。

【示例】演示如何使用JavaScript模块功能:

1.foo.js

    export let counter = 3;              //指定输出变量
    export function inc(){               //指定输出函数
        counter++;
    }

2.main.js

    import {counter, inc} from 'foo';        //从foo.js文件中导入变量counter和函数inc
    console.log(counter);                    //输出3
    inc();                                   //调用外部函数
    console.log(counter);                    //输出4
  • 使用export命令导出对象时,这个关键字可以无限次使用。
  • 使用import命令将其他模块导入指定模块时,可用来导入任意数量的模块。
  • 支持模块的异步加载,同时为加载模块提供编程支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值