Js面向?qū)ο缶幊?2):this&call/apply/bind

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對象
  1. 函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的this不是其父函數(shù),仍然是全局變量:
function fn0(){
    function fn(){
        console.log(this);
    }
    fn();
}
fn0();  //window對象
  1. 回調(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的指向。

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

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

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