this是JS語言的一個關(guān)鍵字。它代表函數(shù)運行時,自動生成的一個內(nèi)部對象,只能在函數(shù)內(nèi)部使用。例如:
function(){
this.x = 1;
}
隨著函數(shù)使用場合的不同,this的指向也會相應(yīng)發(fā)生變化,但是有一個總原則,this總是指向調(diào)用函數(shù)的那個對象。
下面分四種情況說說this的用法。
情況一:函數(shù)調(diào)用:
1.這是函數(shù)的最通常用法,屬于全局性調(diào)用,因此this就代表全局對象Global。
function fn1(){
console.log(this)
}
fn1() //window對象
- 函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的this不是其父函數(shù),仍然是全局變量:
function fn0(){
function fn(){
console.log(this);
}
fn();
}
fn0(); //window對象
- 回調(diào)函數(shù):
var a = 1
function f1(fn){
fn()
console.log(a)//1
}
function f2(){
var a = 2
}
f1(f2)
改寫代碼如下:
var a = 1
function f1(){
(function (){var a = 2})()
console.log(a)
}
f1() //1
4.定時器中的this:
《高程》上說:超時調(diào)用的代碼都是在全局作用域中執(zhí)行的。因此,setTimeout和setInterval的回調(diào)函數(shù)中的this指向window.
var name = 'Lee';
function fn(){
this.name = 'li';
this.sayName = function(){
console.log(this.name);
}
setTimeout(this.sayName,1000)
}
new fn() //Lee
上面代碼中,定時器中this.sayName的this指向創(chuàng)建的實例,而sayName里面的this指向全局作用域。
情況二:作為對象的方法調(diào)用:
var a = 1
var obj1 = {
a:2,
fn:function(){
console.log(this.a)
}
}
obj1.fn() //2
此時的this是指obj1這個對象,因為是obj1調(diào)用了函數(shù)fn。
- 但若是把函數(shù)賦值之后再調(diào)用:
var a = 1
var obj1 = {
a:2,
fn:function(){
console.log(this.a)
}
}
var fn1 = obj1.fn
fn1()//1
此時fn1就是不帶任何修飾的函數(shù)調(diào)用,因此它的this綁定的就是window,它也被稱為隱性綁定,相當(dāng)于obj1.fn.call(undefined)
情況三:在構(gòu)造函數(shù)中調(diào)用:
所謂構(gòu)造函數(shù),就是通過這個函數(shù)生成一個新對象(object)。這時,this就指這個新對象。
function Person(name,age){
// 這里的this都指向?qū)嵗? this.name = name
this.age = age
this.sayAge = function(){
console.log(this.age)
}
}
var li = new Person('Li',24)
li.sayAge() //24
情況四:call/apply/bind調(diào)用:
call、apply、bind方法的作用都是改變函數(shù)this的指向。
-
call和apply:
call和apply方法都接受兩個參數(shù),第一個參數(shù)都是this要指向的對象,而call的后面?zhèn)魅氲氖且粋€參數(shù)列表,apply的第二個參數(shù)為一個參數(shù)數(shù)組。他們的第一個參數(shù)為endefined或null時,this均指向window。
也就是說:
obj.method() = obj.method.call(obj);
fn() = fn.call(endefined);
f1(f2) = f1.call(undefined,f2);
例如:
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(obj) // 456
function f(x,y){
console.log(x+y);
}
f.call(null,1,1) // 2
f.apply(null,[1,1]) // 2
應(yīng)用場景:
- 求數(shù)組中的最大值和最小值:
var arr = [1,2,3,89,46]
var max = Math.max.apply(null,arr)//89
var min = Math.min.apply(null,arr)//1
- 將類數(shù)組轉(zhuǎn)化為數(shù)組
var trueArr = Array.prototype.slice.call(arrayLike)
- 不改變原數(shù)組的情況下數(shù)組追加
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var total = [].push.apply(arr1, arr2);//6
// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]
- 判斷變量類型
function isArray(obj){
return Object.prototype.toString.call(obj) == '[object Array]';
}
isArray([]) // true
isArray('abc') // false
- 利用call和apply做繼承
function Person(name,age){
// 這里的this都指向?qū)嵗? this.name = name
this.age = age
this.sayAge = function(){
console.log(this.age)
}
}
function Boy(){
Person.apply(this,arguments)//將父元素所有方法在這里執(zhí)行一遍就繼承了
}
var person = new Boy('li',24)
- 使用 log 代理 console.log
function log(){
console.log.apply(console, arguments);
}
// 當(dāng)然也有更方便的 var log = console.log()
2.bind:
和call很相似,第一個參數(shù)是this的指向,從第二個參數(shù)開始是接收的參數(shù)列表。區(qū)別在于bind方法返回值是改變了上下文的函數(shù)。
var obj = {
name: 'Li'
}
function printName() {
console.log(this.name)
}
var person = printName.bind(obj)
console.log(person) // function () { … }
person() // Li