欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js instanceof 的工作原理细解

程序员文章站 2022-07-13 21:10:53
...

根据 MDN 的解释

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。


s instanceof F 用递归函数来表达, 流程大致如下:

function _instanceof(s, F) {
	if(s.__proto__ === F.prototype) {
		// 找到目标
		return true
	} else if("__proto__" in F) {
		// 存在上一层原型1
		_instanceof(s, F.__proto__)
	} else {
		// 穷尽原型链仍找不到目标
		return false
	}
}
_instanceof(s, F)

instanceof 的工作原理就是将 s 每一层的 __proto__ 与 F.prototype 做比较
找到相同返回 true
至最后一层仍没有找到返回 false




因为构造函数的 prototype 可以修改(一般不建议这么做), 所以 instanceof 返回的结果并不是固定的, 甚至是错误的
我们通过下例理解其原因

<html>

<head>
	<title>instanceof 的工作原理</title>
</head>

<body>

	<script type="text/javascript">
		function section1() {
			function F1() { }

			function F2() { }

			// F1.prototype 的粗略结构
			// F1_prototype = {
			// 	constructor: F1,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			// F2.prototype 的粗略结构
			// F2_prototype = {
			// 	constructor: F2,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			var s = new F1();

			// 根据实例化原理可知 s.__proto__ === F1.prototype
			console.log(s.__proto__ === F1.prototype) // true
			// 所以得以下结果
			console.log(s instanceof F1) // true

			// 根据 F2_prototype 显示的结构, s 整个原型链都没有 F2.prototype
			// 所以得以下结果
			console.log(s instanceof F2) // false

		}

		function section2() {
			function F1() { }

			// F1.prototype 的粗略结构
			// F1_prototype = {
			// 	constructor: F1,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			var s = new F1();
			// s 的粗略结构
			// _s = {
			// 	__proto__: {
			// 		constructor: F1,
			// 		__proto__: {
			// 			constructor: Object
			// 		}
			// 	}
			// }

			// *提示: {} 相当于新建一个对象, 与其它对象都不相等, 类似于 {} !== {}
			F1.prototype = {};

			// F1.prototype 的粗略结构
			// F1_prototype = {
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			var s2 = new F1();

			// s2 的粗略结构
			// _s2 = {
			// 	__proto__: {
			// 		__proto__: {
			// 			constructor: Object
			// 		}
			// 	}
			// }

			// F1.prototype 重写后, F1.prototype 是一个新的对象, 不存在于 s 的原型链上
			// 所以得以下结果
			console.log(s instanceof F1) // false

			// 根据 F1_prototype, _s2 显示的结构
			console.log(s2.__proto__ === F1.prototype) // false
			// 所以得以下结果
			console.log(s2 instanceof F1) // true

		}

		function section3() {
			function F1() { }

			function F2() { }

			// F2.prototype 的粗略结构
			// F2_prototype = {
			// 	constructor: F2,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			var s = new F2();

			// 根据实例化原理可知 s.__proto__ === F2.prototype
			console.log(s.__proto__ === F2.prototype) // true
			// 所以得以下结果
			console.log(s instanceof F2) // true

			// 根据 F2_prototype 显示的结构, s 整个原型链都没有 F1.prototype
			// 所以得以下结果
			console.log(s instanceof F1) // false

		}

		function section4() {
			function F1() { }

			function F2() { }

			F2.prototype = new F1(); // 继承

			// F1.prototype 的粗略结构
			// F1_prototype = {
			// 	constructor: F1,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			// F2.prototype 的粗略结构
			// *提示: F2.prototype.__proto__ === F1.prototype
			// F2_prototype = {
			// 	constructor: undefined,
			// 	__proto__: {
			// 		constructor: F1,
			// 		__proto__: {
			// 			constructor: Object
			// 		}
			// 	}
			// }

			var s = new F2();

			// 根据实例化原理可知 s.__proto__ === F2.prototype
			console.log(s.__proto__ === F2.prototype) // true
			// 所以得以下结果
			console.log(s instanceof F2) // true

			// 根据 F2_prototype 显示的结构, 推理可得
			console.log(s.__proto__.__proto__ === F1.prototype)
			// 所以得以下结果
			console.log(s instanceof F1) // true

		}

		function section5() {
			function F1() { }

			function F2() { }

			F2.prototype = F1.prototype; // 继承

			// F1.prototype 的粗略结构
			// F1_prototype = {
			// 	constructor: F1,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			// F2.prototype 的粗略结构
			// F2_prototype = {
			// 	constructor: F1,
			// 	__proto__: {
			// 		constructor: Object
			// 	}
			// }

			var s = new F2();

			// 根据实例化原理可知 s.__proto__ === F2.prototype
			console.log(s.__proto__ === F2.prototype) // true
			// 所以得以下结果
			console.log(s instanceof F2) // true

			// 因为 F2.prototype 重写后就是 F1.prototype
			console.log(s.__proto__ === F1.prototype)
			// 所以得以下结果
			console.log(s instanceof F1) // true

		}

		section1()
		section2()
		section3()
		section4()
		section5()
	</script>
</body>

</html>

因为 instanceof 是通过构造函数的原型(prototype) 计算结果的, 所以当 prototype 被修改后, instanceof 的结果也将受到影响

//end