JavaScript 学习笔记 之 原型 (二)

修改原型链

在关联两个对象的时候我们通常会使用Object.create(..)方法

这个方法接受两个参数第一个参数是创建的对象的[[prototype]]属性引用的对象,第二个参数是想要给新对象添加的属性以及对应的属性描述符

		var obj1 = {
			a: "a"
		}
		var obj2 = Object.create(obj1, {
			b: {
				value: "b"
			}
		});
		console.log(obj2.__proto__ === obj1); //true

在原型继承(关联两个构造函数的prototype对象)时,我们同样也可以这么做,例如

		Fun2.prototype = Object.create(Fun1.prototype);

但事实上很多人会选择另外两个错误的操作

例如,现在我们需要的是Fun2.prototype引用一个[[prototype]]指向Fun1.prototype的对象

错误操作 一

		Fun2.prototype = Fun1.prototype;

但事实上这么做只是让Fun2.prototype引用了Fun1.prototype引用对象本身

而这么做会导致修改Fun2.prototype的时候修改到Fun1.prototype,显然不合适

错误操作二

		Fun2.prototype = new Fun1();

这个操作基本能满足我们的需求,但是可能产生一些副作用

比如Fun1如果存在一些给this添加属性或者注册到其他对象之类的方法

就会影响到Fun2的后代,这也存在一定隐患

正确操作除了先前我们说过的Object.create(..)方法

还可以通过设置.__proto__(双下划线)属性来实现,这个属性在ES6之前只被部分浏览器支持,并且不是一个标准方法

但是在ES6之后变成了一个标准方法并被所有浏览器支持,具体的我们稍后再介绍

还有一种选择是ES6中另一个Object.setPrototypeOf(..)方法

		Fun2.prototype = Object.create(Fun1.prototype) //ES6之前需要抛弃默认的Fun2.prototype

		Object.setPrototypeOf(Fun2.prototype, Fun1.prototype) //ES6之后直接修改现有的Fun.prototype

这两种方法结果是等效的,除了些许因为垃圾回收而造成的轻微性能损失

查询原型链

查询一个对象中的原型链是否有另一个对象也是一个常用的操作

方法一

instanceOf 操作符左侧是一个普通对象,右侧是一个函数,instanceOf回答的是在对象的整条[[prototype]]连中是否有函数的prototype属性指向的对象

		function Fun() {
			//..
		}
		var a = new Fun();
		console.log(a instanceof Fun);//true

在这个例子中指的是a的[[prototype]]链中是否有Fun.prototype指向的对象

但是这个方法仅限于处理对象和函数之间的关系

(bind()硬绑定返回的函数是没有prototype对象的,强行使用instanceOf操作符实际上查询的是原函数的prototype对象)

方法二

isPrototypeOf(..)函数,这个函数直接可以判断两个对象之间的关系

		function Fun() {
			//..
		}
		var a = new Fun();
		console.log(Fun.prototype.isPrototypeOf(a)); //true

这个例子中回答的是Fun.prototype是否出现在a的[[prototype]]链上

方法三

在ES5中,我们也可以直接用Object.getPrototypeOf(..)方法来获取一个对象的[[prototype]]链

		function Fun() {
			//..
		}
		var a = new Fun();
		console.log(Object.getPrototypeOf(a) === Fun.prototype); //true

 

方法四

.__proto__(双下划线)属性,在ES6后成为了一个标准的方法,但在ES6之前只有部分浏览器支持且不是一个标准的方法

		function Fun() {
			//..
		}
		var a = new Fun();
		console.log(a.__proto__ === Fun.prototype); //true

.__proto__属性可以访问到对象中的[[prototype]]属性

你甚至可用.__proto__.__proto__...的方式来遍历原型链

但是这个属性和.constructor一样,实际上并不存在于你调用的对象中,而是存在于Object.prototype中

而获取值事实上也是调用了一个__proto__()方法(getter方法)

兼容性

Object.create(..)是ES5新增的函数,所以在ES5之前我们可用一段简单的polyfill代码来部分实现这一功能

(因为ES5之前没有办法模拟属性描述符)

		if(!Object.create) {
			Object.create = function(o) {
				function F() {}
				F.prototype = o;
				return new F();
			}
		}

猜你喜欢

转载自blog.csdn.net/Aproducer/article/details/82720095