前面講過(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).