【Java Script】详解 原型链
Java Script 与 面向对象思想
在本人讲解Java Script的第一篇博文起,就讲到过:
Java Script作为sun公司的产品,
并且在当时,乃至如今,Java的面向对象的思想,都很重要!
因此,Java Script 在一定程度上沿袭了Java的许多面向对象 思想
那么,在Java中,类与类之间能够进行继承
相对地,在Java Script中,类与类之间也能够进行继承
这时候可能会有同学有疑问了:
Java Script哪来的类?
答曰:
Java Script中的函数,其本质上就是 类
那么,本人现在来验证下上述的结论:
首先本人来给出一个用于测试的html文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
右转测试页面
</body>
<script src="js/youzg.js" type="text/javascript" charset="UTF-8"></script>
</html>
那么,现在本人来提供一个youzg.js文件的内容:
function Fan() {
this.name = "youzg";
this.age = "666";
this.setName = function(name) {
this.name = name || "youzgFan";
}
this.getName = function() {
return this.name;
}
this.setAge = function(age) {
this.age = age || "233";
}
this.getAge = function() {
return this.age;
}
};
console.log(Fan);
console.log("============================================================");
var aFan = new Fan();
aFan.setAge();
aFan.setName("aFanName");
console.log(aFan);
console.log("------------------------------------------------------------");
console.log(aFan.getName());
console.log(aFan.getAge());
console.log("============================================================");
console.log("aFan instanceof Fun", aFan instanceof Fan);
那么,现在本人来展示下控制台的结果:
可以看到,Java Script中的函数,确实和Java中的类几乎一致!
这样就印证了本人上文中所讲到的结论:
Java Script中的函数,其本质上就是 类
那么,同学们在理解了上述的讲解后,不要忽然开始得意
请看本文的标题 —— 原型链
这才是本文的主题!
原型链 与 原型对象:
那么,什么是原型链呢?
本人现在还是通过上面的图来进行讲解:
细心的同学能够发现,在我们new出来的对象中,
存在着一个名为
__proto__
的成员
其实,这个成员,就是本文的核心讲点 —— 原型链
原型链:
概念:
在任意对象和Object.prototype之间,
存在着一条以非标准属性__proto__进行连接的链,
我们将这条链称为原型链,
在默认情况下,一个任意的对象的原型是Object.prototype
作用:
- 表明一个对象的所属类
- 在“对象.成员”访问失败时,会沿着原型链继续访问
在这里,本人要强调一点:
在几乎所有程序设计语言中,
用下划线 开头的变量,几乎都是被这个语言“隐藏”的变量,
即,这个语言极其不建议编程者直接操作这类变量!
这里的原型链(__proto __)就是一个“隐藏变量”!
但是,我们若是在火狐浏览器中运行上述代码,显示的结果会是如下所示:
其实相对于第一张图,本人更倾向于火狐的控制台的展示结果
因为在Java Script当中,每一个类或是每一个对象,
都存在着一个特定的成员 —— prototy成员(原型对象):
原型对象:
我们每创建一个函数,都有一个prototype(原型)属性,
这个属性是一个指针,指向一个对象,
这个对象包含特定类型所有实例共享的属性和方法
原型对象的内容,包含着两个重要的成员:
- constructor(构造函数)
- __proto __(原型链)
如下图所示:
构造函数:
本人对上面的JavaScript文件 稍作更改:
function Kid() {
this.age = 18;
this.marry = function() {
return "male";
}
}
var child = new Kid();
console.log("child.constructor:", child.constructor);
console.log("Kid:", Kid);
console.log("child.constructor == Kid:", child.constructor == Kid);
现在,本人来展示下控制台的内容:
因此,我们能够得出结论:
- 子类对象.constructor == 子类
- 子类.prototype.constructor == 子类
原型链:
现在,本人对上面的JavaScript文件 稍作更改:
function Kid() {
this.age = 18;
this.marry = function() {
return "male";
}
}
var child = new Kid();
console.log("child.__proto__ == Kid.prototype:", child.__proto__ == Kid.prototype);
现在,本人来展示下控制台的内容:
由此,我们能够得出如下结论:
子类对象.__proto __ == 子类.prototype
现在,本人再来修改下JavaScript文件:
function Father() {
this.money = 10086;
this.setFMoney = function(money) {
this.money = money || 10000;
}
this.getFMoney = function() {
return this.money;
}
}
function Kid() {
this.age = 18;
this.marry = function() {
return "male";
}
}
var child = new Father();
Kid.prototype = child;
var kidO = new Kid();
console.log("kidO.getFMoney():", kidO.getFMoney());
现在,本人来展示下运行结果:
我们能够看到:
经过对Kid类的prototype属性的操作,
Kid类对象竟然能够调用Father类的函数成员!
其本质上是让子类的 原型链(__proto __) 指向 父类的 原型对象(prototype)
如下图所示:
这是因为:
在Java Script中,若是我们访问一个对象的某成员
若 在此对象中未找到,则会顺着它的 “原型链” 去寻找
说到这里,相信已经有同学和我的感触一样了:
在此对象中未找到,则会顺着 原型链去寻找
这在Java中,不就是 继承体系链 嘛
那么,看了上面的那么多解释,
相信已经有同学晕头转向了
本人怎么可能不给右转粉一些福利呢?
下面,本人就来给出一套公式,来帮助大家巩固下上述的知识点:
公式:
假设:
父类 —— Father类
子类 —— Kid类
子类对象 —— child对象
由上述的假设,我们能够推导出:
Kid.prototype.constructor == Kid;
child.constructor == Kid;
child.__proto__ == Kid.prototype;
Kid.__proto__ == Father.prototype
child.__proto__.__proto__ == Father.prototype
根据上述的结论,我们可以来制作一个小工具,
来实现 类与类 之间的继承:
函数的继承:
依据上面的例子,
function (SuperClass, ChildClass) {
if (SuperClass === undefined || ChildClass === undefined
|| SuperClass.prototype === undefined
|| ChildClass.prototype === undefined) {
return;
}
var tmp = new SuperClass;
tmp.constructor = ChildClass; // 此语句可以不加,本人在这里加上主要是为了满足“编程规范”
ChildClass.prototype = tmp;
}
那么,现在本人来展示下这个小工具的使用:
function Father() {
this.money = 10086;
this.setFMoney = function(money) {
this.money = money || 10000;
}
this.getFMoney = function() {
return this.money;
}
}
function Kid() {
this.age = 18;
this.marry = function() {
return "male";
}
}
(function Extend(SuperClass, ChildClass) {
if (SuperClass === undefined || ChildClass === undefined
|| SuperClass.prototype === undefined
|| ChildClass.prototype === undefined) {
return;
}
var tmp = new SuperClass;
tmp.constructor = ChildClass; // 此语句可以不加,本人在这里加上主要是为了满足“编程规范”
ChildClass.prototype = tmp;
}(Father, Kid));
var child = new Kid();
child.getFMoney();
console.log(child);
console.log("Kid:", Kid);
console.log("Father:", Father);
那么,现在本人来展示下控制台的内容:
可以看到,继承体系实现了!
在本文最后,本人还是强调一点:
以下划线开头的变量,是该语言的“隐藏变量”
在一般的情况下,我们不要使用它们
只需要知道有这么个存在就行
参考博文:
若是同学们还想深挖原型链的相关知识的话,
本人也为同学们找到了一篇讲解十分清晰的博文: