1、说明
函数(Function)才有prototype属性,对象(除Object)拥有__proto__。
2、prototype与__proto__区别
示例:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>prototype与__proto__区别</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????var a = {}; ???????????console.log(a.prototype); //undefined ???????????console.log(a.__proto__); //Object {} ???????????var b = function() {} ???????????console.log(b.prototype); //b {} ???????????console.log(b.__proto__); //function() {} ???????</script> ???</body></html>
控制台输出:
(3)__proto__指向
示例:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>__proto__指向</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????/*1、字面量方式*/ ???????????var a = {}; ???????????console.log(a.__proto__); //Object {} ???????????console.log(a.__proto__ === a.constructor.prototype); //true ???????????/*2、构造器方式*/ ???????????var A = function() {}; ???????????var b = new A(); ???????????console.log(b.__proto__); //A {} ???????????console.log(b.__proto__ === b.constructor.prototype); //true ???????????/*3、Object.create()方式*/ ???????????var a1 = { ???????????????a: 1 ???????????} ???????????var a2 = Object.create(a1); ???????????console.log(a2.__proto__); //Object {a: 1} ???????????console.log(a2.__proto__ === a2.constructor.prototype); //false(此处即为图1中的例外情况) ???????</script> ???</body></html>
控制台输出:
(4)原型链
(1)是__proto__指向的一条指针链!
(2)查找属性时,首先先查找自身属性,找不到的话,在查找原型链上的属性。但是不会查找自身的prototype属性。
示例代码:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>属性查找</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????Function.prototype.age = 20; ???????????let b = function() {} ???????????b.prototype.age = 10; ???????????console.log(b.age)//输出20 ???????</script> ???</body></html>
示例:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>原型链</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????var A = function() {}; ???????????var a = new A(); ???????????console.log(a.__proto__); //A {}(即构造器function A 的原型对象) ???????????console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象) ???????????console.log(a.__proto__.__proto__.__proto__); //null ???????</script> ???</body></html>
(5)prototype
prototype
和length
是每一个函数类型自带的两个属性,而其它非函数类型并没有,这一点之所以比较容易被忽略或误解,是因为所有类型的构造函数本身也是函数,所以它们自带了prototype
属性:
示例:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>prototype</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????console.log(Object.prototype); //=> {} ????????????console.log(Function.prototype); //=> [Function: Empty] ????????????console.log(String.prototype); //=> [String: ‘‘] ???????</script> ???</body></html>
除了prototype
之外,Js中的所有对象(undefined
、null
等特殊情况除外)都有一个内置的[[Prototype]]
属性,指向它“父类”的prototype
,这个内置属性在ECMA标准中并没有给出明确的获取方式,但是许多Js的实现(如Node、大部分浏览器等)都提供了一个__proto__
属性来指代这一[[Prototype]]
,我们通过下面的例子来说明实例中的__proto__
是如何指向构造函数的prototype
的:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>prototype与__proto__</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????var Person = function() {}; ???????????Person.prototype.type = ‘Person‘; ???????????Person.prototype.maxAge = 100; ???????????var p = new Person(); ???????????p.name = ‘rainy‘; ???????????Person.prototype.constructor === Person; //=> true ????????????p.__proto__ === Person.prototype; //=> true ????????????console.log(p.prototype); //=> undefined ???????????console.log(p.maxAge); //100 ???????????console.log(p.__proto__.maxAge); //100 ???????????console.log(p.name); //rainy ???????????console.log(p.__proto__.name); //undefined ???????</script> ???</body></html>
图示:
Person
是一个函数类型的变量,因此自带了prototype
属性,prototype指向
中的Person.prototype对象。Person.prototype.constructor
又指向Person
本身;通过new
关键字生成的Person
类的实例p1
,通过__proto__
属性指向了Person
的原型。这里的__proto__
只是为了说明实例p1
在内部实现的时候与父类之间存在的关联(指向父类的原型),在实际操作过程中实例可以直接通过.
获取父类原型中的属性,从而实现了继承的功能。
(6)原型链
示例代码:
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>prototype与__proto__</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????var Obj = function() {}; ???????????var o = new Obj(); ???????????o.__proto__ === Obj.prototype; //=> true ????????????o.__proto__.constructor === Obj; //=> true ???????????Obj.__proto__ === Function.prototype; //=> true ????????????Obj.__proto__.constructor === Function; //=> true ???????????Function.__proto__ === Function.prototype; //=> true ????????????Object.__proto__ === Object.prototype; //=> false ????????????Object.__proto__ === Function.prototype; //=> true ???????????Function.__proto__.constructor === Function; //=> true ????????????Function.__proto__.__proto__; //=> {} ????????????Function.__proto__.__proto__ === o.__proto__.__proto__; //=> true ????????????o.__proto__.__proto__.__proto__ === null; //=> true ???????</script> ???</body></html>
(7)null与undefined
null与undefined 无原型
//报错 ???????????console.log(Object.getPrototypeOf(undefined)) ???????????//报错 ???????????console.log(Object.getPrototypeOf(null))
从上面的例子和图解可以看出,prototype
对象也有__proto__
属性,向上追溯一直到null
。
(8)原型链的遍历过程(一直到null)
<!DOCTYPE html><html lang="zh"> ???<head> ???????<meta charset="UTF-8" /> ???????<meta name="viewport" content="width=device-width, initial-scale=1.0" /> ???????<meta http-equiv="X-UA-Compatible" content="ie=edge" /> ???????<title>原型链的遍历过程</title> ???</head> ???<body> ???????<script src="https://cdn.bootcss.com/lodash.js/4.17.10/lodash.min.js"></script> ???????<script type="text/javascript"> ???????????let a = 1 ???????????console.log(a.__proto__ === Number.prototype) //true ???????????console.log(Number.__proto__ === Function.prototype) //true ???????????console.log(Function.__proto__ === Function.prototype) //true ???????????console.log(Function.__proto__.__proto__ === Object.prototype) //true ???????????console.log(Function.__proto__.__proto__.__proto__) ???????</script> ???</body></html>
(9)获取原型对象
Object.getPrototypeOf(object)
(10)原型上可遍历的属性
__proto__ 隐式原型 prototype显示原型
js 原型链 prototype __proto__
原文地址:https://www.cnblogs.com/mengfangui/p/9566114.html