【Java Script】详解 原型链

Youzg Logo

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

作用

  1. 表明一个对象所属类
  2. 在“对象.成员”访问失败时,会沿着原型链继续访问

在这里,本人要强调一点:
在几乎所有程序设计语言中,
下划线 开头的变量,几乎都是被这个语言“隐藏”的变量,
即,这个语言极其不建议编程者直接操作这类变量!

这里的原型链(__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);

现在,本人来展示下控制台的内容:
控制台 展示
因此,我们能够得出结论

  1. 子类对象.constructor == 子类
  2. 子类.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);

那么,现在本人来展示下控制台的内容:
控制台 展示
可以看到,继承体系实现了!


在本文最后,本人还是强调一点:

以下划线开头的变量,是该语言的“隐藏变量”
在一般的情况下,我们不要使用它们
只需要知道有这么个存在就行


参考博文:

若是同学们还想深挖原型链的相关知识的话,
本人也为同学们找到了一篇讲解十分清晰的博文:

《最详尽的 JS 原型与原型链终极详解》


posted @ 2020-05-12 01:01  在下右转,有何贵干  阅读(43)  评论(0编辑  收藏  举报