2017-03-31 面向?qū)ο髮W(xué)習(xí)筆記

函數(shù)的調(diào)用方式和 this 丟失

  • 函數(shù)調(diào)用方式
  • 普通函數(shù)方式調(diào)用 this - window
  • 對象的方法 this - 對象
  • 構(gòu)造函數(shù)方式 this - 內(nèi)部創(chuàng)建的新對象
  • 函數(shù)上下文(call|apply) this - 第一個參數(shù)
  • this 的指向發(fā)生了改變
    函數(shù)的調(diào)用方式發(fā)生了改變
var name = 'window 的屬性';
function demo(){
        console.log(this.name);
}
var obj = {
        name:"張三",
        demo:demo
}
demo();
obj.demo();
var div = document.getElementById('demoId');
console.log(div);
//var div2 = getId('demoId');
//console.log(div2);
//document.getElemenetById 方法內(nèi)部的實現(xiàn)梳凛,在該方法內(nèi)部使用到了 this
//這個 this 默認指向的是document
//getId 在調(diào)用的時候使用普通函數(shù)的方式來進行調(diào)用驾凶, this 指向的是 window
document.getId = document.getElemenetById;
var div3 = document.getId('demoId');
console.log(div3);
//console.log(document.getElemenetById.call(document,''demoId));
//getId('demo');
var getId = (function(){
        return function(){
                  //return document.getElementById.call(document,arguments[0]);
                  return document.getElemenetById.apply(document,arguments);
        }
})();
var div4 = getId('demoId');
console.log(div4);

圖書管理員面向?qū)ο?/h2>
//注意點:在原型對象的方法中訪問該對象的其他方法剩晴,需要使用 this 前綴
function BookListManager(){
         this.bookList = null;
}
BookListManager.prototype = {
        constructor:BookListManager,
        init:function(){
                this.bookList = arr || [];
        },
        getBook:function(name){
                for(var i in this.bookList){
                          if(this.bookList[i].name == name){
                                return this.bookList[i];
                          }
                  }
                  throw "要查找的對象不存在资溃!"
        },
        updateBook:function(name,author){
                //先找到這個對象
                var book = this.getBook(name);
                //修改對象
                book.author = author;
        },
        addBook:function(obj){
                this.bookList.push(obj);
        },
        removeBook:function(){
                var book = this.getBook(name);
                var index = this.bookList.indexOf(book);
                if(index == -1){
                        throw '要刪除的對象不存在'
                }
                //刪除該對象
             this.bookList.splice(index,1);
        }
}
var jack = new BookListManager();
var tom = new BookListManager();
jack.init([{name:'古典文學(xué)研究',author:'古典'},{name:'莫言文集',author:'莫言'}]);
jack.addBook({name:'飛鳥集',author:'泰戈爾'});
console.log(jack.getBook('飛鳥集'));
jack.updateBook('飛鳥集','老太太');
jack.removeBook('飛鳥集');
console.log(jack.bookList);

嚴格模式的簡單說明

  • js 中有兩種開發(fā)模式,非嚴格模式(默認) + 嚴格模式 ('use strict')
  • 嚴格模式會進行更嚴格的代碼檢查
  • 以前可以的特性在嚴格模式下可能被禁止使用
  • 以前可以使用的代碼方式纲仍,在嚴格模式下會直接報錯
  • 開啟嚴格模式
  • 字符串命令 'use strict';
  • 位置 當前作用域的頂端
  • 兼容性問題:
    嚴格模式不存在兼容性問題浮创,如果當前的瀏覽器支持嚴格模式差导,那么再掃描到"use strict"命令的時候就會開啟嚴格模式檢查,如果不支持嚴格模式那么就直接忽略
  • 使用建議
    建議在寫代碼的時候全部開啟嚴格模式

嚴格模式使用注意

  • 在嚴格模式下帜消,所有的變量都必須使用 var 聲明
  • 在嚴格模式下棠枉,禁止使用八進制
  • 在嚴格模式下,禁止使用 with
  • 在嚴格模式下泡挺,不能刪除全局的變量
  • 在嚴格模式下辈讶,不能在 if 語句中聲明函數(shù)
  • 在嚴格模式下,函數(shù)的形參不能出現(xiàn)同名的情況
  • 在嚴格模式下娄猫,不能使用 callee|caller
  • 在嚴格模式下贱除,不能使用 eval 和 arguments 作為標識符(變量和函數(shù)名稱)
  • 在嚴格模式下,修正了 this 的指向
  • 在嚴格模式下媳溺,arguments 的表現(xiàn)不一致
  • 在嚴格模式下月幌,對象中不能出現(xiàn)同名的屬性
    "use strict";

    //01 在嚴格模式下,所有的變量都必須使用var聲明
    //   在默認情況下悬蔽,如果不適用var聲明變量扯躺,那么該變量默認會成為window的屬性(全局變量)
//    var a = 10;
//    b = 20;
//    console.log(b);

    //02 在嚴格模式下,禁止使用八進制
//    var num = 022;            //數(shù)值以0開頭,以八進制的方式來處理
//    var num = 0x22;
//    console.log(num);

    //03 在嚴格模式下录语,禁止使用使用with
//    var obj = {name:"張三",age:20};
//    with (obj)
//    {
//        name = "李四";
//        age = 99
//    }
//    console.log(obj);

    //04 在嚴格模式下, 不能刪除全局的變量
    //   在默認情況下倍啥,可以刪除全局變量(不能刪除成功),靜默失敗
//    var str = "string";
//    console.log(delete str);
//    console.log(str);

    //05 在嚴格模式下澎埠,不能在if語句中聲明函數(shù)
//    if (true)
//    {
//        function demo() {
//            console.log("demo");
//        }
//
//        demo();
//    }

    //06 在嚴格模式下虽缕,函數(shù)的形參不能出現(xiàn)同名的情況
//    function test(a,b,a) {
////        var a = 1;
////        var b = 2;
////        var a = 3;
//        console.log(a + b + a);   //6 ? 8 ? 4  后面的會把前面的覆蓋
//    }
//
//    test(1,2,3);

    //07 在嚴格模式下,不能使用arguments.callee|caller
    //caller 指向的函數(shù)的調(diào)用者 注意點:window調(diào)用該函數(shù)蒲稳,指向的是null
    //arguments.callee 常用在遞歸調(diào)用中彼宠,指向的是函數(shù)自己
//    function f1() {
//        f2();
//    }
//    function f2() {
//        console.log(f2.caller);
//    }
//    f1();
//    f2();

//    console.log((function (n) {
//    if (n == 1) {
//        return 1;
//    }
//
//    return arguments.callee(n - 1) + n;
//})(11));

    //08 在嚴格模式下, 不能使用eval和arguments作為標識符(變量和函數(shù)的名稱)
//    var eval = "測試字符串";
//    console.log(eval);
//    var arguments ="....";
//    console.log(arguments);

    //09 在嚴格模式下,修正了this的指向
    //   默認情況下弟塞,this指向的是window,嚴格模式指向的undefined
//    function func() {
//        console.log(this);
//    }
//
//    func();
//    var o = {};
//    func.call(null);            //嚴格模式下凭峡,指向的是null
//10 在嚴格模式下,arguments的表現(xiàn)不一致
    //在默認情況下决记,如果函數(shù)內(nèi)部形參被重新設(shè)置摧冀,那么arguments也會跟著改變
    //在嚴格模式情況下,如果函數(shù)內(nèi)部形參被重新設(shè)置系宫,那么arguments不會被改變索昂,他們是相互獨立的
    //值類型的數(shù)據(jù)作為函數(shù)的參數(shù)
    function demo(str) {
        console.log(str);
        console.log(arguments[0]);


        //重新設(shè)置形參的值
        str = "hahahaha";
        console.log(str);
        console.log(arguments[0]);
    }
    demo("123456");

    //引用類型的數(shù)據(jù)作為函數(shù)參數(shù)
    function demo(obj) {
        console.log(obj);
        console.log(arguments[0]);

        //重新設(shè)置形參的值
        obj = {age:20};
        console.log(obj);
        console.log(arguments[0]);
    }
    demo({name:"張三"});

嚴格模式的書寫格式

//"use strict";
//"use strict"               正確
//'use strict';     正確
//'use strict'      正確
//use strict;       錯誤
//"use Strict";     錯誤
//"use  strict";    錯誤
//"use strict ";    錯誤
//" use strict";      錯誤

嚴格模式的作用范圍

  • 位置:當前作用域的最上面
  • js 中的作用域:
  • script 標簽 全局作用域
  • 函數(shù)內(nèi)部 局部作用域
//    "use strict";    //位置01  對整個作用域中的代碼都有用

   function demo01() {
//       "use strict";    //位置02   僅僅對當前的函數(shù)有用,函數(shù)后面的代碼不受影響
       a = 10;
       console.log(a);
   }

   function demo02() {
//       "use strict";    //位置03  僅僅對當前的函數(shù)有用
       b = 20;
       console.log(b);
   }

   demo01();
   demo02();

作用域說明

  • 作用域
    概念:變量或者是函數(shù)起作用的范圍
  • js 的作用域
  • js 本身沒有塊級作用域(try-catch 除外)
  • js 中只有函數(shù)可以創(chuàng)建作用域
  • js 本身是此法作用域 (with|eval 除外)
  • 詞法作用域:
    當代碼寫好之后扩借,某個變量的作用域就已經(jīng)確定了
  • 動態(tài)作用域:
    變量的作用域在代碼運行之前是不確定的椒惨,只有在代碼執(zhí)行的時候才能根據(jù)當前的上下文來確定
  • 詞法作用域的訪問規(guī)則:
  • 單向性的(單向鏡),內(nèi)部的作用域可以訪問外層的作用域空間潮罪,反過來卻不行
  • 在訪問變量的時候康谆,先在當前作用于中查找,如果找不到那么就在上一級作用域中查找嫉到,重復(fù)這個過程
  • 在分析輸出的時候沃暗,需要考慮到變量和函數(shù)聲明的提升
  var a = "test-A";
    function f1() {
        var b = "test-B";

    }
    
    function f2() {
        var c = "test-C";
    }

  for (var i = 0; i < 10; i++) {
        console.log(i);
    }

    console.log(i,"_____");             //? 10

    try
    {
        //可能出錯的代碼
        a();
    }catch (error){
        //如果出錯了,那么就執(zhí)行此處的代碼
        console.log(error);
    }
//    console.log(error);
  var demo = "測試的字符串01";
    function f1() {
        var demo = "demo";
        var test = 10;
        f2();
    }

    function f2() {
        console.log(demo);
        console.log(test);
    }

//    f2();   //測試的字符串
    f1();   //demo

變量和函數(shù)的提升

  • js 代碼的執(zhí)行
    編譯語言
    解釋語言(js)
  • 預(yù)先解析階段
    變量和函數(shù)聲明的提升
  • 具體的執(zhí)行代碼
  • js 變量和函數(shù)聲明提升的注意點
  • 變量和變量同名 后面的變量會把前面的變量覆蓋
  • 函數(shù)和函數(shù)同名 覆蓋
  • 變量和函數(shù)同名 函數(shù)聲明會正常的提升何恶,而變量的聲明可以認為被忽略了
    只會提升到當前作用域的最頂端
  console.log("_____");
    console.log(a);            //und
    var a = "test-A";
    console.log(a);            //Test-A
    var a = "demo-A";
    console.log(a);            //demo-A

    //模擬變量聲明的提升
//    var a;
//    console.log("_____");
//    console.log(a);            //und
//    a = "test-A";
//    console.log(a);            //Test-A
//    a = "demo-A";
//    console.log(a);            //demo-A
</script>
<script>

    f1();                      //Demo
    function f1() {
        console.log("Test");
    }
    f1();                      //Demo
    function f1() {
        console.log("Demo");
    }
    f1();                       //Demo



    //模擬提升
//    function f1() {
//        console.log("Demo");
//    }
//    f1();                      //Demo
//    f1();                      //Demo
//    f1();
</script>

<!--<script>-->
    <!--console.log(a);                    //函數(shù)-->
    <!--var a = "test-A";-->
    <!--function a() {-->
        <!--console.log("demo-A");-->
    <!--}-->
    <!--console.log(a);                   //函數(shù)-->



    <!--//模擬-->
    <!--var a;-->
    <!--function a() {-->
        <!--console.log("demo-A");-->
    <!--}-->
    <!---->
    <!--console.log(a);                    //函數(shù)-->
    <!--a = "test-A";-->
    <!--console.log(a);                   //test-A-->
<!--</script>-->

<script>
    console.log(a);
    var a = "test-A";
    function a() {
        console.log("demo-A");
    }

//    不管函數(shù)在前面還是變量在前面孽锥,打印出來的結(jié)果都是函數(shù)
</script>

思考:
<script>
    var demoA ="10";
    function foo() {
        console.log(demoA);            //10  undefined(正確)
        var demoA = "20";
        console.log(demoA);            //20
    }

    function func() {
        console.log(demoA);            //10
        demoA = "30";
        console.log(demoA);           //30
    }

    foo();
    func();

    console.log(demoA);                 //30

變量提升是分作用域的

  • 在代碼執(zhí)行之前,會把所有的變量和函數(shù)生命進行提升
  • 在提升的時候细层,變量和函數(shù)聲明的提升是分作用域的惜辑,只能提升到當前作用域的頂端
  • 內(nèi)層作用域中的變量聲明并不會覆蓋外層作用域中的同名變量

    console.log(demo);
    var a = "第一個a";
    function demo() {
        console.log(a);   //? undefined
        a = "張三";
        console.log(a);   //張三
        var a = "哈哈哈";
        console.log(a);   //哈哈哈
    }

    console.log(a);
    demo();
    console.log(a);     //第一個a(正確) ? 張三  ?哈哈哈
</script>

<script>
    var b = 10;
    function test() {
        console.log(b);
        var b = 20;
    }

    console.log(b);    //10
    test();            //und
    console.log(b);
</script>

函數(shù)表達式的提升

  • 函數(shù)表達式提升疫赎,在提升的時候僅僅只會把聲明部分(var func02)提升到當前作用域的頂端
<script>
    console.log(func01);;
    function func01() {
        console.log("func01");
    }
</script>

<script>
//    var func02;
    console.log(func02);;
    var func02 = function () {
        console.log("func02");
    }
</script>

筆試題練習(xí)

<script>
    function foo() {
        var num = 123;
        console.log(num);  //123
    }
    foo();
    //console.log(num);       //報錯

</script>

<script>
    var scope = "global";
    foo();
    function foo() {
        console.log(scope);  //盛撑?global
        scope = "local";
        console.log(scope);  //?local
    }

    console.log(scope);         //local
</script>

in:檢查對象中是否存在指定的屬性
<!--<script>-->
    <!--function f1(){-->
        <!--var a;-->
        <!--if("a" in window){-->
            <!--a = 10;-->
        <!--}-->
        <!--console.log(a); //? 10 虚缎? undefined 讶隐?報錯-->
    <!--}-->

    <!--f1();-->

<!--</script>-->

<!--<script>-->
    <!--if("a" in window){-->
        <!--var a = 10;-->
    <!--}-->
    <!--console.log(a); //?  10 -->
<!--</script>-->

<!--<script>-->
    <!--if(!"a" in window){-->
        <!--var a = 10;-->
    <!--}-->
    <!--console.log(a); //?-->
<!--</script>-->



<script>
    if("a" in window){
      a = 10;
    }
    console.log(a); //?  報錯
</script>

<script>
    var foo = 1;
    function bar() {
        var foo;
        if(!foo)
        {
            foo = 10;
        }
        console.log(foo);   //?
    }
    bar();
//    undefined == null;  相等
//    undefined == false;  不相等
//    !undefined
    console.log(undefined === null);   //true
    console.log(!undefined == true);
</script>

  function Foo() {
        getName = function(){
            console.log("1");
        };
        return this;
    }
    Foo.getName = function() {
        console.log("2");};
    Foo.prototype.getName = function(){
        console.log("3");};
    var getName = function() {
        console.log("4");
    };
    function getName(){
        console.log("5");
    }
    Foo.getName();      // ? 2
    getName();          // ? 4
    Foo().getName();        // ? (1) ? 3 ? 2 ? 4
    getName();              // ? (1)
    new Foo.getName();      // ? 2
    new Foo().getName();    // ? 3
    new new Foo().getName(); // ? 3

作用域鏈

  • 有多少個作用域 (函數(shù)的個數(shù) + 1)
  • 相同作用域可以相互訪問
  • 作用域鏈:
    在 js 中函數(shù)可以創(chuàng)建作用域楷扬,在函數(shù)內(nèi)部又可以聲明函數(shù)嘿般,在函數(shù)的函數(shù)內(nèi)部又可以聲明函數(shù),每個函數(shù)都會創(chuàng)建一個作用域,這樣就會形成一個作用域鏈
  • 在訪問變量的時候,總是先在自己的作用域中查找
  • 如果沒有那么就向上一級作用域查找,如果找到那么就直接使用受葛,如果沒有找到那么就繼續(xù)重復(fù)這個過程
  • 直到最外層的全局作用域,如果還沒有找到那么就報錯
  var a = "a";
    //f1--->全局作用域
    function f1() {
        var b = "b";
        var a = "f1-a"
        //f2-->f1--->全局作用域
        function f2() {
            var c = "c";
            var b = "f2--b";
            //f3-->f2-->f1--->全局作用域
            function f3() {
                var d = "d";

                //f4-->f3-->f2-->f1--->全局作用域
                function f4() {
                    console.log(a, b, c, d,e);
                }

                f4();

            }
            f3();
        }
        f2();
    }

    f1();

作用域鏈繪圖

  • 首先先找出全局變量(包含函數(shù)) a f1 f2 f3

  • 畫出他們的圖形偎谁,并且連線(有箭頭)总滩,箭頭的方向表示的是是否可以訪問(同一級作用域可以互相訪問)

  • 以上畫出0級作用域鏈 var a = "test-a";
    function f1() {
    var b = "test-b";
    function f4() {

          function f5() {
              var c = "test-c";
              var d = "test-d"
          }
      }
    

    }

    function f2() {
    var e = "test-e";

// f4();
}

function f3() {
}
f2();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市巡雨,隨后出現(xiàn)的幾起案子闰渔,更是在濱河造成了極大的恐慌,老刑警劉巖铐望,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冈涧,死亡現(xiàn)場離奇詭異,居然都是意外死亡正蛙,警方通過查閱死者的電腦和手機督弓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乒验,“玉大人愚隧,你說我怎么就攤上這事《腿” “怎么了狂塘?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長虱痕。 經(jīng)常有香客問我睹耐,道長辐赞,這世上最難降的妖魔是什么部翘? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮响委,結(jié)果婚禮上新思,老公的妹妹穿的比我還像新娘。我一直安慰自己赘风,他們只是感情好夹囚,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邀窃,像睡著了一般荸哟。 火紅的嫁衣襯著肌膚如雪假哎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天鞍历,我揣著相機與錄音舵抹,去河邊找鬼。 笑死劣砍,一個胖子當著我的面吹牛惧蛹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刑枝,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼香嗓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了装畅?” 一聲冷哼從身側(cè)響起靠娱,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掠兄,沒想到半個月后饱岸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡徽千,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年苫费,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片双抽。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡百框,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牍汹,到底是詐尸還是另有隱情铐维,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布慎菲,位于F島的核電站嫁蛇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏露该。R本人自食惡果不足惜睬棚,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望解幼。 院中可真熱鬧抑党,春花似錦、人聲如沸撵摆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽特铝。三九已至暑中,卻和暖如春壹瘟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鳄逾。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工俐筋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人严衬。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓澄者,卻偏偏與公主長得像,于是被迫代替她去往敵國和親请琳。 傳聞我的和親對象是個殘疾皇子粱挡,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容