1.原型模式:
- 每个函数都会创建一个
prototype
属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法
。实际上,这个对象就是通过构造函数创建的对象的原型。- 使用原型对象的好处是,在它上面定义的的属性和方法可以被对象实例共享。原来在构造函数中直接赋给
对象实例
的值,可以直接赋值给它们的原型
,如下所示:
function Person(){}
// 原型上创建的属性和方法,可以被对象实例共享
Person.prototype.name='maria'
Person.prototype.age=22
Person.prototype.sayName=function(){
console.log(this.name);
}
- 实例共享的属性和方法
let person=new Person()
person.sayName()//maria
let person1=new Person()
person1.sayName()//maria
- 实例的
__proto__
访问的是对象的原型
console.log(person.__proto__);
console.log(person1.__proto__);
- 不同实例的
constructor
指向是相同的
console.log(person.constructor==Person); //实例属性指向Person
console.log(person1.constructor==Person); //实例属性指向Person
在创建
Person
的实例的时候,应使用new
操作符,以这种方式会用构造函数会执行如下操作。new
的时候发生了下面内容:
- 在内存中创建一个新对象
- 这个新对象内部的特性被赋值为构造函数的
prototype
属性。- 构造函数内部的
this
被赋值为这个新对象(即this
指向新对象)- 执行
构造函数
内部的代码(给新对象添加属性)- 如果
构造函数
返回非空对象,则返回该对象,否则返回刚创建的新对象。
2.理解原型
- 只要创建一个函数,就会按照认定的规则为这个函数创建一个
prototype
属性指向原型对象。- 默认情况下,所有原型对象自动获得一个名为
constructor
的属性,指回与之关联的构造函数。也就是:
Person.prototype.constructor
指向Person
。然后因构造函数而异,可能会给原型对象添加其他属性和方法。在自定义构造函数时,原型对象默认只会获得constructor
属性,其他所有方法都继承自Object
。
- 原型行为:
2.1. 构造函数可以是函数表达式也可以是函数声明
function Person(){}
let Person=function(){}
2.2 声明之后构造函数
就有了一个与之关联的原型对象。
console.log(Person.prototype);
console.log(typeof Person.prototype);
2.3 如前所述、构造函数有一个prototype
属性,引用其原型对象,而这个原型对象也有一个constructor
属性,引用这个构造函数
。换句话说,两者循环引用。
console.log(Person.prototype.constructor==Person);//true
2.4 正常的原型链都会终止于Object
的原型对象,而Object
原型的原型是null
console.log(Person.prototype.__proto__===Object.prototype);
console.log(Person.prototype.__proto__.constructor==Object);
console.log(Person.prototype.__proto__.__proto__===null);
console.log(Person.prototype.__proto__);
2.5 构造函数
、原型对象
和实例
是3个完全不同的对象。
let person1=new Person()
let person2=new Person()
console.log(person1!==Person);
console.log(person1!==Person.prototype);
console.log(Person.prototype!==Person);
2.6 实例通过__proto__
链接到原型对象,构造函数通过prototype
属性链接到原型对象,实例与构造函数没有直接联系,与原型对象有直接联系。
console.log(person1.__proto__===Person.prototype);//true
console.log(person1.__proto__.constructor===Person);//true
2.7 同一个构造函数的两个实例
,共享同一个原型对象。
console.log(person1.__proto__==person2.__proto__);//true
2.8 instanceof
检查实例的原型链中,是否包含指定构造函数的原型。
console.log(person1 instanceof Person);
console.log(person1 instanceof Object);
console.log(Person.prototype instanceof Object);
看到这已经晕了……
- 利用这个还可以判断
是否是数组
3.原型层级
通过对象访问属性时,会按照这个属性的名称开始搜索。
- 搜索开始于对象
实例
本身。如果在这个实例上发现了给定的名称,则返回该名称对应的值。- 如果没有找到这个属性,则搜索会沿着指针进入
原型对象
,然后在原型对象上找到属性后,再返回对应的值。
- 前面提到的
constructor
属性只存在于原型对象
,因此通过实例对象也是可以访问到的。