JS 原型中的this理解

前面講過(guò)了,在全局作用域下聲明的函數(shù)或者變量,默認(rèn)是window這個(gè)對(duì)象的屬性了,前面再議函數(shù)時(shí),說(shuō)過(guò),上下文這個(gè)概念跟作用域的概念的區(qū)別,上下文是一個(gè)目標(biāo)變量被當(dāng)成某個(gè)對(duì)象的屬性或者方法時(shí),這里的對(duì)象是目標(biāo)的上下文,我是這么理解的。而this在代碼層面上就是時(shí)刻指向這個(gè)對(duì)象了。

內(nèi)部函數(shù)


這里的this怎么會(huì)這樣呢?可以這樣理解,要執(zhí)行的是f0,所以f0是目標(biāo)函數(shù),這時(shí)候里面可以是這樣的:

function f0(){
 // var this = window   這里隱含著一個(gè)這樣的聲明了。
  function f2(){
    console.log(this)
  }
  f2()
} 
f0()

setTimeout setInterval


document.addEventListener('click',function(e){
  console.log(this)
  setTimeout(function(){
    console.log(this)
  },200)
},false)

運(yùn)行如圖:



之前做項(xiàng)目封裝的時(shí)候,在這個(gè)定時(shí)器上栽過(guò)很多跟頭的,因?yàn)檫@個(gè)定時(shí)器是個(gè)獨(dú)立的函數(shù),不是跟內(nèi)嵌的一樣,因?yàn)樗\(yùn)行是異步運(yùn)行在任務(wù)列表里的,我認(rèn)為在任務(wù)隊(duì)列里的時(shí)候它是全局作用域的變量,否則取消定時(shí)器不就只能放在它所在作用域里取消它了嗎?那如何實(shí)時(shí)取消操作它呢?當(dāng)然這里不能再說(shuō)作用域了,比如這個(gè)是相對(duì)于變量的存在意義的范疇,而不是作為變量所屬的對(duì)象研究的上下文。
這里老師給了一個(gè)一般性結(jié)論:
如果碰到了回調(diào)函數(shù),那this基本都變了,否則也不會(huì)用回調(diào)函數(shù)了。

構(gòu)造函數(shù)

上次寫原型的時(shí)候,寫new的作用,第一步就是創(chuàng)建一個(gè)空對(duì)象,空對(duì)象的proto等于原函數(shù)的prototype,第二部就是運(yùn)行這個(gè)函數(shù),運(yùn)行時(shí),函數(shù)里的this指向這個(gè)空對(duì)象,最后把加工了的空對(duì)象返回。

作為對(duì)象方法調(diào)用

var obj = {
  name:'haha',
  printname : function(){
  console.log(this.name)
}
}
obj.printname()  //'haha'

對(duì)象的方法調(diào)用,這個(gè)方法的對(duì)象就是這個(gè)對(duì)象了,this直接指向它嘍。
陷阱:



fn是在全局聲明的,就是window的屬性了,只不過(guò)這個(gè)賦值的范疇讓你迷惑,就是聲明加賦值嘛。

DOM綁定事件

除了低版本的bug指向window,事件處理中的this代表事件源DOM對(duì)象。

document.addEventListener('click',function(e){
  console.log(this)
  var self = this              //經(jīng)常用到的技巧,拿不準(zhǔn)了,提前把this的指針賦值給一個(gè)變量,
//因?yàn)槟J(rèn)this這四個(gè)字母代表了當(dāng)下目標(biāo)變量的上下文,鐵打的this,流水的變量。
  setTimeout(function(){
    console.log(this)
    console.log(self)
  },200)
},false)

Function.prototype.bind

bind返回一個(gè)新函數(shù),并使函數(shù)內(nèi)部的this為傳入的第一個(gè)參數(shù)。
bind執(zhí)行時(shí),也就是返回的函數(shù)執(zhí)行時(shí),那個(gè)對(duì)象作為參數(shù)傳了進(jìn)來(lái)。換句話說(shuō),我們?yōu)檫@個(gè)函數(shù)設(shè)置了新對(duì)象。
所有的函數(shù)都是Function創(chuàng)造的,在Function.prototype.bind上加一個(gè)函數(shù),所有的函數(shù)都有bind這個(gè)方法了。



它的作用有利于復(fù)用函數(shù),而且是在指定的上下文里去運(yùn)行。注意最后面的括號(hào)不要忘了,因?yàn)榉祷氐氖呛瘮?shù),要執(zhí)行就要加。



再看看這樣呢:

this.say是對(duì)的,this就是指的page,這時(shí)候,相當(dāng)于事件被解讀狀態(tài)。但是觸發(fā)事件運(yùn)行事件的回調(diào)say函數(shù)時(shí),里面的this就變了,代表了當(dāng)前的事件事件節(jié)點(diǎn)。
驗(yàn)證一下;

var page = {
  init:function(){
    this.node = document.body
    this.bind()
  },
  bind:function(){
    this.node.addEventListener('click',this.say)
  },
  say:function(){
    console.log(this)
    console.log('haha')
  }
}

page.init()

結(jié)果;

那怎么辦呢?


var page = {
  init:function(){
    this.node = document.body
    this.bind()
  },
  bind:function(){
    this.node.addEventListener('click',this.say.bind(this))
  },
  say:function(){
    console.log(this)
    console.log('haha')
  }
}

page.init()

那就對(duì)于上面那個(gè)DOM事件用bind處理一下吧:

document.addEventListener('click',function(e){
  console.log(this)
             
  setTimeout((function(){
    console.log(this)
  }).bind(this),200)
},false)

call ,apply設(shè)置this

fn.call(context,x,y,a,b,,,,)
fn.apply(contet,array)
//第一個(gè)參數(shù)是設(shè)置this的對(duì)象,剩下的是參數(shù),一個(gè)是枚舉形式,一個(gè)是數(shù)組形式。
function sum(){
  var result = 0
  var arg = Array.prototype.slice.call(arguments,0)
  var agu = Array.prototype.sort.call(arguments)
  var max = Math.max.apply(null,arg)       //之前講過(guò)參數(shù)的傳遞,傳少了會(huì)默認(rèn)從第一個(gè)參數(shù)開始匹配,
//第一個(gè)是this的指向,必須要設(shè),就設(shè)null,否則報(bào)錯(cuò)的
  Array.prototype.forEach.call(arguments,function(val){
    result += val
  })
  console.log(result,arg,agu,max)
  return result
  
}
sum(1,4,7,2)

就是簡(jiǎn)化我們的代碼,一般call的處理速度更快。

caller

在函數(shù)A調(diào)用函數(shù)B時(shí),被調(diào)用的B會(huì)自動(dòng)生成一個(gè)caller屬性,指向調(diào)用它的函數(shù)對(duì)象,如果沒(méi)有被調(diào)用,或者并非被其他函數(shù)調(diào)用,caller= null。

function fn1(){
  console.log(fn1.caller)
  function fn2(){
    console.log(fn2.caller)
  }
  fn2()
}
fn1()

arguments

函數(shù)在調(diào)用時(shí),傳入的參數(shù)被加工生產(chǎn)出的一個(gè)類數(shù)組對(duì)象.


callee

當(dāng)函數(shù)被調(diào)用時(shí),它的arguments.callee對(duì)象會(huì)指向這個(gè)函數(shù)自身。對(duì)自己的引用,比如遞歸。
匿名函數(shù)特好用。



var i =1
window.onclick = function(){
  console.log(i)
  if(i<20){
    i++
    setTimeout(arguments.callee,3000)
  }
} //可以試試這個(gè)函數(shù),相當(dāng)于自己設(shè)定條件,只要滿足了什么,
//它就可以無(wú)限調(diào)用自身的??梢宰霰O(jiān)察檢測(cè)之類,判斷狀態(tài),,,
//但是嚴(yán)格模式下用不了了,平時(shí)玩玩就可以了。

函數(shù)變量

  • 實(shí)例變量:this,類的實(shí)例才能訪問(wèn)到的
  • 靜態(tài)變量:屬性,直接類型對(duì)象能訪問(wèn)到的
  • 私有變量:局部變量,當(dāng)前作用域內(nèi)有效變量
function A(){
  var a =1      //局部變量
  this.b = 2    //實(shí)例變量,必須要?jiǎng)?chuàng)造實(shí)例
}
A.c = 3  //屬性對(duì)象
console.log(a)     //error
console.log(A.b,A.c)   //undefined ,3
var d = new A()
console.log(a)    //error
console.log(d.b,d.c)  //2,undefined

this練習(xí)

函數(shù)調(diào)用的步驟認(rèn)識(shí)

fn.call(context,x,y,,,,)  //任何函數(shù)調(diào)用都這樣的,只不過(guò)大多數(shù)指向自身的設(shè)置為null。
fn(x,y)  === fn.call(undefined,x,y)
obj.child.mesold(x,y) ===obj.child.mesold.call(obj.child,x,y)
function fn(){
 console.log(this)
}
fn()  === fn.call(undefined)    
//如果傳的是null,undefined,那么window默認(rèn)是context,嚴(yán)格模式下寫什么就是什么,沒(méi)window的事兒。
var obj = {
  foo:function(){
    console.log(this)
  }
}
var bar  = obj.foo
obj.foo() === obj.foo.call(obj)  //foo前面是obj,那就是obj
bar()   === bar.call(null)    //bar前面沒(méi)東西,那就是null
function fn(){
console.log(this)
}
var arr = [fn,fn2]
arr[0]()   ===arr.0.call(arr)

Event中的this

body.addEventListener('click',funcftion hand(){
  console.log(this)
})

this都是由call,apply指定的,要知道this指誰(shuí),就要看hand函數(shù)前綴是哪個(gè),但是事件是內(nèi)置的方法,看不了源碼,MDN上說(shuō),當(dāng)事件觸發(fā)時(shí),

hand.call(event.currentTarget,event)  //觸發(fā)事件的作為this

,,,,

$ul.on('click','li',function(){
  console.log(this)
})      //Jquary?

文檔中說(shuō)的意思:this指向當(dāng)前正在執(zhí)行的事件的元素。對(duì)直接事件就是綁定的元素。對(duì)代理事件,就是當(dāng)前觸發(fā)事件的元素。

最后:
不要瞎猜,不清楚就console.log(this).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容