1. 原型

1.1 概念引入

  1. // 构造函数
  2. function Phone(color, brand) {
  3. this.color = color;
  4. this.brand = brand;
  5. }
  6. Phone.prototype; // { constructor: function Phone() }
  7. Phone.prototype.rom = 64;
  8. Phone.prototype.call = function () {
  9. console.log("I am calling")
  10. };
  11. var ph1 = new Phone();
  12. var ph2 = new Phone();
  13. ph1.rom; // 64
  14. ph2.rom; // 64
  15. ph1.call(); // "I am calling"

构造函数的prototype属性

  • prototype 是 function的一个属性,其本身也是一个对象
  • 其 constructor 属性指向原 function 本身 { constructor: function Phone() }

构造函数prototype属性是干什么的?

  • prototype属性是定义构造函数构造出的每个实例的公共祖先
  • 在构造函数prototype属性上定义的属性和方法,所有构造出的实例都可以通过 属性名/方法名 直接访问

意义:

  • 使用this.propName = propValue生成实例化对象时,会为每个实例创建各自的propValue
  • 当该propName在各个实例中相同时,会造成数据的冗余,尤其是方法,会为每一个实例生成相同的函数对象
  • 因此相同的属性和方法会挂在原型上,供所有实例使用

注意:当this和原型上存在同名属性时,会读取this中的属性

1.2 实例对原型对象的增删改查

  1. function Test(){}
  2. Test.prototype.name = 'prototype';
  3. var test = new Test();
  4. // 查 ok
  5. test.name // 'prototype'
  6. // 增 fail
  7. test.num = 1;
  8. Test.prototype.num // undefined
  9. // 删 fail
  10. delete test.name;
  11. Test.prototype.name // 'prototype'
  12. // 改 fail
  13. test.name = "proto";
  14. Test.prototype.name // 'prototype'
  • 实例对象只能读取原型上的属性,不能更改(增、删、改

1.3 原型对象设置

  1. // 构造函数
  2. function Phone(color, brand) {
  3. this.color = color;
  4. this.brand = brand;
  5. }
  6. // 方式一:给prototype对象添加属性
  7. Phone.prototype.rom = "64G";
  8. Phone.prototype.ram = "6G";
  9. Phone.prototype.call = function() { console.log("call to somebody.")};
  10. var ph1 = new Phone();
  11. ph1.rom; // "64G"
  12. ph1.constructor;
  13. // ƒ Phone(color, brand) {
  14. // this.color = color;
  15. // this.brand = brand;
  16. //}
  17. // 方式二:将object赋值给prototype对象
  18. Phone.prototype = {
  19. rom: "64G",
  20. ram: "6G",
  21. call: function() { console.log("call to somebody.")}
  22. }
  23. var ph1 = new Phone();
  24. ph1.rom; // "64G"
  25. ph1.constructor; // ƒ Object() { [native code] }
  26. // 将object赋值给prototype对象, 并指定其constructor属性为构造函数
  27. Phone.prototype = {
  28. rom: "64G",
  29. ram: "6G",
  30. call: function() { console.log("call to somebody.")},
  31. constructor: Phone
  32. }
  • prototype 对象自带constructor属性,指向构造函数本身
  • 将新的对象赋值给prototype,会导致prototype失去constructor属性
  • 解决方式:将object赋值给prototype的同时, 指定其constructor属性为构造函数

1.4 实例化对象的 proto | [[Prototype]] 属性

  1. function Car() {
  2. var this = {
  3. __proto__: Car.prototype
  4. }
  5. };
  6. Car.prototype.name = "Benz";
  7. var car = new Car();
  8. car;
  9. // Car {[[Prototype]]: Object}
  10. car.__proto__;
  11. // {
  12. // name: "Benz",
  13. // constructor: ƒ Car()
  14. // }
  15. // __proto__属性可以修改:
  16. car.__proto__ = {name: "mini"};
  17. car.name; // mini

明确:原型是实例的原型,而不是构造函数的原型!

  • 在声明构造函数时,由于还没有实例化对象,故而将原型作为一个属性挂靠在构造函数上
  • 实例化对象时,将原型赋值给实例的proto属性

!原型是实例的原型,而不是构造函数的原型!

  1. function Car() {};
  2. Car.prototype.name = "Benz";
  3. var car1 = new Car();
  4. car1.name; // 'Benz'
  5. Car.prototype = {name: 'Mazda'};
  6. var car2 = new Car();
  7. car1.name; // 'Benz'
  8. car2.name; // 'Mazda'
  1. function Car() {};
  2. // 1. 修改属性(影响所有已创建的实例)
  3. Car.prototype.name = "Benz";
  4. // 2. 重新赋值(影响后续创建的实例,但不影响已创建好的实例)
  5. Car.prototype = {name: 'Mazda'};
  6. // 实例化
  7. var car1 = new Car();
  8. // 3. 给实例的__proto__ 重新赋值(只影响当前实例)
  9. car.__proto__ = {name: "mini"};