JavaScript进阶:深入理解原型与原型链

JavaScript进阶:深入理解原型与原型链

一、普通对象和函数对象

对象可以分为普通对象和函数对象,ObjectFunctionECMAScript是自带函数对象。看如下代码:

function fun1 () {};
var fun2 = new Function();
 
var ob1 = {};
var ob2 = new Object();
var ob3 = new fun1();
 
console.log (typeof Function);  //Function
console.log(typeof Object);     //Function
 
console.log(typeof fun1);   //Function
console.log(typeof fun2);   //Function
console.log(typeof ob1);        //Object
console.log(typeof ob2);        //Object
console.log(typeof ob3);        //Object

在上面例子中ob123为普通对象。fun12为函数对象,因为fun1fun2归根结底是通过new Function()创建的。

 

二、原型对象

JavaScript中,每当定义一个对象的时候,对象中都包含一些预定义的属性。其中每个函数对象都会有一个prototype属性,这个属性指向函数的原型对象。这里有一个特别重要的特性:每个对象(普通对象和函数对象)都有_proto_属性,但是只有函数对象才有prototype属性

看如下代码:

function Person() {
Person.prototype.name = "tom";
Person.prototype.sayname = function () {
alert (this.name);
}
}
var person1 = new Person();
var person2 = new Person();
alert(person1.name == person2.name); //true,因为两个实例的name属性,都是同一属性,即原型对象中的name。

如果不好理解,可以把上面代码转换一下:

Person.propertype =  {
name = "tom";
sayname = function () {
alert (this.name);
}}

上面提到对象可分为普通对象和函数对象,这里原型对象便是普通对象了。可以这样认为原型对像就是Person.prototype

 

三、原型对象中的construtor属性

上述原型对象Person.prototype这里只给了他一个name属性,默认情况下所有的原型对象自动获得一个construtor属性。construtor属性是一个指针,指向它的构造函数,在例子中指向Person。基本构造函数有Number()、Boolean()、String()、Function()、Object()等等。如果通过构造函数创建新对象,这种创建方法都有一个共同点,那就是代码格式为:var 【对象】 = new 【构造函数】。

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

看看如下代码:

console.log(Person.prototype.constructor === person1.constructor); //true

这里严格相等的原因是实例person1constructor属性和Person.prototypeconstructor属性是同一样东西,正确地说person1constructor属性继承于原型对象Person.prototype

 

四、_proto_

JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做_proto_的内置属性,用于指向创建它的构造函数的原型对象。

对象person1有一个_proto_属性,创建它的构造函数是Person,构造函数的原型对象是Person.prototype,所以

person1._proto_ = Person.prototype;

 

Person的原型对象为Person.prototype;
Person.prototype.constructor = Person;
person1._proto_ = Person.prototype;
person1.constructor = Person;

五、检验对原型链的理解

1person1_proto_是什么?

解:意思是实例对象person1的构造函数的原型对象,首先person1的构造函数是Person,然后Person的原型对象是Person.prototype。所以person1_proto = Person.prototype

2、Person_proto_是什么?

解:因为Person在创建时是通过function Person(){}的形式创建的,所以Person的构造函数是Function,而Function的构造函数是Function.prototype。所以Person_proto = Function.prototype

3、Person.prototype._proto_是什么?

解:在前面提过Person.prototype是一个普通对象,所以他的构造函数是ObjectObject的原型对象是Object.prototype

4、Object._proto_是什么?

解:ObjectPerson一样是函数对象,所以两者答案一样。

5、Object.prototype._proto_是什么?

解:这个比较特殊,结果为null,因为null位于原型链的顶端。

 

六、函数对象

所有函数对象,包括:NumberBooleanStringFunctionObject_proto_都是Function.prototype

Number.__proto__ === Function.prototype  // true
Number.constructor == Function //true
Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true
String.__proto__ === Function.prototype  // true
String.constructor == Function //true
Object.__proto__ === Function.prototype  // true
Object.constructor == Function // true
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
Array.__proto__ === Function.prototype   // true
Array.constructor == Function //true
RegExp.__proto__ === Function.prototype  // true
RegExp.constructor == Function //true
Error.__proto__ === Function.prototype   // true
Error.constructor == Function //true
Date.__proto__ === Function.prototype    // true
Date.constructor == Function //true

ECMAScript中内置构造器有12个,这里列举了8个构造器。剩下的如Global不可以访问,Arguments仅在函数调用时由JS引擎创建,MathJSON是以对象形式存在的。他们的构造函数是Object_proto_Object.prototype。如下代码:

Math.__proto__ === Object.prototype  // true
Math.construrctor == Object // true
JSON.__proto__ === Object.prototype  // true
JSON.construrctor == Object //true

所有的构造器都继承于Function.prototype,甚至包括根构造器ObjectFunction自身。

Function.prototype也是唯一一个类型为Function的原型对象。其他构造器的原型对象的类型都是Object。看如下代码:

console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object

这里可能有一个疑问,Function.prototype是一个Function,那么Function.prototype的构造函数应该是FunctionFunction.prototype._proto_岂不是Function.prototype,这样就进入一个死循环。其实ESMASriptFunction.prototype._protoObject.prototype,而Object.prototype._proto_则是原型链最顶端的null

 

六、构造器的继承

Object的原型对象里面有着如下图中的所有属性,

 

而当我们创建一个数组时:

var arr = new Array();

arr继承了Array.prototype的所有属性和方法,如下图:

 

但是却没有找到constructor,按照道理来说,每一个函数对象的原型对象都应该有constroctor才对。原因是,因为Array.prototype是一个对象,Array.prototype继承了Object.prototype的所有属性和方法,所以Array.prototype最终是拥有constructor属性的。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值