JavaScript基础捡漏之原型与原型链
JavaScript基础捡漏之原型与原型链
前言
关于JavaScript的原型与原型链的知识点很多,本文仅是作者在阅读很多大牛的文章后,做出的自己的理解。方便与日后对基础知识的回忆和巩固。
当然如果对读者有帮助,也是笔者非常乐意看到的一件事情。
构造函数
用new关键字来调用的函数,首字母一般大写。用来初始化和创建实例对象的函数。
Code:
functin Person() {}
var person = new Person();
console.log(person); // Person {}
在上述code中Person就是一个构造函数,创建了一个实例对象person;
实例与原型
原型为所有实例对象的“基础”,它定义并实现了一个新创建对象所必须包含的成员列表,为所有实例对象所共享!
当读取实例的属性时,如果查找失败就会继续沿着与实例对象关联的原型中去查找,一直到找最顶层为止。
Code:
function Person() {
}
Person.prototype.name = '张三';
var person = new Person();
person.name = '老王';
console.log(person.name); // 老王
delete person.name;
console.log(person.name); // 张三
第一次打印name结果为老王,是因为我们给实例对象person添加了name属性。打印时他会优先查找实例成员,找到老王后直接返回打印结果
第二次打印name结果为张三,因为我们对实例对象的name进行了删除,打印时,他在实例成员中并未找到name,而后去person实例相关的原型中去找,找到张三后返回打印结果。
实例成员与原型成员
实例成员在对象创建后就存在与实例对象中。原型成员则从对象原型“继承”而来。
当访问对象的某属性时,会优先访问该对象的实例成员,如果查询未果,则会从原型成员中查找。
prototype
翻译过来就是原型的意思。每个函数都有一个prototype属性,提供给构造函数所创建的实例对象关联其原型的能力。
Code:
function Person() {}
Person.prototype.name = '张三';
var person1 = new Person();
var person2 = new Person();
Person.prototype其实就是指向了一个对象。
这个对象正是通过调用该构造函数Person()方法所创建的实例的原型。
得出对应代码就是Person.prototype就是person1和person2原型对象。
_proto_
每个对象都有一个__proto__属性,提供给该对象关联原型的能力。
它指向该对象的原型。
Code:
console.log(Person.prototype === person1.__proto__); // true
constructor
翻译过来就是构造函数,主要用于初始化和创建实例对象。每个原型都有一个constructor,指向与原型关联的构造函数
Code:
function Person() {}
console.log(Person.prototype.constructor === Person); // true
综上所述,总结图谱如下:
Code:
function Person() {};
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
// Es5提供的查询对象原型的方法
console.log(Object.getPrototypeOf(person) === Person.prototype); // true
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
console.log(Object instanceof Function); // true
console.log(Function instanceof Object); // true
console.log(Function instanceof Function); // true
Instanceof: 沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false
原型的原型
来看这样一段代码:
var obj = new Object();
obj.name = '张三';
console.log(obj.name); // 张三
console.log(obj.__proto__);
对象的创建也可以通过Object来创建,既然创建的也是对象,那么,我们看看他的__proto__属性
我们可以发现通过Object创建的实例对象的原型和前面实例对象person._proto_.__proto__访问的属性得到的是一样的结果。可以访问到原始基本Object对象的所有属性和方法。
当我们再次添加一个__proto__属性时,便会发现得到的是null。说明至此已经完成了所有原型的访问。
更新得到图谱:
前面的Person还是很好理解的。起初笔者到Object()和Function()这里还是蒙蔽了一会。不是说只有对象才有__proto__属性嘛?为什么最后的所有构造函数都有__proto__属性了?
其实JavaScript中万物皆对象。包括函数也可以理解为对象。不过这些对象都是有Function()创建的实例。
所以也可以说所有的函数都是Function的实例对象。
既然如此,那所有函数的.__proto__其实也就指向了Function.prototype
Object也就可以理解为是一个构造函数,所以就有了
Object.prototype === Function.prototype
这里可能就涉及到了JavaScript中蛋生鸡,鸡生蛋的问题了。后续在知识得到补充后,将会作出补充!
补充
_proto_
该属性并不是某实例对象的属性,可以理解为当使用__proto__时,执行了Object.getPrototypeOf()方法,只不过现在主流浏览器也都支持这种非标准的方法访问原型。
如果对本文有任何疑问可留言,很希望大家能帮我指出错误。
参考文献
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!