什么是构造函数?

构造函数本身就是一个函数,与普通函数没有任何区别,不过为了规范一般将其首字母大写。构造函数和普通函数的区别在于,使用 new 生成实例的函数就是构造函数,直接调用的就是普通函数。

constructor

  1. constructor 返回创建实例对象时构造函数的引用。此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。

    1. 构造函数

      1
      2
      3
      4
      5
      6
      function Parent(age) {
      this.age = age;
      }
      var p = new Parent(50);
      p.constructor === Parent; // true
      p.constructor === Object; // false
    2. 普通函数

      1
      2
      3
      4
      5
      6
      7
      function parent1(age) {
      return {
      age: age
      }
      }
      var p = parent1(20);
      p.constructor === Object; // true
  2. 对于基本类型(String、Number、Boolean、Symbol、null、undefined)constructor只读,当然null、undefined没有构造属性;对于引用类型constructor可修改。

new Class()详解

案例

  1. 代码:
    1
    2
    3
    4
    5
    function Person(name, age){
    this.name = name;
    this.age = age;
    }
    var p = new Person('chao', 12);

new Person(‘chao’, 12)一个对象的4个过程

  1. 创建一个空对象

    1
    var obj = new Object();
  2. 让实例对象中this指向obj, 并且执行Person函数体

    1
    var result = Person.call(this);
  3. 设置原型链,将obj的proto指向实例化对象的prototype成员对象

    1
    obj.__proto__ = Person.prototype;
  4. 判断实例化返回类型

    1
    2
    3
    4
    5
    if(typeof(result) === 'object'){
    p = result;
    }else{
    p = obj;
    }

模拟实现new

1
2
3
4
5
6
7
8
9
10
function create() {
// 1、获得构造函数,同时删除 arguments 中第一个参数
Con = [].shift.call(arguments);
// 2、创建一个空的对象并链接到原型,obj 可以访问构造函数原型中的属性
var obj = Object.create(Con.prototype);
// 3、绑定 this 实现继承,obj 可以访问到构造函数中的属性
var ret = Con.apply(obj, arguments);
// 4、优先返回构造函数返回的对象
return ret instanceof Object ? ret : obj;
};

原型

prototype

__proto__

原型链

  1. 含义:每个对象拥有一个原型对象,通过 __proto__ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null。这种关系被称为原型链 (prototype chain)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Person(name, age){
    this.name = name;
    this.age = age;
    }
    var p = new Person('chao', 12);
    p //Person
    p.__proto__ === Person.prototype // true
    p.__proto__.__proto__ === Object.prototype //true
    p.__proto__.__proto__.__proto__ === null //true

总结

  1. Symbol 作为构造函数来说并不完整,因为不支持语法 new Symbol(),但其原型上拥有 constructor 属性,即 Symbol.prototype.constructor。
  2. 引用类型 constructor 属性值是可以修改的,但是对于基本类型来说是只读的,当然 null 和 undefined 没有 constructor 属性。
  3. __proto__ 是每个实例上都有的属性,prototype 是构造函数的属性,这两个并不一样,但 p.__proto__ 和 Parent.prototype 指向同一个对象。
  4. __proto__ 属性在 ES6 时被标准化,但因为性能问题并不推荐使用,推荐使用 Object.getPrototypeOf()。
  5. 每个对象拥有一个原型对象,通过 __proto__ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null,这就是原型链。

思考题

  1. js无限累计
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function add(a){
    function sum(b){
    a += b;
    return sum;
    }

    //重写toString
    sum.toString = function(){
    console.log('======');
    return a;
    }

    return sum; //返回函数
    }
    add(1)(2)(3)

我们知道打印函数时会自动调用 toString()方法,函数 add(a) 返回一个闭包 sum(b),函数 sum() 中累加计算 a = a + b,只需要重写sum.toString()方法返回变量 a 就OK了