美文网首页
2017-03-31 面向对象学习笔记

2017-03-31 面向对象学习笔记

作者: GodlinE | 来源:发表于2017-03-31 19:34 被阅读0次

    函数的调用方式和 this 丢失

    • 函数调用方式
    • 普通函数方式调用 this - window
    • 对象的方法 this - 对象
    • 构造函数方式 this - 内部创建的新对象
    • 函数上下文(call|apply) this - 第一个参数
    • this 的指向发生了改变
      函数的调用方式发生了改变
    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 方法内部的实现,在该方法内部使用到了 this
    //这个 this 默认指向的是document
    //getId 在调用的时候使用普通函数的方式来进行调用, 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);
    

    图书管理员面向对象

    //注意点:在原型对象的方法中访问该对象的其他方法,需要使用 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:'古典文学研究',author:'古典'},{name:'莫言文集',author:'莫言'}]);
    jack.addBook({name:'飞鸟集',author:'泰戈尔'});
    console.log(jack.getBook('飞鸟集'));
    jack.updateBook('飞鸟集','老太太');
    jack.removeBook('飞鸟集');
    console.log(jack.bookList);
    

    严格模式的简单说明

    • js 中有两种开发模式,非严格模式(默认) + 严格模式 ('use strict')
    • 严格模式会进行更严格的代码检查
    • 以前可以的特性在严格模式下可能被禁止使用
    • 以前可以使用的代码方式,在严格模式下会直接报错
    • 开启严格模式
    • 字符串命令 'use strict';
    • 位置 当前作用域的顶端
    • 兼容性问题:
      严格模式不存在兼容性问题,如果当前的浏览器支持严格模式,那么再扫描到"use strict"命令的时候就会开启严格模式检查,如果不支持严格模式那么就直接忽略
    • 使用建议
      建议在写代码的时候全部开启严格模式

    严格模式使用注意

    • 在严格模式下,所有的变量都必须使用 var 声明
    • 在严格模式下,禁止使用八进制
    • 在严格模式下,禁止使用 with
    • 在严格模式下,不能删除全局的变量
    • 在严格模式下,不能在 if 语句中声明函数
    • 在严格模式下,函数的形参不能出现同名的情况
    • 在严格模式下,不能使用 callee|caller
    • 在严格模式下,不能使用 eval 和 arguments 作为标识符(变量和函数名称)
    • 在严格模式下,修正了 this 的指向
    • 在严格模式下,arguments 的表现不一致
    • 在严格模式下,对象中不能出现同名的属性
        "use strict";
    
        //01 在严格模式下,所有的变量都必须使用var声明
        //   在默认情况下,如果不适用var声明变量,那么该变量默认会成为window的属性(全局变量)
    //    var a = 10;
    //    b = 20;
    //    console.log(b);
    
        //02 在严格模式下,禁止使用八进制
    //    var num = 022;            //数值以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语句中声明函数
    //    if (true)
    //    {
    //        function demo() {
    //            console.log("demo");
    //        }
    //
    //        demo();
    //    }
    
        //06 在严格模式下,函数的形参不能出现同名的情况
    //    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 指向的函数的调用者 注意点:window调用该函数,指向的是null
        //arguments.callee 常用在递归调用中,指向的是函数自己
    //    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作为标识符(变量和函数的名称)
    //    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的表现不一致
        //在默认情况下,如果函数内部形参被重新设置,那么arguments也会跟着改变
        //在严格模式情况下,如果函数内部形参被重新设置,那么arguments不会被改变,他们是相互独立的
        //值类型的数据作为函数的参数
        function demo(str) {
            console.log(str);
            console.log(arguments[0]);
    
    
            //重新设置形参的值
            str = "hahahaha";
            console.log(str);
            console.log(arguments[0]);
        }
        demo("123456");
    
        //引用类型的数据作为函数参数
        function demo(obj) {
            console.log(obj);
            console.log(arguments[0]);
    
            //重新设置形参的值
            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 标签 全局作用域
    • 函数内部 局部作用域
    //    "use strict";    //位置01  对整个作用域中的代码都有用
    
       function demo01() {
    //       "use strict";    //位置02   仅仅对当前的函数有用,函数后面的代码不受影响
           a = 10;
           console.log(a);
       }
    
       function demo02() {
    //       "use strict";    //位置03  仅仅对当前的函数有用
           b = 20;
           console.log(b);
       }
    
       demo01();
       demo02();
    
    

    作用域说明

    • 作用域
      概念:变量或者是函数起作用的范围
    • js 的作用域
    • js 本身没有块级作用域(try-catch 除外)
    • js 中只有函数可以创建作用域
    • js 本身是此法作用域 (with|eval 除外)
    • 词法作用域:
      当代码写好之后,某个变量的作用域就已经确定了
    • 动态作用域:
      变量的作用域在代码运行之前是不确定的,只有在代码执行的时候才能根据当前的上下文来确定
    • 词法作用域的访问规则:
    • 单向性的(单向镜),内部的作用域可以访问外层的作用域空间,反过来却不行
    • 在访问变量的时候,先在当前作用于中查找,如果找不到那么就在上一级作用域中查找,重复这个过程
    • 在分析输出的时候,需要考虑到变量和函数声明的提升
      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){
            //如果出错了,那么就执行此处的代码
            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
    

    变量和函数的提升

    • js 代码的执行
      编译语言
      解释语言(js)
    • 预先解析阶段
      变量和函数声明的提升
    • 具体的执行代码
    • js 变量和函数声明提升的注意点
    • 变量和变量同名 后面的变量会把前面的变量覆盖
    • 函数和函数同名 覆盖
    • 变量和函数同名 函数声明会正常的提升,而变量的声明可以认为被忽略了
      只会提升到当前作用域的最顶端
      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);                    //函数-->
        <!--var a = "test-A";-->
        <!--function a() {-->
            <!--console.log("demo-A");-->
        <!--}-->
        <!--console.log(a);                   //函数-->
    
    
    
        <!--//模拟-->
        <!--var a;-->
        <!--function a() {-->
            <!--console.log("demo-A");-->
        <!--}-->
        <!---->
        <!--console.log(a);                    //函数-->
        <!--a = "test-A";-->
        <!--console.log(a);                   //test-A-->
    <!--</script>-->
    
    <script>
        console.log(a);
        var a = "test-A";
        function a() {
            console.log("demo-A");
        }
    
    //    不管函数在前面还是变量在前面,打印出来的结果都是函数
    </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
    

    变量提升是分作用域的

    • 在代码执行之前,会把所有的变量和函数生命进行提升
    • 在提升的时候,变量和函数声明的提升是分作用域的,只能提升到当前作用域的顶端
    • 内层作用域中的变量声明并不会覆盖外层作用域中的同名变量
    
        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>
    
    

    函数表达式的提升

    • 函数表达式提升,在提升的时候仅仅只会把声明部分(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>
    
    

    笔试题练习

    <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
    
    

    作用域链

    • 有多少个作用域 (函数的个数 + 1)
    • 相同作用域可以相互访问
    • 作用域链:
      在 js 中函数可以创建作用域,在函数内部又可以声明函数,在函数的函数内部又可以声明函数,每个函数都会创建一个作用域,这样就会形成一个作用域链
    • 在访问变量的时候,总是先在自己的作用域中查找
    • 如果没有那么就向上一级作用域查找,如果找到那么就直接使用,如果没有找到那么就继续重复这个过程
    • 直到最外层的全局作用域,如果还没有找到那么就报错
      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();
    

    作用域链绘图

    • 首先先找出全局变量(包含函数) 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();

    相关文章

      网友评论

          本文标题:2017-03-31 面向对象学习笔记

          本文链接:https://www.haomeiwen.com/subject/uuivottx.html