1. 原型
1.1 概念引入
// 构造函数function Phone(color, brand) {this.color = color;this.brand = brand;}Phone.prototype; // { constructor: function Phone() }Phone.prototype.rom = 64;Phone.prototype.call = function () {console.log("I am calling")};var ph1 = new Phone();var ph2 = new Phone();ph1.rom; // 64ph2.rom; // 64ph1.call(); // "I am calling"
构造函数的prototype属性
- prototype 是 function的一个属性,其本身也是一个对象
- 其 constructor 属性指向原 function 本身
{ constructor: function Phone() }
构造函数prototype属性是干什么的?
- prototype属性是定义构造函数构造出的每个实例的公共祖先
- 在构造函数prototype属性上定义的属性和方法,所有构造出的实例都可以通过 属性名/方法名 直接访问
意义:
- 使用this.propName = propValue生成实例化对象时,会为每个实例创建各自的propValue
- 当该propName在各个实例中相同时,会造成数据的冗余,尤其是方法,会为每一个实例生成相同的函数对象
- 因此相同的属性和方法会挂在原型上,供所有实例使用
注意:当this和原型上存在同名属性时,会读取this中的属性
1.2 实例对原型对象的增删改查
function Test(){}Test.prototype.name = 'prototype';var test = new Test();// 查 oktest.name // 'prototype'// 增 failtest.num = 1;Test.prototype.num // undefined// 删 faildelete test.name;Test.prototype.name // 'prototype'// 改 failtest.name = "proto";Test.prototype.name // 'prototype'
- 实例对象只能读取原型上的属性,不能更改(增、删、改
1.3 原型对象设置
// 构造函数function Phone(color, brand) {this.color = color;this.brand = brand;}// 方式一:给prototype对象添加属性Phone.prototype.rom = "64G";Phone.prototype.ram = "6G";Phone.prototype.call = function() { console.log("call to somebody.")};var ph1 = new Phone();ph1.rom; // "64G"ph1.constructor;// ƒ Phone(color, brand) {// this.color = color;// this.brand = brand;//}// 方式二:将object赋值给prototype对象Phone.prototype = {rom: "64G",ram: "6G",call: function() { console.log("call to somebody.")}}var ph1 = new Phone();ph1.rom; // "64G"ph1.constructor; // ƒ Object() { [native code] }// 将object赋值给prototype对象, 并指定其constructor属性为构造函数Phone.prototype = {rom: "64G",ram: "6G",call: function() { console.log("call to somebody.")},constructor: Phone}
- prototype 对象自带constructor属性,指向构造函数本身
- 将新的对象赋值给prototype,会导致prototype失去constructor属性
- 解决方式:将object赋值给prototype的同时, 指定其constructor属性为构造函数
1.4 实例化对象的 proto | [[Prototype]] 属性
function Car() {var this = {__proto__: Car.prototype}};Car.prototype.name = "Benz";var car = new Car();car;// Car {[[Prototype]]: Object}car.__proto__;// {// name: "Benz",// constructor: ƒ Car()// }// __proto__属性可以修改:car.__proto__ = {name: "mini"};car.name; // mini
明确:原型是实例的原型,而不是构造函数的原型!
- 在声明构造函数时,由于还没有实例化对象,故而将原型作为一个属性挂靠在构造函数上
- 实例化对象时,将原型赋值给实例的proto属性
!原型是实例的原型,而不是构造函数的原型!
function Car() {};Car.prototype.name = "Benz";var car1 = new Car();car1.name; // 'Benz'Car.prototype = {name: 'Mazda'};var car2 = new Car();car1.name; // 'Benz'car2.name; // 'Mazda'
function Car() {};// 1. 修改属性(影响所有已创建的实例)Car.prototype.name = "Benz";// 2. 重新赋值(影响后续创建的实例,但不影响已创建好的实例)Car.prototype = {name: 'Mazda'};// 实例化var car1 = new Car();// 3. 给实例的__proto__ 重新赋值(只影响当前实例)car.__proto__ = {name: "mini"};
