您的位置:首页 > Web前端 > JavaScript

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

2017-08-27 01:01 471 查看
JavaScript进阶:深入理解原型与原型链

一、普通对象和函数对象

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

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


在上面例子中ob1、2、3为普通对象。fun1、2为函数对象,因为fun1、fun2归根结底是通过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


这里严格相等的原因是实例person1的constructor属性和Person.prototype的constructor属性是同一样东西,正确地说person1的constructor属性继承于原型对象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;


五、检验对原型链的理解

1、person1_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是一个普通对象,所以他的构造函数是Object,Object的原型对象是Object.prototype;

4、Object._proto_是什么?

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

5、Object.prototype._proto_是什么?

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

 

六、函数对象

所有函数对象,包括:Number、Boolean、String、Function、Object的_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引擎创建,Math、JSON是以对象形式存在的。他们的构造函数是Object,_proto_是Object.prototype。如下代码:

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


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

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的构造函数应该是Function,Function.prototype._proto_岂不是Function.prototype,这样就进入一个死循环。其实ESMASript中Function.prototype._proto是Object.prototype,而Object.prototype._proto_则是原型链最顶端的null。

 

六、构造器的继承

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

 


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

var arr = new Array();

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

 


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

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: