【JavaScript高階】5、函式高階(原型與原型鏈)
阿新 • • 發佈:2018-12-17
一、原型
1. 函式的prototype屬性(圖) * 每個函式都有一個prototype屬性, 它預設指向一個Object空物件(沒有我們指定的屬性和方法)(即稱為: 原型物件) * 原型物件中有一個屬性constructor, 它指向函式物件 2. 給原型物件新增屬性(一般都是方法) * 作用: 函式的所有例項物件自動擁有原型中的屬性(方法)<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>01_原型(prototype)</title> </head> <body> <script type="text/javascript"> //每個函式都有一個prototype屬性,它預設指向一個object空物件(即稱為:原型物件) console.log(Date.prototype,typeof Date.prototype) function Fun() { //alt + shift +r(重新命名rename) // webstorm整體重新命名替換 } console.log(Fun.prototype) // Object 'object' 預設指向一個Object空物件,沒有我們的屬性 // 原型物件中有一個屬性constructor, 它指向函式物件 console.log(Date.prototype.constructor === Date) // true console.log(Fun.prototype.constructor === Fun) // true //給原型物件新增屬性(一般是方法)===》例項物件可以訪問 Fun.prototype.test = function () { console.log("test()") } var fun = new Fun() fun.test() // test() </script> </body> </html>
二、顯式原型與隱式原型
1. 每個函式function都有一個prototype,即顯式原型(屬性)
2. 每個例項物件都有一個__proto__,可稱為隱式原型(屬性)
3. 物件的隱式原型的值為其對應建構函式的顯式原型的值
4. 記憶體結構(如下圖2-1)
5. 總結:
* 函式的prototype屬性: 在定義函式時自動新增的, 預設值是一個空Object物件
* 物件的__proto__屬性: 建立物件時自動新增的, 預設值為建構函式的prototype屬性值
* 程式設計師能直接操作顯式原型, 但不能直接操作隱式原型(ES6之前)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>02_顯式原型與隱式原型</title> </head> <body> <script type="text/javascript"> //定義建構函式 function Fn() { // 內部語句: this.prototype = {} } // 1. 每個函式function都有一個prototype,即顯式原型屬性, 預設指向一個空的Object物件 console.log(Fn.prototype) // 2. 每個例項物件都有一個__proto__,可稱為隱式原型 //建立例項物件 var fn = new Fn() // 內部語句: this.__proto__ = Fn.prototype console.log(fn.__proto__) // 3. 物件的隱式原型的值為其對應建構函式的顯式原型的值 console.log(Fn.prototype===fn.__proto__) // true //給原型新增方法 Fn.prototype.test = function () { console.log('test()') } //通過例項呼叫原型的方法 fn.test() // test() </script> </body> </html>
圖2-1
三、原型鏈
1. 原型鏈(圖解見下方3-1)
* 訪問一個物件的屬性時,
* 先在自身屬性中查詢,找到返回
* 如果沒有, 再沿著__proto__這條鏈向上查詢, 找到返回
* 如果最終沒找到, 返回undefined
* 別名: 隱式原型鏈
* 作用: 查詢物件的屬性(方法)
2. 建構函式/原型/實體物件的關係(圖解3-2)
3. 建構函式/原型/實體物件的關係2(圖解3-3)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_原型鏈</title>
</head>
<body>
<script type="text/javascript">
// console.log(Object)
//console.log(Object.prototype)
console.log(Object.prototype.__proto__) // null
function Fn() {
this.test1 = function () {
console.log('test1()')
}
}
console.log(Fn.prototype) // Object
Fn.prototype.test2 = function () {
console.log('test2()')
}
var fn = new Fn()
fn.test1() // 'test1()'
fn.test2() // 'test2()'
console.log(fn.toString()) // '[object Object]'
console.log(fn.test3) // undefined
// fn.test3() // 報錯
/*
1. 函式的顯示原型指向的物件預設是空Object例項物件(但Object不滿足)
*/
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
/*
2. 所有函式都是Function的例項(包含Function)(Function是它自身的例項)
*/
console.log(Function.__proto__===Function.prototype)
/*
3. Object的原型物件是原型鏈盡頭
*/
console.log(Object.prototype.__proto__) // null
</script>
</body>
</html>
圖3-1
圖3-2
圖3-3
四、原型鏈—屬性問題
1. 讀取物件的屬性值時: 會自動到原型鏈中查詢
2. 設定物件的屬性值時: 不會查詢原型鏈, 如果當前物件中沒有此屬性, 直接新增此屬性並設定其值
3. 方法一般定義在原型中, 屬性一般通過建構函式定義在物件本身上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_原型鏈_屬性問題</title>
</head>
<body>
<script type="text/javascript">
function Fn() {
}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a,fn1) // 'xxx' Fn 讀取物件的屬性值時: 會自動到原型鏈中查詢
var fn2 = new Fn()
fn2.a = 'yyy' // 設定物件的屬性值時: 不會查詢原型鏈, 如果當前物件中沒有此屬性, 直接新增此屬性並設定其值
console.log(fn2.a,fn2) // 'yyy' Fn
function Person(name,age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
var p1 = new Person('tom',12)
p1.setName('bob')
console.log(p1) // Person {name: "bob", age: 12}
var p2 = new Person('jack',13)
p2.setName('cat')
console.log(p2) // Person {name: "cat", age: 13}
console.log(p1.__proto__ === p2.__proto__) // true
</script>
</body>
</html>
五、探索instanceof
1. instanceof是如何判斷的? * 表示式: A instanceof B * 如果B函式的顯式原型物件在A物件的原型鏈上, 返回true, 否則返回false 2. Function是通過new自己產生的例項
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_探索instanceof</title>
</head>
<body>
<script type="text/javascript">
//以下兩個案例可由上面圖3-3分析
/*
案例1
*/
function Foo() {
}
var f1 = new Foo()
console.log(f1 instanceof Foo) // true
console.log(f1 instanceof Object) // true
/*
案例2
*/
console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true
function Foo() {
}
console.log(Object instanceof Foo) // false
</script>
</body>
</html>
六、面試題
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_面試題</title>
</head>
<body>
<script type="text/javascript">
/*
測試題1
*/
var A = function() {
}
A.prototype.n = 1
var b = new A()
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(b.n, b.m, c.n, c.m) // 1 undefined 2 3
/*
測試題2
*/
var F = function(){};
Object.prototype.a = function(){
console.log('a()')
};
Function.prototype.b = function(){
console.log('b()')
};
var f = new F();
f.a() // a()
f.b() // b()
//F.a() //報錯
F.b() // b()
</script>
</body>
</html>