0.写在前面
如果大家想深入学习Javascript编程语言,Javascript中的原型及原型链是必须掌握的。当初我在学习原型及原型链的时候,就遇到过不少阻碍,希望通过我的这篇文章,能够让你真正的掌握JavaScript中的原型及原型链。好啦,开始我们的原型及原型链的旅途吧~
在介绍Javascript原型之前,我们先来了解一段历史。
1.Javascript继承机制的设计思想
1994年,网景公司发布了Navigator浏览器0.9版,当时这个版本的浏览器只能用来浏览,并不具有与用户用户进行互动的功能,比如说,要判断用户是否填写了表单数据,只能通过服务器来进行判断,这样会带来一个弊端:极大的浪费了带宽以及服务器资源。在这种情况下,就需要一种脚本语言,这种语言能够与浏览器进行交互,Brendan Eich负责开发这种脚本语言(也就是Javascript),当时,这位工程师认为这种脚本语言不需要设计的太复杂,只需完成简单操作即可,比如判断用户是否填写了表单数据。此时,我们还要了解下当时的编程语言背景,在1994年的时候,C++是最兴盛的面向对象的编程语言,Java1.0也将于第二年推出,Brendan Eich也将Javascript设计为面向对象的语言,在Javascript中一切皆对象。当时,他遇到了一个难题,到底需不需要将继承机制引入Javascript中?最终的结果是,也许他受到了C++和Java的影响,继承机制最终被引入到Javascript编程语言中。
下面我们来看看在C++中生成一个对象的方法:
A *a=new A(param);
而在Java中生成一个对象的方法:
Foo foo=new Foo();
我们再来看看Javascript生成一个对象的方法:
function Dog(name){
this.name=name;
}
var dogA = new Dog("旺旺");
alert(dogA.name);//旺旺
我们再来看看Javascript中另外一种写法:
function Dog(name){
this.name=name;
this.species ="犬科";
}
var dogA = new Dog("旺旺");
dogA.species="猫科";
var dogB = new Dog("旺旺2");
alert(dogB.species);//犬科
在这个例子中,生成了两个对象dogA与dogB,dogA修改了species,但是我们访问dogB的species,还是原来的值。于是,我们可以看出通过这种方法生成的实例对象,每个对象都有自己的属性和方法的副本,实例对象间不能做到属性的方法的共享,这样带来的一个缺点就是极大的浪费了系统的资源。有没有改进的方法呢?有,肯定有!
2.Javascript中原型(prototype)的引入
考虑到上面的不足,这位工程师决定给每个构造函数添加一个prototype属性,这个属性指向一个对象,称为prototype对象。在Javascript中,一切皆对象,对象可以分为三类:实例对象(通过new和构造函数创建出来的对象)、函数对象(一般也称为函数)、原型对象(函数对象的prototype属性所指向的对象)。我们首先来看下实例对象中的属性和方法,如下图:
实例一旦创建,将自动引用prototype对象的方法和属性,也就是说,针对实例对象而言,它的属性和方法可以分为两种:一种是本地的,另外一种是引用的。
prototype、_proto_和constructor三角关系
我将用下面的一副图来描述三者的关系:
我将上幅图总结为下面几点内容:
- 任何函数对象都有prototype属性,它指向对应的原型对象,表示其实例对象的原型对象;
- 任何原型对象都有一个constructor属性,它指向对应的函数对象;
任何对象都有一个隐藏的_proto属性,它是对原型对象的引用;
- _proto_属性不是一个规范的属性,只是部分浏览器实现了此属性(如chrome和Firefox),如果想访问对象的原型,可以使用Object.getPrototype(object)访问。
一定要牢记上面的几点内容,它将对后面的内容非常重要。
3 原型实例分析
说明:后面的实例,如果看不懂,可以再看看前面的内容,好好理解下前面的内容,一定可以理解后面的例子的。同时,下面的例子运行结果我会有一定的解释。
step1:查看对象的原型
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
}
var will = new Person("Will", 28);
console.log(will.__proto__);
console.log(will.constructor);
运行结果:
解释:will对象本身并没有"constructor"这个属性,但是通过原型链查找,找到了will原型(will.__proto__)的"constructor"属性,并得到了Person函数
对象之间的关系:
step2:查看对象will原型的原型
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
}
console.log(will.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__);
console.log(Person.prototype.constructor);
console.log(Person.prototype.constructor === Person);
运行结果:
对象之间的关系
step3:查看对象Object的原型
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
}
console.log(Person.prototype.__proto__ === Object.prototype);
console.log(typeof Object);
console.log(Object);
console.log(Object.prototype);
console.log(Object.prototype.__proto__);
console.log(Object.prototype.constructor);
运行结果:
对象之间的关系:
step4:查看函数对象的原型
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
}
console.log(Person.__proto__ === Function.prototype);
console.log(Person.constructor === Function)
console.log(typeof Function);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.__proto__);
console.log(Function.prototype.constructor);
运行结果:
对象之间的关系:
4 通过原型改进实例-实现继承
step1:最老的方式
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
}
var will = new Person('Will',28);
var wilber = new Person("Will", 20);
对象之间的关系:
step2:通过原型prototype实现继承
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
对象之间的关系:
5 原型链
什么是原型链?
由于_proto_是任何对象都有的属性,而Javascript中万物皆对象,所以会形成一条_proto_连接起来的链条,递归访问_proto_必须最终到头,并且值为null。
原型链有什么作用?
属性查找与隐藏:当Javascript引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,再沿着_proto_这条链向上查找,但不会查找自身的prototype。
var A = function(){};
var a = new A();
以上面的这幅图为例,查找某个属性的时候,会沿着这条原型链进行查找,直到为null。
原型链之属性查找
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.MaxNumber = 9999;
Person.__proto__.MinNumber = -9999;
var will = new Person("Will", 28);
console.log(will.MaxNumber);// 9999
console.log(will.MinNumber);//undefined
原型链之属性隐藏
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function(){
console.log(this.name + " is " + this.age + " years old");
}
var will = new Person("Will", 28);
will.getInfo = function(){
console.log("getInfo method from will instead of prototype");//
};
will.getInfo();
对象创建方式影响原型链的构成
var July = {
name: "July",
age: 28,
getInfo: function(){
console.log(this.name + " is " + this.age + " years old");
},
}
console.log(July.getInfo());
hasOwnProperty
var will = new Person('Will',28);
var wilber = new Person("Will", 20);
for(var attr in will){
console.log(attr);
}
console.log('---------------');
for(var attr in wilber){
if(will.hasOwnProperty(attr)){
console.log(attr);
}
}
6.总结
- 在Javascript中,通过原型(prototype)实现了对象的继承;
- 在Javascript中,一切皆对象,prototype、_proto_与constructorJavascript中所有的对象关联起来;
- 原型链可以实现对象属性的查找和隐藏; hasOwnProterty函数可以用来判断属性是对象本地属性还是原型链上的属性;
相信到这里,你已经掌握了Javascript中的原型和原型链的知识点了。
欢迎关注我的微信公众号。您的支持将鼓励我继续创作!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。