原型和原型链小结

160 阅读2分钟

原型和原型链

原型

在 JavaScript 中,函数(function)是允许拥有属性的。所有的函数会有一个特别的属性 —— prototype,这个属性就是原型,它是一个对象。

原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayName = function() {
    return this.name;
  }
}
var timbok = new Person('timbok', 18);
var lucy = new Person('lucy', 20);

console.log(timbok.sayName === lucy.sayName); // false

可以看到,对于同一个函数,我们通过 new 生成出来的实例,都会开出新的一块堆区,所以上面代码中 timbok 和 lucy的sayName不相等。

当使用prototype

Person.prototype.eat = function() {
  console.log('吃');
}
var timbok = new Person('timbok', 18);
var lucy = new Person('lucy', 20);

console.log(timbok.eat === lucy.eat); // true

原型链

在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。

Person.prototype.constructor === Person // true

Person.prototype === timbok.__proto__ // true

当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。

Person.prototype.a = 123;

var person = new Person()

console.log(person.a) // 123
console.log(person.b) // undefined

person.a:

先在person对象里找a -> 没找到会再到person.__proto__,也就是 Person.prototype内找 -> 找到了

person.b:

先在person对象里找b -> 没找到会再到person.__proto__内找 -> 查找与对象关联的原型中的属性 -> 找原型的原型,一直找到最顶层Object为止 -> 找不到就undefined

衍生扩展-new操作符

要想弄懂new,得先了解一下何为构造函数

构造函数

构造函数与其他函数的唯一区别,就在于调用它们的方式不同。不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数

用以下的例子来模仿 var person = new Person() 的过程

// 1. 需要一个创造器
function Creator() {
  this.name='creator'
  console.log("创造器");
}

// 2. 新建变量,开辟内存
var person = {};

// 3. 通过 __proto__ 指向Creator的原型
person.__proto__ = Creator.prototype

// 4. call person 使其可以扩展name
Creator.call(person) // 创造器

// 5.在原型上增加方法
Creator.prototype.action = function() {
  console.log('创造动作')
}

person.action() // 创造动作
console.log(person) // Creator {name: 1}

关于 this、apply、call、bind 可以看这篇文章。

写在最后

个人总结,如有不正确,欢迎指正!