大家好,我是IT修真院北京总院第29期的学员禚洪宇,一枚正直、纯洁、善良的前端程序员今天给大家分享一下,修真院官网JS任务5深度思考中的知识点——原型链是什么?有什么功能?若想访问一个对象的原型,应该使用什么方法?
1 背景介绍
1.1什么是原型
学习原型链之前我们首先要明白什么是原型;那么什么是原型呢?我们来简单学习一下:
只要我们像这样简单的定义一个函数foo(),就可以访问像访问其他对象一样访问该函数的属性:
>>>function foo(a,b){return a*b;}
>>>foo.length
2
>>>foo.constructor
Function()
其实我们在创建一个函数的时候,这个函数就包括了prototype属性,它的初始值是一个空对象(object),
>>>typeof foo.prototype
"object"
所以我们可以自己在这个空对象中添加属性,像这样:
>>>foo.prototype = {}
1.2 原型有什么作用
简述一下prototype属性的出现:
第一版浏览器无用户交互—》需要脚本语言—》借鉴C++和Java语言,又想节省服务器资源和时间—》prototype。
由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。
这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
而实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。
2 知识剖析
2.1 原型链是什么
我们上面说到,每个构造函数在创建时都包含一个属性prototype,其初始值是一个空对象;
原型对象结构:
Function.prototype={
constructor :Function,
__proto__:parentprototype,
someprototypeproperties: ...
};
函数的原型对象constructor默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针__proto__,该指针指向上一层的原型对象,而上一层的原型对象的结构依然类似,这样利用__proto__一直指向Object的原型对象上,而Object的原型对象用Object.prototype.__proto__ = null表示原型链的最顶端,如此变形成了javascript的原型链继承,同时也解释了为什么所有的javascript对象都具有Object的基本方法。
2.2 若想访问一个对象的原型,应该使用什么方法?
获取实例对象obj的原型对象,有三种方法
1. obj.__proto__
2. obj.constructor.prototype
3. Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。最新的ES6标准规定,__proto__属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype在手动改变原型对象时,可能会失效。
3 常见问题
Array.isArray(Array.prototype)输出什么?
4 解决方案
Array.prototype是Array构造函数实例的原型,构造函数实例化后仍为数组,所以输出true。
5 扩展思考
Q1: prototype与_proto_是什么关系
__proto__(隐式原型)、prototype(显式原型)
A1: 显式原型 explicit prototype property:每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。
隐式原型 implicit prototype link:JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问。ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf().
二者的关系:
隐式原型指向创建这个对象的函数(constructor)的prototype
Q2:在IE中可以使用_proto_属性吗?
A:_proto_将在ES6中进行标准化,目前在ES6的草案附录B中。
Q3:_proto_的兼容性怎么样?
A:_proto_目前是浏览器的内置属性,不同的浏览器有不同的情况。
6 参考文献
参考三:谈谈对原型链的理解
参考四:《JavaScript面向对象编程指南》