原型和原型链
原型
在 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 可以看这篇文章。
写在最后
个人总结,如有不正确,欢迎指正!