Skip to main content

构造函数

Q:是什么?

  • A:专门用来生成实例对象的函数。
    • JavaScript 语言使用构造函数(constructor)作为对象的模板。

Q:特点是什么?

  • A:
    • 函数体内部使用了this关键字,代表了所要生成的对象实例。
    • 生成对象的时候,必须使用new命令。
    • 构造函数名一般为大写字母开头

Q:构造函数如何实现继承?

  • A:

    • 方法一:构造函数绑定

      • 使用call或apply方法,将父对象的构造函数绑定在子对象上

        function Animal(){
        this.species = "动物";
        }
        function Cat(name,color){
        //继承Animal
        Animal.apply(this, arguments);
        this.name = name;
        this.color = color;
        }

        var cat1 = new Cat("大毛","黄色");
        alert(cat1.species); // 动物
    • 方法二: prototype模式(常见)

      • 若子类的prototype对象,指向一个父类的实例,那么所有子类的实例,就能继承父类了。

        //将子类的prototype对象,指向一个父类的实例
        //它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。
        Cat.prototype = new Animal();

        //任何一个prototype对象都有一个constructor属性,指向它的构造函数。
        //若没有这行,Cat.prototype.constructor指向Animal。
        Cat.prototype.constructor = Cat;

        var cat1 = new Cat("大毛","黄色");

        alert(cat1.species); // 动物

        注意:

        • 如果替换了prototype对象,必需为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

          o.prototype = {};
          o.prototype.constructor = o;
    • 方法三:直接继承prototype

      1. 先将子类prototype指向父类prototype
      2. 再改变子类构造函数
      3. 最后创建子类实例
      function Animal(){ }

      Animal.prototype.species = "动物";

      Cat.prototype = Animal.prototype;
      Cat.prototype.constructor = Cat;
      var cat1 = new Cat("大毛","黄色");

      alert(cat1.species); // 动物
      • 优点:效率比较高(不用执行和建立父类的实例),比较省内存
      • 缺点:子类prototype和父类prototype都指向同一个对象(即:子类可以对父类的prototype进行修改)
    • 方法四: 利用空对象作为中介

      function extend(Child, Parent) {
      //F是空对象,所以几乎不占内存。
      var F = function(){};
      F.prototype = Parent.prototype;
      Child.prototype = new F();
      Child.prototype.constructor = Child;

      //意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。
      //等于在子对象上打开一条通道,可以直接调用父对象的方法。
      //为了实现继承的完备性,纯属备用性质。
      Child.uber = Parent.prototype;
      }

      extend(Cat,Animal);
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物
    • 方法五:拷贝继承

      • 把父对象的所有属性和方法,拷贝进子对象
      //将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。 
      function extend2(Child, Parent) {
      var p = Parent.prototype;
      var c = Child.prototype;
      for (var i in p) {
      c[i] = p[i];
      }
      c.uber = p;
      }

      extend2(Cat, Animal);
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物

Q:如何给构造函数添加属性?

  • A:将属性添加至构造函数原型上。

    //✅
    Person.prototype.getFullName = function () {
    return `${this.firstName} ${this.lastName}`;
    }
    //❌
    Person.getFullName = function () {
    return `${this.firstName} ${this.lastName}`;
    }

Q:如何使用super实现继承

  • A:

    class Dog {
    constructor(name) {
    this.name = name;
    }
    };

    class Labrador extends Dog {
    constructor(name, size) {
    super(name);
    this.size = size;
    }
    }
    • super相当于调用父类的构造函数,所传的参数,在父类构造函数中可以接受到。

new命令

Q:new使用时发生了什么?

  • A:执行构造函数,返回一个实例对象。相当于使用一个立即函数。每当用 new 调用函数时,JavaScript 解释器都会在底层创建一个全新的对象并把这个对象当做 this

    1. 首先创建一个空对象,然后赋值给this。
    2. 执行函数,通常修改this对象,增加一些新的属性。
    3. this被返回。
    function person(name) {
    this.name = name;
    }
    var foo = new person("deen");
    //通过new创建了一个对象
    //new是一种语法糖,new person等价于
    var bar = (function(name) {
    var _newObj = {
    constructor : person,
    __proto__ : person.prototype,
    };
    _newObj.constructor(name); // _newObj.constructor.call(_newObj, name)
    return _newObj;
    })();

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

  • A:构造函数就变成了普通函数,并不会生成实例对象。this这时代表全局对象。

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

    var v = Vehicle();

    v // undefined
    //price属性变成了全局变
    price // 1000

Q:构造函数内部有return语句会发生什么?

  • A:

    • 若return对象,则返回return指定的对象

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

      (new Vehicle()).price
      // 2000

      注意:

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

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

      (new Vehicle()) === 1000
      // false

Q:构造函数内部如何知道是否使用new指令?

  • A:可以使用new.target属性。

    • 如果当前函数是new命令调用,new.target指向当前函数
    • 否则为undefined
    function f() {
    console.log(new.target === f);
    }

    f() // false
    new f() // true

对象

Q:是什么?

  • A:每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。
    • 对象是单个实物的抽象。
    • 对象是一个容器,封装了属性(property)和方法(method)。

Q:有什么特征?

  • A:

    • 可以复用,通过继承机制还可以定制。

    • 如果你有两个名称相同的键,则键会被替换掉。它仍然位于第一个键出现的位置,但是值是最后出现那个键的值。

      const obj = { 
      a: 'one',
      b: 'two',
      a: 'three'
      }
      console.log(obj)
      //{a:'three',b:'two'}

Q:如何访问对象中的属性?

  • A:

    //方法一
    const value=obj.key;
    //方法二
    const value=obj['key'];

Q:所有对象的键所属类型是啥?

  • 所有对象的键(不包括 Symbol)在底层都是字符串。

    const obj = { 1: 'a', 2: 'b', 3: 'c' }
    obj.hasOwnProperty('1')//true
    obj.hasOwnProperty(1)//false

Q:如何判断一个对象是否拥有某一个属性/方法?

  • A:通过in来判断,无论是该属性/方法存在于实例对象还是原型对象。

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

    Person.prototype.getName = function() {
    return this.name;
    }

    var p1 = new Person('tim', 10);
    console.log('name' in p1); // true

Q:当调用一个对象不存在的函数时,会抛出什么类型的错误?

  • A:TypeError

Q:如何给对象添加一个新属性?

  • A:

    • 方法一:defineProperty方法。

      Object.defineProperty(targetObj, key, options);
      • targetObj:修改的目标对象(object)

      • key:键名(string)

      • options

        键名描述
        value键值
        writable可写性
        enumerable可枚举性(默认为false)
        configurable
    • 方法二:obj[key]

实例

Q:是什么?

  • A:通过构造函数创建出来的对象。

instanceof

Q:能干啥?

  • A:可以判断实例对象的__proto__属性是否与构造函数的prototype属性指向同一地址,是的话返回true,否则fasle。

静态方法

Q:特点是啥?

  • 只能被创建它们的构造器使用,并且不能传递给实例。(即:不能被实例使用)

    • 若被使用则抛出 TypeError 错误。
    class Chameleon {
    static colorChange(newColor) {
    this.newColor = newColor
    return this.newColor
    }

    constructor({ newColor = 'green' } = {}) {
    this.newColor = newColor
    }
    }

    const freddie = new Chameleon({ newColor: 'purple' })
    freddie.colorChange('orange')