匿名函數以及閉包內部this指向(函數調用模式的問題)

網上看到一句話,匿名函數的執行是具有全局性的,那怎麼具有的全局性呢?閉包內部this的指向是window,爲什麼指向了window呢?下面通過js函數調用模式和部分案例分析了爲什麼確實如此

1.js函數調用的模式

1.方法調用模式和函數調用模式

  • 如果一個函數被設置爲一個對象的屬性,則稱它爲一個方法。當通過對象對其進行調用時,即this的方法調用模式。在方法調用模式下,函數中的this指向該函數所屬的對象。
  • 當一個函數並非對象的屬性,而是直接作爲函數進行調用時,爲函數調用模式。此模式來調用函數的時候,this綁定的是全局對象。這是語言設計的一個錯誤。倘若語言設計正確,那麼當內部函數被調用時,this應該仍然綁定到外部函數的this變量。這個設計錯誤的後果就是方法不能利用內部函數來幫助它工作,因爲內部函數的this被綁定了錯誤的值,所以不能共享該方法對對象的訪問權
var obj = {
    val : 1,
    show : function(){alert(this.val);},//方法調用模式
    outFunc : function(){
        function innerFunc(){
            console.log(this);
        }
        innerFunc(); //函數調用模式
    }
};
obj.innerFunc();
//在嚴格模式下,console.log(this)中的this爲undefined,
//否則,console.log(this)中的this爲全局對象(瀏覽器中爲window)
//下文講解爲什麼

2.構造器調用模式

當以new來調用一個函數時,即構造器模式。
當使用new調用時,發生這些事情:
創建一個連接到該函數prototype的新對象
將this綁定到創建的新對象上
函數結束時,如果沒有返回其它對象,就返回this,即新創建的對象。

 var quo=function(string){
            this.status=string;
        }
    quo.prototype.get_status=function(){
            return this.status;
        }
    var qq=new quo("aaa");
    alert(qq.get_status());

3.上下文調用模式(call,apply)

var myobject={};
var sum = function(a,b){
  return a+b;
};
var sum2 = sum.call(myobject,10,30); //var sum2 = sum.apply(myobject,[10,30]); 
alert(sum2);

2.閉包和匿名函數案例分析(這兩種都是函數調用模式)

    var person = {
        name :'one',
        sayOne:function () {//方法調用模式
            console.log(this.name)
        },
        sayTwo:function () {//函數調用模式
            return function () {
                console.log(this.name)
            }
        },
        wrap: function(){//函數調用模式,匿名函數的執行環境具有全局性的由來
            (function (){
                console.log(this.name)
            })()
        }
    }
    person.sayOne()//one   sayOne調用者是person對象,所以this指向person;(方法調用模式)
    person.sayTwo()()//window 返回的匿名函數在全局執行所以是window(函數調用模式)
    person.wrap()//window 語言就是這樣設計的,也是匿名函數具有全局性的由來(函數調用模式)

3.事件監聽內部調用方法案例分析

    var div=document.getElementById("one");
    function f2(){
    console.log(this)
    }
    div.onclick =function () {
        console.log(this)//one那個節點
        f2()//window(函數調用模式)
    }

4.綜合應用:函數節流案例分析

1.throttle函數的執行環境具有全局性,內部this通常是指向window的,然後返回一個匿名函數。
2.返回的匿名函數綁定了事件,this指向監聽的元素(document)
3.fn其實與上面返回匿名函數形成了閉包,且fn也其實是一個匿名函數,匿名函數的執行具有全局性,fn內部this應該指向window
4這裏用apply修正this指向,使fn內部的this重新指向document

            function throttle(fn, delay) {
                console.log(this)//window
                // 記錄上一次函數觸發的時間
                var lastTime = 0;
                return function() {
                    // 記錄當前函數觸發的時間
                    var nowTime = Date.now();
                    if(nowTime - lastTime > delay) {
                     /*
                          fn();
                        console.log(this)//document
                    */
                        
                        fn.apply(this)// 修正this指向問題
                        console.log(this)//document
                        
                        // 同步時間
                        lastTime = nowTime;
                    }
                }
            }
            document.onscroll = throttle(function() {
                /*console.log(this)//window*/
                console.log(this)//document
                console.log('scroll事件被觸發了' + Date.now())
            }, 1000)

5.參考JS高級編程的案例解決問題

var name = "global";

var foo = {
    name: "foo",
    getName : function(){
        console.log(this.name);
    }
}

var bar = {
    name: "bar",
    getName : function(){
        return (function(){
            console.log(this.name);
        })();
    }
}

foo.getName(); //foo
foo.getName.call(bar); //bar
foo.getName.call(this); //global
foo.getName.call(window); //global

(function(){

    console.log(this.name)

}.bind(bar))(); //bar

(function(){

    console.log(this.name)

}.bind())(); //global
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章