1. 前言
JS中原型和原型链的概念一直都是混淆不清,确实需要时间,偶尔回头看看。对于原型和原型链的理解,其实一直处于比较浅的概念。有句话说,没理解透原型和原型链,就算还没有真正入门的前端。希望通过总结这篇文章,我算的上入门前端了,没入门也能偶尔翻翻看看/(ㄒoㄒ)/~~。
在理解原型之前,需要弄清楚几个概念:函数对象、普通对象、原型对象(prototype)、__proto__属性和构造器constructor。
2. 函数对象
顾名思义,由函数new Function()创建得来的对象都是函数对象。函数对象拥有__proto__属性和prototype属性。
注意:只有函数对象才有prototype属性!
系统内置的函数对象有
Function、Object、Array、Date、String、自定义函数等
//函数对象
function f1(){};
var f2 = function(){};
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof Object); //function
console.log(typeof Array); //function
console.log(typeof String); //function
console.log(typeof Date); //function
console.log(typeof Function); //function
思考: js的引用数据类型都属于函数对象吗?
3. 普通对象
除函数对象外的对象都是普通对象。且只有指向原型链的__proto__属性,没有prototype属性。
//普通对象
var a = 123;
var b = {};
var c = new Object();
console.log(typeof a); //Object
console.log(typeof b); //Object
console.log(typeof c); //Object
思考:js有五种基本类型:Undefined,Null,Boolean,Number和String,他们都是属于普通对象吗?
4. 原型对象
JS设计之初为了实现简单继承,引入了prototype属性,也叫原型对象。
//原型对象
function animal(){};
console.log(typeof animal.prototype) //Object
console.log(typeof Object.prototype) // Object
从本质上来讲,原型对象是一个普通对象,是函数对象的构造函数创建的一个实例。相当于在person创建的时候,自动创建了一个它的实例,并且把这个实例赋值给了prototype。
但是存在一个特例Function, Function.prototype是原型对象,本质却是函数对象。作为一个函数对象,又没有prototype属性。
console.log(typeof Function.prototype) // 特殊 Function
console.log(typeof Function.prototype.prototype) //undefined 函数对象却没有prototype属性
思考:原型对象prototype 属于函数对象吗?
5. __proto__属性
__proto__属性在本质上为一个指针,指向创造obj对象的函数对象的prototype属性。所有的对象obj都具有proto属性(null和undefined除外)。
function Dog(){};
Dog.prototype.name = "小黄";
Dog.prototype.age = 13;
Dog.prototype.getAge = function(){
return this.age;
}
var dog1 = new Dog();
var dog2 = new Dog();
dog2.name = "小黑";
console.log(dog1.name); // 小黄 来自原型
console.log(dog2.name); // 小黑 来自实例
对象dog1和对象dog2中的__proto__属性指向创造其实例的函数对象Dog的原型对象即Dog.prototype,如下所示:
dog1.__proto__ === Dog.prototype //true
Dog.prototype.__proto__ === Object.prototype //继承Object 下面原型链说
dog1.__proto__.__proto__ === Object.prototype
Dog.prototype.constructor === Dog
Dog.prototype.isPrototypeOf(dog1)
获取对象的原型
dog1.__proto__ //不推荐
Object.getPrototypeOf(dog1) === Dog.prototype //推荐
思考一下,var obj={}; obj.prototype.proto指向谁?
6.构造器constructor
constructor 属性返回对创建此对象的函数对象的引用。
function a(){};
console.log(a.constructor===Function); //true
console.log(a.prototype.constructor===a); //true
函数a是由Function创造出来,那么它的constructor指向的Function,a.prototype是由new a()方式创造出来,那么a.prototype.constructor理应指向a
思考:a.prototype.proto.constructor指向谁?
7. 原型链
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想指针(constructor),而实例对象都包含一个指向原型对象的内部指针(proto)。
如果让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针(proto),另一个原型也包含着一个指向另一个构造函数的指针(constructor)。
假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。
function animal(){
this.type = "animal";
}
animal.prototype.getType = function(){
return this.type;
}
function dog(){
this.name = "dog";
}
dog.prototype = new animal();
dog.prototype.getName = function(){
return this.name;
}
var xiaohuang = new dog();
//原型链关系
xiaohuang.__proto__ === dog.prototype
dog.prototype.__proto__ === animal.prototype
animal.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
8.思考解答
函数对象思考题解答
思考: js的引用数据类型都属于函数对象吗?
引用类型值:指的是那些保存在堆内存中的对象,意思是,变量中保存的实际上只是一个指针,这个指针执行内存中的另一个位置,由该位置保存对象
那么数组,普通对象,函数对象都算是引用数据类型,引用数据类型范围包含函数对象的范围
普通对象思考题解答
思考:js有五种基本类型:Undefined,Null,Boolean,Number和String,他们都是属于普通对象吗?
基本类型值:指的是保存在栈内存中的简单数据段;除开函数对象之外的对象都是普通对象,那么普通对象范围是包含基本数据类型的。
事实上(函数对象,普通对象)以及(基本数据类型,引用数据类型)是在不同角度对js变量进行的定义
原型对象思考题解答
思考:原型对象prototype 属于函数对象吗?
事实上 这个问题要进行分别回答:
Function.prototype 属于函数对象,其他对象的prototype属于普通对象
function a(){};
console.log(typeof Function.prototype); // function
console.log(typeof a.prototype); //object
原型对象prototype的创造过程为:
var temp = new a();
a.prototype = temp;
temp当然是普通对象,但是看下Function的prototype创造过程:
var a = new Function();
Function.prototype = a;
现在不难理解,Function的prototype为什么是函数对象了。
指针_proto_思考题解答
思考一下,var obj={}; obj.prototype.proto指向谁?
这里分步思考:
1、obj是是一个普通对象
2、什么类型的对象是由prototype属性的?当然是函数对象
3、所以obj是没有prototype属性的
4、所以obj.prototype===undefined
5、所以此题的最终问题是:undefined.proto指向什么
6、所有的对象obj都具有proto属性(null和undefined除外)!所以答案是 js报错
构造器constructor思考题解答
思考:a.prototype.proto.constructor指向谁?
function a(){};
这里继续分解题目:
1、a.prototype指向a的一个实例,我们已经多次强调了,而且属于普通对象
2、proto定义为:指向创造obj对象的函数对象的prototype属性,所以看下谁创造了a.prototype,因为a.prototype是普通对象,类型为object,那么是Object创造了它。
3、那么显而易见a.prototype.proto指向了Object.prototype
4、那么题目简化为Object.prototype.constructor指向谁
5、继续分解题目,Object.prototype为基本对象,那么就是Object创造了它,那么它的constructor就指向了Object
Object.prototype.constructor===Object //true
继续之,到了尽头
Object.prototype.__proto__===null //true
参考原文:http://www.0313.name/2017/01/13/prototype-proto-constructor.html