JavaScript的原型與原型鏈

原型與原型鏈

什麼是原型?

在聲明定義函數時,函數都會有一個 prototype屬性,這個屬性就是一個指針,指向一個對象,而這個對象就是原型對象(簡稱原型)

原型的做用?

經過構造函數建立的實例對象,能夠直接訪問到構造函數的 prototype屬性上(即原型對象)的屬性和方法

什麼是原型鏈?

對象有 __proto__屬性, 屬性值指向了當前的原型對象, 原型對象也是對象, 原型對象也有 __proto__屬性,原型對象的 __proto__屬性值指向了原型對象的原型對象, 這樣一環套一環,造成的鏈式結構叫作原型鏈

原型鏈圖解

image

原型鏈特色:面試

  • 實例對象的隱式原型(__proto__)等於構造函數的顯示原型(prototype
 f1.__proto__ === Foo.prototype //true
  • 全部的函數都是Function的實例,即函數都是經過new Function產生的
 Foo.__proto__ === Function.prototype //true  
 Date.__proto__ === Function.prototype //true  
 Object.__proto__ === Function.prototype //true
  • Function也是new本身產生的,即Function的隱式原型等於本身的顯示原型
 Function.__proto__ === Function.prototype //true
  • 原型對象也是對象,因此原型對象也是new Object產生的,即原型對象的隱式原型指向Object的顯示原型
 Foo.prototype.__proto__ === Objecct.prototype //true  
 Function.prototype.__proto__ === Objecct.prototype //true
  • Object的原型,是原型鏈的盡頭
 Object.prototype.__proto__ === null //true
  • 原型對象自帶constructor,該屬性指向當前的構造函數
 Foo.prototype.constructor === Foo  //true  
 Object.prototype.constructor === Object  //true  
 Function.prototype.constructor === Function  //true

注意點:函數

  • 實例對象上只有__proto__屬性
  • 函數上有prototype屬性和__proto__屬性
  • 原型對象上有constructor屬性和__proto__屬性

屬性查找原則

  1. 首先在對象自身上來查找是否有該屬性, 若是有, 就返回屬性值.
  2. 若是沒有, 就去對象的原型對象上來查找, 若是有, 就返回屬性值.
  3. 若是也沒有, 就沿着對象的原型鏈繼續往上找, 直到Object.prototype, 若是有, 就返回屬性值.
  4. 若是尚未, 返回undefined

    簡化記憶: 沿着對象的原型鏈往上找this

注意點: 關鍵看對象上是否有該屬性, 而不在意其值是啥spa

屬性設置原則

  1. 若是對象自身有該屬性, 設置的話就是在修改操做, 只會影響到對象自身, 不會影響到原型和原型鏈上的屬性.
  2. 若是對象自身沒有該屬性, 設置的話就是在給對象添加該屬性, 只會影響到對象自身, 不會影響到原型和原型鏈上的屬性.

簡單記憶: 有就修改, 沒有就添加prototype

面試題:

 

function Person(name, age){  
  // ****有形參, 無實參, 形參是undefined*****  
  this.name = name;  
  this.age = age;  
 }  
 ​  
 Person.prototype.name = "lw";  
 Object.prototype.gender = "male";  
 ​  
 // 變化的點  
 var p = new Person();  
 ​  
 console.log(p);  
 ​  
 // p實例對象的原型鏈  
 //  p ==> Person.prototype ==> Object.prototype ==> null;  
 ​  
 console.log(p.name); // undefined ****  
 console.log(p.age); // undefined  ****  
 console.log(p.gender); // male  
 console.log(p.sex); // undefined
 function Person(name) {  
  // name ==> undefined  
  if (name) {  
  this.name = name;  
  }  
 }  
 ​  
 Person.prototype.name = "ls";  
 Person.prototype.money = 100;  
 ​  
 var p = new Person();  
 ​  
 console.log(p);  
 ​  
 // p實例對象自身沒有name屬性  
 ​  
 console.log(p.name); // ls      undefined   
 console.log(p.money); // 100    100
 function A() {  
 ​  
 }  
 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
 function F() {}  
 Object.prototype.a = function () {  
  console.log('a()')  
 }  
 Function.prototype.b = function () {  
  console.log('b()')  
 }  
 ​  
 var f = new F();  
 f.a() //a()  
 f.b() //報錯   
 F.a() //a()  
 F.b() //b()

補充

  • instanceof判斷複雜數據的具體類型的原理是什麼?
A intanceof B

若是B的顯示原型屬性指向的對象在A的原型鏈上,則返回true,不然返回false指針

  • instanceof的底層原理,手動實現一個instanceof
 /*   
  封裝一個instanceof的具體實現  
  參數:  
  A: 實例對象  
  B: 構造函數  
  返回值:true或者false  
  */  
 function myInstanceof(A, B) {  
  // 判斷A的數據類型,若是A是簡單數據類型或者null,則直接返回false  
  var styleA = typeof A  
  if((styleA !== 'function' && styleA !== 'object') || styleA === null) {  
  return false  
  }  
  // 判斷B構造函數的顯示原型是否在A實例對象的隱式原型上  
  var protoA = A.__proto__  
  while(protoA !== null) {  
  if(protoA === B.prototype) {  
  return true  
  }  
  protoA = protoA.__proto__  
  }  
  return false  
 }
相關文章
相關標籤/搜索