前言
对于前端刚刚入门,原型和原型链算是一个难点而且比较绕,面试又基本肯定会问到,所以整理一版,便于自己回头总结和大家讨论。
一、构造函数
原型首先需要明白构造函数、实例原型、和实例之间的关系(不得不承认有点儿乱)
function Person() {
}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin
这是构造函数,构造函数有prototype上面的属性直接进行了赋值
创建了实例对象输出,最后输出(一般都没啥问题)
*一个构造函数可以生成多个实例
二、prototype属性
每个函数都有一个prototype属性(函数,函数,函数)
function Person() {
}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin
从上面可以看出,protype指向的是通过构造函数调用创建的实例对象,即prototype是person1和2的原型,每一个对象都会从原型中继承属性。
三、__proto__属性
每个javascript对象上都有一个__proto__属性(对象,对象,对象),该属性会指向该对象的原型。(即person1.proto === Person.prototype)
四、constructor属性
每一个原型都有一个constructor属性(原型,原型,原型),该属性指向该原型的构造函数(即Person === Person.prototype.constructor)
*需要注意的是,当person(小写)没有constructor属性时,他会在该对象的原型对象上去找,即person.constructor = Person.prototype.constructor
接下来就是面试中经常会问到或者笔试遇到的一些问题
五、实例与对象
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,直到找到最顶层为止。
function Person() {
}
Person.prototype.name = 'Kevin';
var person = new Person();
person.name = 'Daisy';
console.log(person.name) // Daisy
delete person.name;
console.log(person.name) // Kevin
第一个输出,打印的就是该对象本身属性;第二个输出,因为自己本身对象上并没有这个属性,就去找该对象的原型的属性,即Person.prototype的name属性,所以打印出来是原型的属性值。
六、原型的原型
原型对象也是对象,所以也可以用最原始的方法去创建他。
var obj = new Object();
obj.name = 'Kevin'
console.log(obj.name) // Kevin
即obj.proto === Objcet.prototype
Objcet.prototype.__proto === null 此处Objcet.prototype的原型指向null,即最初的Objcet.prototype没有原型即为最顶层了已经
七、原型链
本质上来说就是一个链表结构,即有属性(proto)值将各个节点(即原型对象,Function.prototype,Object.prototype)连接在了一起。
三个常用和容易混淆的原型链指向顶层(除对象外,都需要先指向自己的本身的原型对象,再指向Object的原型对象,适用于其他number类型,string类型等等)
obj -> Object.prototype -> null 即 obj.proto = Object.protype Object.protype.__proto === null
func -> Function.prototype -> Object.prototype -> null
arr -> Array.prototype -> Object.prototype -> null
八、补充instanceof,判定为true的条件即是在原型链上能找到对象的类型
举个例子:arr instanceof Array 输出为true 因为在arr的原型对象上能找到Array对象
arr instanceof Object 输出也为true,因为Array的原型指向Object,所以arr的原型链上也能找到Object所以为true
九、常见易错面试
上面说到,当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,直到找到最顶层为止。
const obj = {}
obj.x 直接输出肯定是undefined
但是在obj原型上挂一个属性后即Object.prototype.x === 'x'
obj.x 输出为x
最易出错的是
const func = () => {}
Object.prototypr.x === 'x'
func.x 输出为x
get到了么,最后一道常见面试题测试下吧
var foo = {},
F = function() {}
Object.prototype.a = 'value a';
Function.prototype.b = 'value b'
console.log(foo.a); console.log(foo.b); console.log(F.a); console.log(F.b)
答案:value a; undefined; value a; value b