使用构造函数创建对象

  1. function Person(){
  2. }
  3. Person.prototype.name = 'hello';
  4. Person.prototype.age = 29;
  5. Person.prototype.job = 'font-end';
  6. Person.prototype.sayName = function() {
  7. console.log(this.name);
  8. };
  9. var person1 = new Person();
  10. person1.sayName(); // hello
  11. var person2 = new Person();
  12. person1.sayName(); // hello
  13. console.log(person1.sayName == person2.sayName); // true

在上面的代码中,我们没有在构造函数中添加任何属性,将所有需要的方法和属性直接添加到了构造函数Person的prototype属性中。

构造函数Person变成了空函数。

并且我们还使用new创建了2个实例对象person1和person2.

当我们通过调用构造函数来创建新对象时,新对象具有相同的属性和方法。

prototype

每个函数都有一个prototype(原型)属性,也是只有函数才有的属性。这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
函数的prototype属性就是通过调用构造函数而创建的那个对象实例的原型对象,也就是一开始代码中的person1和person2对象。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
构造函数和实例原型之间的关系:

Person.prototype.png

如果需要表示实例(person1或者person2)与Person.prototype之间的关系,那么我们还需要接着了解proto属性。

proto

除了null,每一个javascript对象都具有proto属性高,这个属性会指向该对象的原型。
在上面的代码中:

  1. console.log(person1.__proto__ === Person.prototype); // true
  2. console.log(person2.__proto__ === Person.prototype); // true

于是我们可以得到下图:

__proto__.png

constructor

中文翻译:constructor ——> 建造者

每一个原型都有此属性,指向相关联的构造函数。
在上面的代码中:

  1. console.log(Person.prototype.constructor === Person); // true

于是我们可以得到下图:

constructor.png

此外,我们还可以直接使用以下方法获取对象的原型:

  1. Object.getPrototypeOf()

在上面的代码中:

  1. console.log(Object.getPrototypeOf(person1));
  2. // Person { name: 'hello', age: 29, job: 'font-end', sayName: [Function] }
  3. console.log(Object.getPrototypeOf(person1) === Person.prototype);
  4. // true

实例与原型

当我们需要读取实例的属性时,如果在与当前对象中没有找到,就会在与对象相关联的原型中进行查找,如果还查找不到,就会去原型的原型中进行查找,一直查找到最顶层。

接着上面的代码:

  1. person1.name = 'world';
  2. console.log(person1.name); // world
  3. delete person1.name;
  4. console.log(person1.name); // hello

在上面的代码中,我们先定义了person1的name属性,当第一次获取时,先从实例对象person1的属性中查找,所以打印出world。

当我们删除person1的name属性时,在读取person1.name,从person1中无法找到了,就会自动从person1的原型也就是person1proto,也就是Person.prototype中查找,此时就找到了name属性,也就是hello。

如果这时候还是没有找到,那就跳到原型的原型中查找。在这个例子中会直接返回undefined。

原型的原型

实际在上面的代码示例中:

  1. Person.prototype.__proto__ === Object.prototype // true

其实原型对象是通过Object构造函数生成的,而实例的proto指向构造函数的prototype,因此:
Object-prototype.png
因为Object.prototype 的原型为null,所以原型链图更新为:
Object.prototpe.__proto__.png