美文网首页
JavaScript的原型与原型链

JavaScript的原型与原型链

作者: 前端一小卒 | 来源:发表于2016-11-21 15:20 被阅读87次

在基于原型的面向对象JS中,原型与原型链是重中之重,也是困扰了很多前端新手。在查阅了很多的资料后,写下这篇文章,希望能对各位前端新手有所帮助,如果文中出现错误,欢迎各位指出。

在JS中,我们创建的每个函数都拥有一个prototype属性,该属性被称为原型属性,其指向以当前函数作为构造函数而构造出来的对象的原型对象。在默认的情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,该属性包含了一个指向prototype(原型属性)所在函数的指针。当调用构造函数创建一个实例后,该实例的内部将拥有一个指向构造函数的原型对象的指针。在ECMAScript标准中,将该指针称为[[prototype]]。注意,并没有标准的方式访问[[prototype]],但是在一些浏览器中,为了方便开发者理解,将该属性以proto的形式暴露出来,但是并不建议我们在脚本中使用。好了,概念先介绍到这,举几个例子来详细解释这些概念。


var Person = function(){};
console.log(Person.__proto__);//function(){}
console.log(Person.__proto__ === Function.prototype);//true
console.log(Number.__proto__ === Function.prototype);//true
console.log(Boolean.__proto__ === Function.prototype);//true

__proto__是每个对象都拥有的内置属性,JavaScript中的内置构造函数和自定义构造函数的__proto__都指向Function.prototype,而Function.prototype是一个空函数。由于Function.prototype也是一个对象,其也将拥有__proto__属性。

console.log(Function.prototype.__proto__ === Object.prototype);//true
//追根溯源,Object.prototype也是一个对象,那么其__proto__指向何处
console.log(Object.prototype.__proto__);
//Object.prototype.__proto__指向null,其已到顶
console.log(Object.__proto__===Function.prototype);

//既然构造函数的__proto__指向Function.prototype,那么其实例化的对象的__proto__指向何处
var p = new Person();
console.log(p.__proto__===Person.prototype);//实例化对象的__proto__指向其构造函数的prototype

proto属性可以用来设置对象的原型,由于对象只能拥有一个原型,所以使用proto赋值新的原型时,原来的原型将被覆盖。

var arr = [1,2,3,4,5,6];
var date = new Date();
var obj = {
    name : '张三',
    age : 20
};
var is = true;
var a = 12;
var b = 'zhangsan';
console.log(b.constructor === String);//true
console.log(is.constructor === Boolean);//true
console.log(a.constructor === Number);//true
console.log(arr.constructor === Array);//true
console.log(date.constructor === Date);//true
console.log(obj.constructor === Object);//true

在最新ECMAScript标准定义的七种数据类型中,除了undefined和null这两种原始类型没有constructor属性外,其他都有constructor属性,并且指向创建当前对象的构造函数。关于undefined和null的更多内容,有兴趣的可以阅读这篇文章,探索JavaScript中Null和Undefined的深渊。同时对于构造函数和实例化对象的constructor属性如下面代码所显示那样:

console.log(Person.constructor === Function);//true
console.log(Person.__proto__.constructor === Function);//true

尽管这看上去有点绕,但是仔细分析的话这种结构还是很清晰的。至于这种分析就交给看客了,画一下图就能够清晰的看出了。

prototype属性只有函数才有并且可以访问到,所以实例对象并不是一个函数,其内部也就没有prototype属性。当一个构造函数实例化对象时,其内部的prototype属性值将被作为原型赋值给实例对象,以此设置实例对象的的__proto__属性。所以关于__proto__和constructor和prototype的总结如下图所示:

5642ded50001782508630597.png

所谓的原型链是指:JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

相关文章

网友评论

      本文标题:JavaScript的原型与原型链

      本文链接:https://www.haomeiwen.com/subject/fkfupttx.html