JavaScript之 new 命令

作者: JaniceZD | 来源:发表于2019-05-21 09:36 被阅读5次

    JavaScript 面向对象编程的基础知识篇 1 。

    1. 概述

    面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。

    那么,“对象”(object)到底是什么?

    • 对象是单个实物的抽象。
    • 对象是一个容器,封装了属性(property)和方法(method)。
      属性是对象的状态,方法是对象的行为(完成某种任务)。

    2. 构造函数

    面向对象编程的第一步,就是要生成对象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。

    JavaScript 语言使用构造函数(constructor)作为对象的模板。
    “构造函数”,就是专门用来生成实例对象的函数。

    它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

    var Vehicle = function () {
      this.price = 1000;
    };
    

    上面代码中,Vehicle 就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。

    构造函数的特点有两个。

    • 函数体内部使用了 this 关键字,代表了所要生成的对象实例。
    • 生成对象的时候,必须使用 new 命令。

    3. new 命令

    3.1 基本用法

    3.1.1 new 的基本用法

    new 命令的作用,就是执行构造函数,返回一个实例对象。

    var Vehicle = function () {
      this.price = 1000;
    };
    
    var v = new Vehicle();
    v.price // 1000
    

    上面代码通过 new 命令,让构造函数 Vehicle 生成一个实例对象,保存在变量 v 中。new 命令执行时,构造函数内部的this,就代表了新生成的实例对象,this.price 表示实例对象有一个 price 属性,值是1000。

    下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号

    // 推荐的写法
    var v = new Vehicle();
    // 不推荐的写法
    var v = new Vehicle;
    
    3.1.2 保证构造函数必须与 new 命令一起使用

    如果忘了使用 new 命令,直接调用构造函数会发生什么事?

    var Vehicle = function (){
      this.price = 1000;
    };
    
    var v = Vehicle();
    v // undefined
    price // 1000
    

    上面代码中,调用 Vehicle 构造函数时,忘了加上 new 命令。结果,变量 v 变成了 undefined,而 price 属性变成了全局变量。因此,应该非常小心,避免不使用 new 命令、直接调用构造函数。

    为了保证构造函数必须与 new 命令一起使用,有2种解决办法:

    • 构造函数内部使用严格模式,即第一行加上 use strict
      这样的话,一旦忘了使用 new 命令,直接调用构造函数就会报错。
    function Fubar(foo, bar){
      'use strict';
      this._foo = foo;
      this._bar = bar;
    }
    
    Fubar()
    // TypeError: Cannot set property '_foo' of undefined
    

    上面代码的 Fubar 为构造函数,use strict 命令保证了该函数在严格模式下运行。由于严格模式中,函数内部的 this 不能指向全局对象,默认等于undefined,导致不加 new 调用会报错(JavaScript 不允许对 undefined添加属性)。

    • 构造函数内部判断是否使用 new 命令,如果发现没有使用,则直接返回一个实例对象。
    function Fubar(foo, bar) {
      if (!(this instanceof Fubar)) {
        return new Fubar(foo, bar);
      }
    
      this._foo = foo;
      this._bar = bar;
    }
    
    Fubar(1, 2)._foo // 1
    (new Fubar(1, 2))._foo // 1
    

    3.2 new 命令的原理

    使用 new 命令时,它后面的函数依次执行下面的步骤。

    1. 创建一个空对象,作为将要返回的对象实例。
    2. 将这个空对象的原型,指向构造函数的 prototype 属性。
    3. 将这个空对象赋值给函数内部的 this 关键字。
    4. 开始执行构造函数内部的代码。

    也就是说,构造函数内部,this 指的是一个新生成的空对象,所有针对 this 的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子。

    3.2.1 关于 return语句

    如果构造函数内部有 return 语句,而且 return 后面跟着一个对象,new 命令会返回return 语句指定的对象;否则,就会不管return语句,返回 this 对象。

    var Vehicle = function () {
      this.price = 1000;
      return 1000;
    };
    
    (new Vehicle()) === 1000
    // false    new命令忽略了这个 return 语句,返回“构造”后的 this 对象。
    

    如果 return语句返回的是一个跟 this 无关的新对象,new命令会返回这个新对象,而不是this对象。

    var Vehicle = function (){
      this.price = 1000;
      return { price: 2000 };
    };
    
    (new Vehicle()).price
    // 2000   new 命令返回这个对象,而不是 this 对象。
    
    3.2.2 对普通函数使用 new

    如果对普通函数(内部没有 this 关键字的函数)使用 new 命令,则会返回一个空对象

    function getMessage() {
      return 'this is a message';
    }
    
    var msg = new getMessage();
    
    msg // {}
    typeof msg // "object"
    

    这是因为 new 命令总是返回一个对象,要么是实例对象,要么是return 语句指定的对象。本例中,return 语句返回的是字符串,所以new 命令就忽略了该语句。

    参考链接

    相关文章

      网友评论

        本文标题:JavaScript之 new 命令

        本文链接:https://www.haomeiwen.com/subject/qwekzqtx.html