JS中this的指向問題

前幾天在牛客網上作題,遇到一道關於this指向的問題,之前就對this只知其一;不知其二的我瞬間懵逼,下面咱們來看看這道題,順便講解一下js中this的指向問題。javascript

題目:填寫內容讓下面代碼支持a.name = 「name1」; b.name = 「name2」;java

function obj(name){
    _______
}
obj._____ = "name2";
var a = obj("name1");
var b = new obj;

在作這道題以前,咱們先來學習一下this的知識。首先咱們必需要明白的是,在javascript中this的指向是在函數被調用時才能肯定的,在定義時是不可以肯定的this指向的,準確一點說this最終指向的是調用它的對象。下面咱們舉例說明:segmentfault

1.做爲單獨的函數被調用

1    var name = "小黑";    // 全局變量name
2    function Func() {
3        var name = "大白";    // 局部變量name
    
4        console.log(this);
5        console.log(this.name);
6    }

8    Func();

9    console.log(window.Func() === Func())    //true

上面的代碼中,當咱們調用Func()函數時,實際上Func()是做爲window對象的方法被調用的(第9行代碼能夠能夠驗證),所以this指向的就是全局對象window,第4行代碼打印出來的也就是window,第5行代碼打印出來的天然也就是全局變量name(全部的全局變量都做爲window的屬性)。app

2.做爲對象的方法被調用

仍是先看下面的示例代碼:函數

1    var Obj = {
2       name: "大白",
3        getName: function() {
4            console.log(this.name)
5        }
6    }

7    Obj.getName();           // 大白
8    window.Obj.getName();    // 大白

這段代碼中getName()做爲對象Obj的方法被Obj調用,所以這個時候this指向的即是Obj對象,天然this.name獲得的就是"大白"。那麼在第8行代碼中window調用了getName()爲何不是指向window呢?由於window其實是經過調用Obj間接調用getName()的,因此this仍是指向直接調用它的Obj。學習

3.做爲構造函數被調用

function Func() {
    this.name = "大白";
}

var fn = new Func();
console.log(fn.name)    // 大白

當咱們經過new關鍵字構造一個實例對象的過程當中,構造函數中的this通常狀況下指向咱們構造出來的實例化對象(特殊狀況後面有單獨講解),所以在構造過程當中this.name = "大白"這句代碼就至關於給實例對象fn建立了一個name屬性並賦值"大白"。this

使用apply()/call()改變this的指向

1    function getName() {
2        console.log(this.name);
3    }

4    var Obj = {
5        name: "大白"
6    }

7    getName.apply(Obj);    // 大白
8    console.log(Obj);    //{ name: "大白" }

這裏用到了apply()方法改變this的指向(不知道apply()用法的自行百度),第7行代碼中咱們能夠理解成將getName()函數臨時綁定在Obj對象上做爲Obj對象的方法,同時調用這個方法。這個時候getName()中的this就指向臨時調用它的Obj對象了,天然this.name獲得的就是"大白"。注意這裏並無改變Obj對象,如第8行代碼所示。prototype

最後要解決前面留下的題,咱們還須要講個知識點:當構造函數中的this遇到return時的狀況。code

//示例1
function Fn1() {
    this.name = "大白";
    return { name: "小黑" };    // 返回一個空對象
}
var fn1 = new Fn1();
console.log(fn1.name);    // 小黑

//示例2
function Fn2() {
    this.name = "大白";
    return true;    // 返回true
}
var fn2 = new Fn2();
console.log(fn2.name);    // 大白

你可能會奇怪,如出一轍的代碼爲何獲得的值不同呢? 注意!這裏兩段代碼是區別的,示例1中函數返回值是一個對象,示例2中的返回值是true,當構造函數中返回值是一個對象時,this指向的就是返回的那個對象,若是返回值不是對象時,返回值指向的就是構造函數的示例對象,所以實例1中的this.name獲得的是小黑而不是大白。對象

如今咱們就能夠來作上面的題了:填寫內容讓下面代碼支持a.name = 「name1」; b.name = 「name2」;

//建立全局函數
1    function obj(name){
2         if(name) {        // 區分普通調用和實例化調用
            this.name = name;
          }
          return this;    // 返回this引用,調用時this指向window
3    }

4    obj.prototype.name = "name2";    // 設置原型對象
5    var a = obj("name1");    //直接調用函數,a等於window,name爲window的屬性。
6    var b = new obj;    //調用函數實例化對象,this指向obj的實例化對象。

上面第4行代碼涉及到對象原型的知識,若是對這方面還有疑問的能夠看看我總結的另外一篇文章:javaScript原型及原型鏈詳解(一)

以上內容都是我我的的理解,不免會有理解不到位的地方,但願各位不吝賜教!你們一塊兒進步。

相關文章
相關標籤/搜索