在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。

1.创建一个函数对象

  1. function doSomething(){}
  2. console.log( doSomething.prototype );

截屏2021-08-22 下午4.34.22.png

2.给函数对象的原型加上一个属性

  1. function doSomething(){}
  2. doSomething.prototype.foo = "bar";
  3. console.log( doSomething.prototype );

截屏2021-08-22 下午4.34.55.png

3.通过new操作符来创建基于这个原型对象的doSomething实例

new 实际上只会 使用doSomething的prototype 创建实例,而dosomething的自有属性一个都不会拿到

  1. function doSomething(){}
  2. doSomething.prototype.foo = "bar";
  3. var doSomeInstancing = new doSomething();
  4. doSomeInstancing.prop = "some value"; // add a property onto the object
  5. console.log( doSomeInstancing );

result:
从结果中我们可以看到实际上some value 并不在doSomeInstancing的prototype中
截屏2021-08-22 下午4.43.50.png

4. 直接在创建的实例中 操作prototype —> 添加property会失败

截屏2021-08-22 下午4.48.13.png

5. 我们为函数原型doSomething继续添加property,在实例doSomeInstacing中也可以获得

得出结论:实例中对prototype的使用是通过引用

  1. function doSomething(){}
  2. doSomething.prototype.foo = "bar";
  3. var doSomeInstancing = new doSomething();
  4. doSomeInstancing.prop = "some value"; // add a property onto the object
  5. // 对原型进行修改
  6. doSomething.prototype.afterJoin = function(){
  7. console.log("之后添加的")
  8. }
  9. console.log(doSomeInstancong)

截屏2021-08-22 下午4.52.00.png

6.在doSomething上直接添加一个属性

结论:只有原型链上的东西可被修改后被实例拿到

  1. doSomething.normalMethod = function normalMethod(){
  2. console.log("普通操作");
  3. }

截屏2021-08-22 下午5.11.10.png
在实例中拿不到这个添加的属性:
截屏2021-08-22 下午5.15.52.png

7. new 实际上只会 使用doSomething的prototype 创建实例,而doSomething的自有属性一个都不会拿到

  1. function doSomething(){}
  2. doSomething.prototype.foo = "bar";
  3. // 对原型进行修改
  4. doSomething.prototype.afterJoin = function(){
  5. console.log("之后添加的")
  6. }
  7. console.log(doSomeInstancong)
  8. doSomeInstancong_2 = new doSomething();
  9. doSomeInstancong_2.name = '我是第二个实例,但是我拥有不了doSomething的自由属性,当然doSomething的prototype的我还是拥有的'
  10. console.log(doSomeInstancong_2);
  11. console.log(doSomething.prototype)

截屏2021-08-22 下午5.56.13.png

8.使用不同的方法来创建对象和生成原型链

8.1 使用语法结构创建的对象

  1. var o = {a: 1};
  2. // o 这个对象继承了 Object.prototype 上面的所有属性
  3. // o 自身没有名为 hasOwnProperty 的属性
  4. // hasOwnProperty Object.prototype 的属性
  5. // 因此 o 继承了 Object.prototype hasOwnProperty
  6. // Object.prototype 的原型为 null
  7. // 原型链如下:
  8. // o ---> Object.prototype ---> null
  9. var a = ["yo", "whadup", "?"];
  10. // 数组都继承于 Array.prototype
  11. // (Array.prototype 中包含 indexOf, forEach 等方法)
  12. // 原型链如下:
  13. // a ---> Array.prototype ---> Object.prototype ---> null
  14. function f(){
  15. return 2;
  16. }
  17. // 函数都继承于 Function.prototype
  18. // (Function.prototype 中包含 call, bind等方法)
  19. // 原型链如下:
  20. // f ---> Function.prototype ---> Object.prototype ---> null

8.2 使用构造器创建的对象

function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v){
    this.vertices.push(v);
  }
};

var g = new Graph();
// g 是生成的对象,他的自身属性有 'vertices' 和 'edges'。
// 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype。

8.3 使用Object.create创建的对象

ECMAScript 5 中引入了一个新方法:Object.create()。可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数:

var a = {a: 1};
// a ---> Object.prototype ---> null

var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)

var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null

var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype