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; // 64
ph2.rom; // 64
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 实例对原型对象的增删改查
function Test(){}
Test.prototype.name = 'prototype';
var test = new Test();
// 查 ok
test.name // 'prototype'
// 增 fail
test.num = 1;
Test.prototype.num // undefined
// 删 fail
delete test.name;
Test.prototype.name // 'prototype'
// 改 fail
test.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"};