# JavaScript 之构造函数、原型和原型链
# 举个栗子
我们先使用构造函数创建一个对象:
function Person() {
this.name = 'zhoukingzz';
}
var person = new Person();
console.log(person.name); // zhoukingzz
Person.prototype.name = 'apple';
console.log(person.name); // zhoukingzz
Person.prototype.sayName = function () {
console.log(this.name);
};
person.sayName(); // zhoukingzz
- 在这个例子中,Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person。
- 当 new 两个实例出来,这个实例会获得构造函数所有的属性和方法,new 完后再往构造函数的 prototype 上挂一个新的方法,那么,这两个 new 出来的实例都会拥有这个新的方法;但如果添加的是属性,那么并不会改变实例本身的属性值
# 实例
- 用 new 生成的对象称为实例
- 实例的原型链
_proto_
,指向原型对象 - 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。
# new 调用构造函数的完整步骤
- 创建一个 Object 对象
- 将 Object 对象的原型链
_proto_
指向构造函数的原型 prototype - 将构造函数的 this 指向 Object 对象
- 执行构造函数中的代码
- 返回 Object 对象
# 原型和原型链
- 每一个 JavaScript 对象(除了 null )都具有的一个属性,叫
_proto_
,这个属性会指向该对象的原型 - 所有函数的原型对象的
_proto_
,会指向 Object.prototype - 原型链的尽头是 Object.prototype.proto,为 null。
# 总结
- 在 js 中函数也是一个对象,每个函数(除箭头函数外,下文默认)都有一个
prototype
属性,且 prototype 是函数才会有的属性,这个属性是一个指针,指向一个对象(原型对象),而这个对象的用途是可以由特定类型的所有实例共享的属性和方法。(一句话:构造函数都有自己的原型对象) - 可以说
prototype
就是通过调用构造函数而创建的那个对象实例的原型对象。默认情况下,所有原型对象会自动获得一个 constructor 属性,这个属性指向 prototype 属性所在的指针(原型对象下面有个属性 constructor,该属性指向构造函数) - 实例和他的原型对象之间有条链接,这条链接就是原型链
_proto_
(可以从原型链上继承方法) - 原型对象还会指向自己的原型对象,一直到 Object 为止
- 在构造函数中的 this 指向实例化的对象
# 构造函数和普通函数区别
- 唯一区别:调用方法不同
- 任何函数,只要通过 new 来调用,就可以作为构造函数
- 不通过 new 来调用,就跟普通函数无区别
- 约定构造函数首字母大写
# 构造函数的缺点
- 通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。