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顯示原型