聊聊js最无聊的技术点-原型链

写在前面

js 作为一种动态语言,他的强大之处已经不用我来废话了,那么如果要学习js,你可以学习一些基础入门的简单的,也就是我们常用的一些操作数组啊、格式转化啊等,这些为什么简单呢?其实本质不是它多简单,是它的实用性有多强,我们在写项目的时候很多的时候用到的知识点我们认为是很简单的,原因是是因为我们用了,所以觉得简单,它的简单与否和它本身的难度是没有必然关系的,所以说这么多的意思呢就是今天要说的原型链其实不是很难,只是我们觉得它比较难,原因很简单,我们切实感受到他的存在的时候不多。那么今天我们就简单的会会这个js里面最无聊的部分,原型链。

什么是原型链

  • 实例对象和原型对象之间的关系就叫做原型链
    看到这句话心里骂人的估计不少,其实说人话就是我们写一个构造函数,然后构造函数实例化一个对象,他们之间的关系,也就是__proto__ 和prototype之间的关系,下面我们举个例子:
/**
		 * Gzfun 进行验证实例化对象是可以直接调构造函数原型属性和方法的。  实例对象和原型之间的关系是通过实例化对象的__proto__(原型)进行联系的。 这么关系就叫做原型链
		 * 原型链本身是一种关系,实例对象的原型(__proto__)和构造函数原型(prototype)之间的一种关系就是原型链(或者说实例对象和原型对象之间的一种关系就叫做原型链)    
		 * 实例对象和构造函数是没有直接关系的,实例对象只是构造函数的创造出来的。
		 * @param {Object} param1
		 * @param {Object} param2
		 */
		function Gzfun(param1, param2) {
			this.param1 = param1;
			this.param2 = param2;
			this.sayhello = function() {
				console.info("hello")
			}
		}
		//给原型加上属性和方法
		Gzfun.prototype.param3 = "value3";
		Gzfun.prototype.saybye = function() {
			console.info("bye-bye");
		}
		//实例化一个对象并且初始化
		var gzfun = new Gzfun("value1", "value2");
		//调原型链上面的方法
		gzfun.saybye();
		gzfun.sayhello();
		console.dir(gzfun);
		console.dir(Gzfun);
		//判断构造函数原型的prototype 是和我们实例化对象上面的__proto__对象是相等的
		console.info(gzfun.__proto__ === Gzfun.prototype)

验证原型链中的this指向问题

/**
		 * 验证原型对象中方法的this就是实例对象
		 * @param {Object} val
		 */
		
		function Check_Proto(val) {
			this.val = val;
			console.info(this); //这个this其实就是下面的check_proto 和 ch
		}
		Check_Proto.prototype.sayhi = function() {
			console.info(this); 
			console.info("hi");
			return "123";
		} 
		var check_proto = new Check_Proto("value1");
		var ch = new Check_Proto();
		console.info(check_proto, ch.val, ch.sayhi());
		/**
		 * 结论1:原型对象中方法的this就是实例对象
		 * 结论2:构造函数中的this就是实例对象
		 */

运行结果

在这里插入图片描述

解释一波:上面的可以看得出来我们首先在构造函数里面打印了this,我们想知道的是他和我们实例化的对象有什么关系,所以在最后的时候我们将实例化的对象直接打印出来,可以看的出来,其实原型对象中的this就是实例对象

验证原型链的指向是不是可以改变

既然我们可以直接在构造函数上面添加一个新的属性出来,那么是不是我们将这个初始化的对象重定向一个新的构造函数以后他的指向就发生改变了呢?我们测试一下:

function Check_Proto1() {
			console.info("我是Check_Proto1");
		}
		Check_Proto1.prototype.saych1 = function() {
			console.info("您好,我是Check_Proto1")
		}

		function Check_Proto2() {

		}
		//给Check_Proto2原型加上一个函数
		Check_Proto2.prototype.sayche2 = function(){
			
		}
		//Check_Proto2 的原型指向来Check_Proto1的对象    
		Check_Proto2.prototype = new Check_Proto1();
		var ch2 = new Check_Proto2();
		ch2.saych1();

在这里插入图片描述

  • 我们可以看到,我首先是声明了一个构造函数Check_Proto1,然后我们给Check_Proto1添加原型属性,saych1函数,这个时候我们声明第二个构造函数,我们同样给第二个添加原型函数saych2,此时我们Check_Proto1的实例化的对象给到Check_Proto2的原型对象,这个时候我们实例化Check_Proto2,看一下能不能调的通Check_Proto1的原型函数,看结果就明白了,其实是可以的,说明Check_Proto2的原型对象的指向改变了。

结论

结论:当我们不写Check_Proto2.prototype = new Check_Proto1(); 的时候也就是我们不将原型链上面的指向改变的时候我们ch2的对象是有构造函数的方法的,也就是sayche2
也就是我们可以直接调che2.sayche2()的函数,但是当我们的原型链的指向发生改变的时候,我们的ch2的sayche2的函数就不复存在来,说明来我们的原型链的指向是可以发生改变的。
结论:构造函数的原型对象(prototype) 如果发生改变,那么实例化的对象的原型(proto)也会跟着发生改变 他们的关系是通过是通过__proto__进行联系的。

原型链实现继承

写过java的基本都是知道的,java的三大特性:封装、继承、多态,那么我们的js其实也是有的,我们下面使用原型链的特性实现一个基本的继承,这里简单的解释一下什么是继承,我们都知道java是一门以类作为记一个基础的语言,所谓的类其实就是类别,我们在写函数的时候很多的名字都是有意义的,比如说人就是一个大类,那么人还包括什么呢?女人、男人还可以分为大人、小孩、等等类别,那么不管是什么人,都有的特性就是有思想,会吃,会喝等特性,但是小类里面又可以分为男人、女人他们的特性呢?女人可以生孩子,很伟大的一个特性,男人可以撑起来一个家、也很伟大,那么这些就是一些比较特殊的特性,我们在写函数的时候如果分为了小类作为函数的话,那么我们希望的是女人不仅仅可以生孩子,还要可以吃,喝等人有的特性,这个时候我们不需要再声明一个人的函数,我们只需要将人的大类被女人的小类继承,那么女人的这个类别就有了人类的特性,这个就是继承的基本实现过程。至于说封装和多态这里就不说了,都是相互依赖的,没有继承也不会有多态了,没有不停的封装也不会有所谓的继承了,这个喜欢java的慢慢研究,我这里就不班门弄斧了。

源码

function notebook(keyword,number){
			this.keyword = keyword;
			this.number = number;
		}
		notebook.prototype.wirte = function(){
			console.info("笔记本是可以打字的")
		}
		notebook.prototype.playvideo = function(){
			console.info("笔记本是可以放视频的")
		}
		//mbp自带的一些属性
		function macpro(bar){
			this.bar = bar;
		}
		//将苹果笔记本的原型指向notebook的实例对象,进行一个继承的操作
		macpro.prototype = new notebook("键盘","数字键");
		macpro.prototype.havebar = function(){
			console.info("我是苹果笔记本我有bar");
		}
		var macp = new macpro("这是苹果的touchbar");
		console.info(macp.keyword);
		console.info(macp.number);
		macp.wirte();
		macp.playvideo();
		console.info(macp.bar);
		macp.havebar();

代码很简单,但是简单的做一个解释,因为上面的解释还是比较少的,我们首先给构造函数notebook两个基本的参数属性,然后我们原型对象上添加两个方法,然后我们新建一个macpro的构造函数,这个函数也属于笔记本的一类,那么我他也应该具有的属性就是可以打字,可以放视频,同时有键盘等属性,但是macpro有什么特性呢?有touchbar,这是一般的笔记本没有的,我们这个时候将macpro的原型指向notebook的构造函数也就是实例对象,我们就有了notebook的基本属性,下面看一下打印的结果:

结果

键盘
原型链.html:121 数字键
原型链.html:105 笔记本是可以打字的
原型链.html:108 笔记本是可以放视频的
原型链.html:124 这是苹果的touchbar
原型链.html:117 我是苹果笔记本我有bar

  • 由于在火车上,这里没办法登录截图的软件,就直接复制了,担待一下!

总结

写到这里,关于原型链的基本的介绍就不写了,我也觉得这个东西很无聊,所以也是耐着性子写完的,不过这个东西确实是很有必要的一个东西,我们如果看过juqery和vue的源码的话,会发现,里面其实是大量的原型链进行实现的基本功能,所以说还是很有必要研究的一个东西,以后还会写一些关于原型链的知识点,今天就先这样了,拜拜!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章