慕課網《前端JavaScript面試技巧》學習筆記(2)-原型和原型鏈

weixin_33912445發表於2017-07-12

1.如何準確判斷一個變數是陣列型別
2.寫一個原型鏈繼承的例子
3.描述new一個物件的過程

知識點#####
  • 建構函式
function Foo(name,age){
    this.name=name
    this.age=age
    this.class='class-1'
  //return this  //預設有這一行
}
var f=new Foo('zhangsan',20)
//var f1=new Foo('lisi',22) //建立多個物件
  • 建構函式-擴充套件
var a={} //其實是var a=new Object()的語法糖
var b=[] //其實是var b=new Array()的語法糖
function Foo(){...} //其實是var Foo=new Function(...)
//使用instanceof判斷一個函式是否是一個變數的建構函式

所有的引用型別(物件、陣列、函式)都有建構函式,a的建構函式是Object(),b的建構函式是Array(),Foo的建構函式是Function()。所以假如想要判斷一個變數是否為陣列就可以使用

var a={}
a instanceof Array   //false
  • 原型規則和例項
    • 所有的引用型別都具有物件特性,即可自由擴充套件屬性(null除外)

    • 所有引用型別都有一個__proto__ //隱式原型屬性,屬性值是一個普通的物件

    • 所有函式都有一個prototype //顯示原型屬性,屬性值也是一個普通的物件

    • 所有引用型別的__proto__屬性值指向它的建構函式prototype的屬性值

    • 當試圖得到一個引用型別的某個屬性時,如果這個物件本身沒有這個屬性,那麼會去它的__proto__(即它建構函式的prototype)中尋找

      var obj={};obj.a=100;
      var arr=[];arr.a=100;
      function fn(){}
      fn.a=100
      
      console.log(obj.__proto__)
      console.log(arr.__proto__)
      console.log(fn.__proto__)
      
      console.log(fn.prototype)
      
      console.log(obj.__proto__===Object.prototype)     //true
      
//建構函式
function Foo(name,age){
    this.name=name
}
Foo.prototype.alertName=function(){    //由於prototype是一個普通物件,所以也可以擴充套件屬性
    alert(this.name)   
}    
//建立例項
var f=new Foo('zhangsan')
f.printName=function(){
console.log(this.name)
}
//測試
f.printName()    //zhangsan
f.alertName()    //f沒有alertName屬性,於是去f._proto_即Foo.prototype中查詢

由物件呼叫原型中的方法,this指向物件

//迴圈物件自身的屬性
var item
for(item in f){
    //高階瀏覽器已在for in中遮蔽了來自原型的屬性
    //但是這裡建議還是加上這個判斷以保證程式的健壯性
    if(f.hasOwnProperty(item)){
        console.log(item)
    }
}
  • 原型鏈
//在剛剛的程式碼中加入
f.toString()    //要去f.__proto__.__proto__中查詢

所有的引用型別都有__proto__屬性,且__proto__屬性值指向它的建構函式prototype的屬性值,所以當f不存在toString時,便會在f.__proto__Foo.prototype中查詢,而Foo.prototype中也沒有找到toString。由於Foo.prototype也是一個物件,所以它隱式原型__proto__的屬性值便指向它的建構函式Object的prototype的屬性值。

//試一試
console.log(Object.prototype) 
console.log(Object.prototype.__proto__)    //為了避免死迴圈,所以此處輸出null
5458108-b673cd3e0356c1f7.png
原型鏈
  • instanceof
    用於判斷引用型別屬於哪個建構函式的方法
    f instanceof Foo的判斷邏輯是f__proto__一層層向上能否對應到Foo.prototype,再試著判斷f instanceof Object
解題#####

1.如何準確判斷一個變數是陣列型別
使用instanceof

var arr=[]
arr instanceof Array    //true
typeof arr    //object    typeof無法準確判斷是否是陣列

2.寫一個原型鏈繼承的例子

//簡單示例,比較low,下面有更貼近實戰的例子
//動物
function Animal(){
    this.eat=function(){
        console.log('Animal eat')
    }
}
//狗
function Dog(){
    this.bark=function(){
        console.log('Dog bark')
    }
}
Dog.prototype=new Animal()
//哈士奇
var hashiqi=new Dog()
//封裝一個DOM查詢
function Elem(id){
    this.elem=document.getElementById(id)
}
Elem.prototype.html=function(val){
    var elem=this.elem
    if(val){
        elem.innerHTML=val
        return this    //鏈式操作
    }else{
        return elem.innerHTML
    }
}

Elem.prototype.on=function(type,fn){
  var elem=this.elem
  elem.addEventListener(type,fn)
  return this   //鏈式操作
}

var div1=new Elem('div1')
// console.log(div1.html());
// div1.html('<p>Hello</p>');
// div1.on('click',function(){
//   alert('clicked')
// });
div1.on('click',function(){alert('clicked')}).html('<p>鏈式操作</p>')
//在之前的函式中增加了return this,由div1呼叫時便會返回當前物件,即div1,便可以實現鏈式操作

3.描述new一個物件的過程

function Foo(name,age){
 // this={}
    this.name=name
    this.age=age
    this.class='class-1'
  //return this
}
var f=new Foo('zhangsan',20)
//var f1=new Foo('lisi',22) //建立多個物件

建立一個新物件
this指向這個新物件 this={}
執行程式碼,即對this賦值 this.xxx=xxx
返回this return this

相關文章