我们每创建一个函数都会有一个 prototype
属性,该属性是一个对象,原型对象中存在一个 constructor
属性,该属性值指向原函数
function Person() {
}
console.log(Person.prototype);
控制台输出内容:
每个通过构造函数创建的实例默认都指向了这个原型对象 prototype
function Person() {}
Person.prototype.name = 'Tom'
Person.prototype.sayName = function () {
console.log(this.name);
}
const person1 = new Person()
const person2 = new Person()
//通过构造函数创建的实例内部中,有一个属性指向原型对象
console.log(person1.__proto__ === Person.prototype); //true
console.log(person2.__proto__ === Person.prototype); //true
也可以通过ES5 新增的一个方法来验证
//Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)。MDN
console.log(Object.getPrototypeOf(person1) === Person.prototype); //true
console.log(Object.getPrototypeOf(person1) === Person.prototype); //true
prototype
所指向的那个对象,为通过构造函数创建的实例,提供共享属性和方法的功能,
示例1:
function Person() {}
Person.prototype.name = 'Tom'
Person.prototype.sayName = function () {
console.log(this.name);
}
const person1 = new Person()
const person2 = new Person()
//实例在获取一个方法或属性的时候。会先在自身寻找该属性或方法,如果自身不存在,会继续向上查找原型对象,找到后返回,如果没有找到则是 undefined
function Person() {}
const person1 = new Person()
person1.sayName() //Tom
person2.sayName() //Tom
console.log(person1.sayName === person2.sayName); //true
示例2:
function Person (){}
Person.prototype = {
name:"Tom",
sayName: function(){
log(this.name)
}
}
const person1 = new Person()
person2.sayName() //Tom
要注意的地方
代码段 A:
function Person() {}
Person.prototype = {
name: "Tom",
sayHi: function () {
console.log("Hi --- " + this.name);
}
}
const person1 = new Person()
person1.sayHi() // Hi --- Tom
这段代码中的实例对象,是在原型添加新方法和属性之后创建的,它可以访问到原型中的方法和属性
下面这段代码中的实例,也是在原型中添加新方法和属性之前创建的,但是它却访问不到原型中定义的属性和方法
代码段 B:
function Person() {}
const person1 = new Person()
Person.prototype = {
name:"Tom",
sayHi: function () {
console.log("Hi --- " + this.name);
}
}
person1.sayHi() //报错 Uncaught TypeError: person1.sayHi is not a function
原因就在于, prototype
是一个指针,指针中存放的是原型对象的地址,这里假如存放的地址为 1000H ,那么在new实例的时候,实例对象中也包含一个指针,指向 prototype
这个指针,这有点像C语言中的多级指针。在代码段 B中,new实例的时候,实例中的指针指向 prototype
指针, prototype
指针中存放的原型地址为 1000H,当代码运行到重写原型那一行,这时,原型对象的地址已经改变了 ,这里假如它改变的地址为 1001H,它里面存放了 name 属性 和 sayHi 方法。我们在之后,访问sayHi这个方法时,访问的还是之前 prototype
指针中存放的 1000H 这个地址中的原型对象。
下图来自 js 高程 6.2 --157 页