• 面向对象第7天


         今天的知识怎么说呢,说多也多,说少也少,有些凌乱。主要的知识点是闭包的三个应用、严格模式的相关知识点、ES5数组新方法、创建对象的方式、继承的方式。下面对各个知识点做详细介绍。

       一、闭包的三个应用

          1. 参数复用

            小案例:音乐模板的js代码

           

    onload = function() {  //入口函数
                function bindNav(fn) {  
                    var lis = document.querySelectorAll("#nav li");
                    for(var i = 0, l = lis.length; i < l; i++){
                        lis[i].addEventListener("click", function() {
                            switch(this.getAttribute('data-name')){
                                case "find":
                                    fn("这是发现音乐。");
                                    break;
                                case "mine":
                                    fn("这是我的音乐。");
                                    break;
                                case "friend":
                                    fn("这是我的朋友。");
                                    break;
                            }
                        });
                    }
                }
    
                function curryingBindContent(content) {
                    return function(text) {
                        document.querySelector(content).innerHTML = text;
                    };
                }
    
                bindNav(curryingBindContent("#content"));
            };

          2. 延迟计算/执行

            小案例:统计某地一周售楼的数量

          

                 /**
                   * [curryingSales 创建可以获取和保存售楼数闭包函数]
                   * @param {Function} fn [fn函数决定是获取周总数]
                   * @return {[type]} [闭包函数]
                 */
                 function curryingSales(fn){
                     var dailySales=[];
                     return function(val){
                         if(val==undefined){
                              return fn.apply(null,dailySales);
                         }else{
                             dailySales.push(val);
                         }
                     };
                  }
                 var weeklyTotal=curryingSales(function(){
                     var sum=0;
                     for(var i=0;l=arguments.length,i<l;i++){
                         sum+=arguments[i];
                      }
                     return sum;
                  });
                  weeklyTotal(2);
                  weeklyTotal(1);
                  weeklyTotal(2);
                  weeklyTotal(3);
                  weeklyTotal(1);
                  weeklyTotal(5);
                  weeklyTotal(4);
                 console.log(weeklyTotal());

          3. 提前返回    

          小案例:对addEventListener和attachEvent的兼容代码

      var addEvent = function() { // 浏览器支持addEventListener方法
                 if(window.addEventListener){
                      return function(element, type, callback, captrue) {
                          elem.addEventListener(type, callback, captrue);
                       };
                 } else { // 浏览器支持attachEvent方法
                     return function(element, type, callback) {
                          elem.attachEvent('on' + type, callback);
                          };
                     }
             }();

      二、严格模式的相关知识点

          1. 出现严格模式的目的

             (1)消除JavaScript语法的一些不合理、不严谨之处,减少一些怪异行为;

             (2)消除代码运行的一些不安全之处,保证代码运行的安全;

             (3)提高编译效率,增加运行效率;

             (4)为未来新版本的JavaScript做好铺垫。

          2.  严格模式标记

             直接在js代码中直接添加 "use strict";即可,    在老版本浏览器会将其当做一行普通字符串忽略。

          3.  使用模式

             (1)针对整个脚本文件

                    将"use strict;"放在脚本文件的第一行,则整个脚本将以“严格模式”运行。如果此语句不放在第一行,则无效,整个脚本以“正常模式”运行。

              

    <script>
      "use strict";
      console.log("这是严格模式");
    </script>
    <script>
      console.log("这是正常模式");
        "use strict";
    </script>

             (2)针对单个函数

                    将"use strict;"放在函数体的第一行,则整个函数以"严格模式"运行。

          

    function strict() {
        "use strict";
        console.log("这是严格模式");
    }
    
    function noStrict() {
        console.log("这是正常模式");
        "use strict";
    }

             (3)脚本文件的变通写法

                    由于第一种方式不利于文件合并,所以最好的做法是:将整个脚本文件放在一个沙箱模式(立即执行的匿名函数)中。

             

    (function() {
        "use strict";
        // 代码块
    }());

            4. 语法以及行为变化

                  严格模式下,对JavaScript的语法和行为,都做一些变化。
            (1)全局变量的隐式声明

                  在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。但是在严格模式已禁止这种用法,全局变量必须显式声明。

                 "use strict";

                  v = 1;             // 报错,v is not defined。
               在严格模式下,变量必须先使用var定义,再赋值。

             (2)静态绑定

                 JavaScript语言一个特点,就是允许"动态绑定",即某些属性和方法属于哪一个对象,不是在编译时确定的,而是在运行时确定的。

                 严格模式对动态绑定做一些限制。某些情况下,只允许静态绑定。也就是说,属性和方法到底归属哪个对象,在编译阶段就确定。这样做有利于编译效率的提高,也使代码更易阅读,更少出现bug。

                 a.  禁止使用with语句

                   原因:with语句无法在编译阶段就确定属性到底归属哪个对象。

    "use strict";
    var a = 1;
    // 报错,语法异常
    with(obj){
        a = 2;
    }

                 b. eval作用域

                    正常模式,JavaScript语言具有两种变量作用域:全局作用域 和 函数作用域(局部作用域)。
                    严格模式,具有第三种作用域:eval作用域。

                    正常模式下,eval语句的作用域取决于 它处于全局作用域,还是函数作用域。
                    严格模式下,eval语句本身就是一个作用域,不再能够产生全局变量,其所生产的变量只能用于eval内部。

                  

    <script>
       "use strict";
        var x = 2;
        console.log(eval("var x = 3; x"));    // 3
        console.log(x);    // 2
    </script>

                c.  增强安全性

                  在普通函数执行模式下,禁止this关键字指向全局对象. 因此,在使用构造函数时,忘记写new,this就不再指向window对象,而是报错。就不会意外给window对象添加属性或方法。

             

    function foo() {
        console.log(this);     // window
    }
    
    function foo() {
        "use strict";  
        console.log(this);        // undefined
    }
    
    function foo() {
        "use strict";
        this.name = "tom";
    }
    
    var f = foo();         // 报错

                 d.  禁止在函数内部访问caller以及arguments

    function fn() {
        "use strict";
        fn.caller;      // 报错
        fn.arguments; // 报错
    }
    fn();

                 e.  禁止删除变量

                    在严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。

          

    "use strict";
     var x;
     delete x;         // 报错
     var obj = Object.create(null, {
        "x": {
            value: 10,
            configurable: true
        }
     });
     delete obj.x;           // success

                f.  显式报错

                    (1) 在正常模式下,为一个对象的只读属性进行赋值,不会报错,只会默默的失败;而严格模式下,会抛出异常。

    "use strict";
     var obj = {};
     Object.defineProperty(o, "a", { value: 1, writable: false });
     obj.a = 2;        // 报错

                   (2) 严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。

     "use strict";
      var obj = {
        get a() { return 1; }
      };
      obj.a = 2;       // 报错

                   (3) 严格模式下,对禁止扩展的对象添加新属性,会报错。

    "use strict";
     var obj = {};
     Object.preventExtensions(obj);
     obj.a = 1;        // 报错

                   (4)严格模式下,删除一个不可删除的属性,会报错。

       

    "use strict";
     delete Object.prototype;         // 报错

                 g. 重名错误: 严格模式新增了一些语法错误。

                    (1)对象不能有重名的属性

                        正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误。

    "use strict";
     var obj = {
        p: 1,
        p: 2
     };         // 语法错误

                    (2)函数不能有重名的参数

                         正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。

                         

    "use strict";
     function f(a, a, b) {        // 语法错误
        return;
    }
                  (3)arguments对象的限制

                    arguments是函数的参数对象,严格模式对它的使用做了限制。

                    a. 不允许对arguments赋值

                      

    "use strict";
     arguments++;      // 语法错误
     var obj = { set p(arguments) { } };   // 语法错误
     try { }
     catch (arguments) { }     // 语法错误
     function arguments() { }   // 语法错误
     var f = new Function("arguments", "'use strict'; return 17;");     // 语法错误

                  b. arguments不再追踪参数的变化

    function f(a) {
        a = 2;
        return [a, arguments[0]];
    }
    f(1);         // 正常模式为[2,2]
    function f(a) {
        "use strict";
        a = 2;
        return [a, arguments[0]];
    }
    f(1);         // 严格模式为[2,1]

                  c. 禁止使用arguments.callee

                      这意味着,无法在匿名函数内部调用自身了。

            

    "use strict";
     var f = function() { return arguments.callee; };
     f();              // 报错
              (4)函数必须声明在顶层

                  将来Javascript的新版本会引入"块级作用域"。为了与新版本接轨,严格模式只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数。

    "use strict";
    if (true) {
        function f1() { }       // 语法错误
    }
    for (var i = 0; i < 5; i++) {
        function f2() { }      // 语法错误
    }
              (5)保留字

                  为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

    使用这些词作为变量名将会报错。

               

    function package(protected) {      // 出现保留字,语法错误
        "use strict";
        var implements;      //出现保留字, 语法错误
    }

              此外,ECMAscript第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的。

       三、ES5数组的新方法

          1. forEach 

         forEach是Array新方法中最基本的一个,就是遍历,循环。Array在ES5新增的方法中,参数都是function类型,默认有传参,forEach方法中的function回调支持3个参数,第1个是遍历的数组内容;第2个是对应的数组索引,第3个是数组本身。

             

    [].forEach(function(value, index, array) {
        // ...
    });

         2. map

             这里的map不是“地图”的意思,而是指“映射”。[].map(); 基本用法跟forEach方法类似:array.map(callback,[ thisObject]);callback参数与forEach类似:

    [].map(function(value, index, array) {
        // ...
    });

         案例:数组项求平方

         

    var data = [1, 2, 3, 4];
    
    var squares = data.map(function (item) {
       return item * item;
    });
    
    alert(squares);       // 1, 4, 9, 16

         3. filter 过滤器

           filter为“过滤”、“筛选”的意思。指数组filter后,返回过滤后的新数组。用法跟map极为相似:array.filter(callback,[ thisObject]);

           filtercallback函数需要返回布尔值truefalse.

        4. some和every

           some:指“某些”的意思,指是否“某些项”合乎条件。every:表示是否“每一项”都要靠谱.用法如下:

             array.some(callback,[ thisObject]);

             简单演示:

    var scores = [5, 8, 3, 10];
    var current = 7;
    
    function higherThanCurrent(score) {
      return score > current;
    }
    
    if (scores.some(higherThanCurrent)) {
      alert("朕准了!");
    }

            array.every(callback,[ thisObject]);

            简单演示:

    var scores = [5, 8, 3, 10];
    var current = 7;
    if (scores.every(higherThanCurrent)) {
      console.log("朕准了!");
    } else {
      console.log("来人,拖出去斩了!");        
    }

          5. indexOf

              indexOf方法在字符串中自古就有,string.indexOf(searchString, position)。数组的indexOf方法与之类似。用法:array.indexOf(searchElement[, fromIndex]); 返回整数索引值,如果没有匹配(严格匹配),返回-1fromIndex可选,表示从这个位置开始搜索,若缺省或格式不合要求,使用默认值0.

            小案例:

    var data = [2, 5, 7, 3, 5];
    
    console.log(data.indexOf(5, "x"));      // 1 ("x"被忽略)
    console.log(data.indexOf(5, "3"));     // 4 (从3号位开始搜索)
    
    console.log(data.indexOf(4));          // -1 (未找到)
    console.log(data.indexOf("5"));       // -1 (未找到,因为5 !== "5")

         6. lastIndexOf

             lastIndexOf方法与indexOf方法类似:array.lastIndexOf(searchElement[, fromIndex]);只是lastIndexOf是从字符串的末尾开始查找,而不是从开头。还有一个不同就是fromIndex的默认值是array.length - 1而不是0.

             

    var data = [2, 5, 7, 3, 5];
    
    console.log(data.lastIndexOf(5));      // 4
    console.log(data.lastIndexOf(5, 3));    // 1 (从后往前,索引值小于3的开始搜索)
    
    console.log(data.lastIndexOf(4));     // -1 (未找到)

          7. reduce

           迭代”、“递归(recursion)”的含义,用法:array.reduce(callback[, initialValue]);callback函数接受4个参数:之前值、当前值、索引值以及数组本身。initialValue参数可选,表示初始值。若指定,则当作最初使用的previous值;如果缺省,则使用数组的第一个元素作为previous初始值,同时current往后排一位,相比有initialValue值少一次迭代。

           小案例:

    var arr = [10,11,12,13,14];
    var sum = arr.reduce(function(prev, current, index, arr) {
        return prev + current;
    }, 0);
    console.log(sum);   //60

         实现上:

    // 初始设置
    previous = initialValue = 10, current = 11
    
    // 第一次迭代
    previous = (10 +11) =  21, current = 12
    
    // 第二次迭代
    previous = (21+ 12) =  33, current =13
    
    // 第三次迭代
    previous = (33 + 13) =  46, current = 14
    
    //第四次迭代
    previous = (46 + 14) =  60, current = undefined(退出)

     

          8.reduceRight

            用法与reduce相似,实现上差异在于reduceRight是从数组的末尾开始实现。

            小案例:

    var data = [1, 2, 3, 4];
    var special = data.reduceRight(function (previous, current, index) {
      if (index == 0) {
        return previous + current;
      }
      return previous - current;
    });
    
    console.log(special);   // 0

         实现上:

    // 初始设置
    index = 3, previous = initialValue = 4, current = 3
    
    // 第一次迭代
    index = 2, previous = (4- 3) = 1, current = 2
    
    // 第二次迭代
    index = 1, previous = (1 - 2) = -1, current = 1
    
    // 第三次迭代
    index = 0, previous = (-1 + 1) = 0, current = undefined (退出)

       四、创建对象的方式

            1. 工厂模式

                创建对象,返回带有属性和方法的person对象

    function createPerson(name, age,gender)
    {
        var person = new Person();
        person.name=name;
        person.age=age;
        person.gender=gender
        person.sayName=function()
        {
            alert(this.name);
        };
        return person;
    }
    createPerson("tom",20,"男").sayName();

            2. 构造函数模式

              创建对象,这种方式有个缺陷是sayName这个方法,它的每个实例都是指向不同的函数实例,而不是同一个。

    function Person(name,age,gender)
    {
        this.name=name;
        this.age=age;
        this.gender=gender;
        this.sayName=function()
        {
            console.log(this.name);
        };
    }
    
    var person = new Person("rose",23,"女");
    person.sayName();

            3. 原型模式

               创建对象,解决了上述中提到的缺陷,使不同的对象的函数(如sayFriends)指向了同一个函数。但它本身也有缺陷,就是实例共享了引用类型friends,从下面的代码执行结果可以看到,两个实例的friends的值是一样的。

              

    function Person()
    {
    }
    Person.prototype = {
        constructor : Person,
        name:"Tom",
        age:20,
        gender:"男",
        friends:["Jack","Rose"],
        sayFriends:function()
        {
            console.log(this.friends);
        }
    };
    var person1 = new Person();
    person1.friends.push("Mary");
    person1.sayFriends();   //Jack,Rose,Mary
    var person2 = new Person(); 
    person2.sayFriends();   //Jack,Rose,Mary

            4. 组合模式(推荐)

                使用原型模式和构造函数创建对象,解决了上述方法中提到的缺陷,而且这也是使用最广泛、认同度最高的创建对象的方法,强烈推荐使用。

    function Person(name,age,gender)
    {
        this.name=name;
        this.age=age;
        this.gender=gender;
       this.friends=["Jack","Rose"];
    }
    Person.prototype.sayFriends=function()
    {
        console.log("My name is"+this.name+","+"My friends are"+this.friends);
    };
    var person1 = new Person("Tom",20,"男");
    var person2 = new Person("Alice",18,"女");
    person1.friends.push("Marck");
    person1.sayFriends();  //My name is Tom ,My friends are Jack,Rose,Marck
    person2.sayFriends();  //My name is Alice,My friends are Jack,Rose

            5. 动态原型

              这个模式的好处在于看起来更像传统的面向对象编程,具有更好的封装性,因为在构造函数里完成了对原型创建。这也是一个推荐的创建对象的方法。

    function Person(name, age) {
        this.name = name;
        this.age = age;
        // method
        if(typeof this.sayName !== 'function'){
            Person.prototype.sayName = function() {
                console.log(this.name);
            }
        }
    }

            6. 寄生构造函数模式  (不常用,不推荐)      

    function Person(name, age) {
        var obj = new Object;
        obj.name = name;
        obj.age = age;
        obj.sayName = function() {
            console.log(this.name);
        };
        return obj;
    }

            7. 稳妥构造函数模式 (不常用,不推荐) 

    function Person(name, age) {
        var obj = new Object;
        obj.sayName = function() {
            console.log(name);
        };
    }

       五、继承方式

           1. 原型式

              利用原型让一个引用类型继承另外一个引用类型的属性和方法

    function A() {
                
            }
            A.prototype.location = "地球上。";
            A.prototype.say = function() {};
            A.prototype.talk = function() {};
            A.prototype.run = function() {};
            var a = new A;
            console.log(a.location);
    
            A.prototype = {
                say:function() {},
                talk:function() {},
                run:function() {}
            };
            var na = new A;
            console.log(na);

        2. 混入式

    var o1 = {
                name: 'tom'
            };
            var o2 = {
                age: 18
            };
            var o3 = {
                gender: '男'
            };    
            console.log(o1);
            o1.extend = function() {
                var k,
                    i = 0,
                    l = arguments.length,
                    args = arguments;
                // 遍历在arguments上的每一对象
                for (; i < l; i++) {
                    // 枚举当前对象上的所有属性,添加到this上
                    for (k in args[i]) {
                        this[k] = args[i][k];
                    }
                }
            };
            o1.extend(o2, o3);
            console.log(o1);

         3. 借用构造函数

              在子类型构造函数的内部调用超类构造函数,通过使用call()和apply()方法可以在新创建的对象上执行构造函数。

    function SuperType() {
    this.colors = ["red","blue","green"];
    }
    function SubType() {
    SuperType.call(this);//继承了SuperType
    }
    var instance1 = new SubType();
    instance1.colors.push("black");
    console.log(instance1.colors);//"red","blue","green","black"
    var instance2 = new SubType();
    console.log(instance2.colors);//"red","blue","green"

         4. 对象冒充

    function parent(name, age) {
                this.name = name;
                this.age = age;
            }
    
            function child(name, age, gender, address) {
                // 将parent作为child对象的一个方法来调用
                this.parent = parent;
                this.parent(name, age);
                delete this.parent;
                this.gender = gender;
                this.address = address;
            }
    
            var ch = new child('tom', 18, 'boy', 'beijing');
            console.log(ch);

             5. 组合继承(借用构造函数、原型)

                将原型链和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式。

            6. 寄生式(不常用)

               创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。

            7. 组合寄生(不常用)

              通过借用函数来继承属性,通过原型链的混成形式来继承方法

              

     

              

                   

                   

               

                   

                   

                

     

  • 相关阅读:
    Maven仓库是什么
    什么是Maven
    Shiro 的优点
    shiro有哪些组件
    Python偶斐波那契数
    Python求1000以内所有3或5的倍数的和。
    python"TypeError: 'NoneType' object is not iterable"错误解析
    python中列表常用的几个操作函数
    反射类的一些基本用法
    循环随机数短时间内大多都是重复的问题
  • 原文地址:https://www.cnblogs.com/fatimah1214/p/6067528.html
Copyright © 2020-2023  润新知