美文网首页
JavaScript进阶教程-2.call apply 表格排序

JavaScript进阶教程-2.call apply 表格排序

作者: 超跑飞飞 | 来源:发表于2020-02-18 13:39 被阅读0次

    关于函数、原型、dom、this的深入理解

    原型深入

    dom获取元素

    1. 通过标签获取来的是HtmlCollection,通过标签获取来的都是HtmlCollection类的一个实例
    2. 所有的div都是HTMLDivElement这个类的一个实例>==>HTMLElement==>Element==>Node==>EventTarget==>Object
    3. getElementsByName是定义在document这个家族的方法。
        var p = document.getElementsByName('p'); //通过name获取来的
        var oDiv = document.getElementById('div1');
        var op = oDiv.getElementsByTagName('p'); //通过tag获取来的
        console.dir(p); //p是NodeList的一个实例
        console.dir(op);//op是HtmlCollection这个类的一个实例
        //console.dir({});
        //console.dir([]);
        console.dir(oDiv);
        //所有的div都是HTMLDivElement这个类的一个实例==>HTMLElement==>Element==>Node==>EventTarget==>Object
        var sP = document.getElementById('p'); //通过oDiv来查找getElementsByName的属性,并且让这个属性的值去执行,传入了一个'p'作为参数
        console.dir(sP);
    
        // document.getElementById('p')  这个getElementById属性是不是方法也是一个函数
    

    函数的三种角色

    函数有多种角色:

    1. 普通函数: 函数执行的时候就会产生一个私有的作用域,栈内存。 形参赋值 预解释 代码逐行执行 闭包 内存释放问题
    2. 构造函数(类): new 实例 实力!! 构造函数中的this是当前实例 return问题
    3. 那么函数它自己本身是谁的实例 任何一个函数都是Function这个类的一个实例,那么任何一个函数实例都可以调用(proto)定义在Function这个类原型上的所有属性和方法
        Object.prototype.toString.call();
        var obj = {}; // [object Object]
        var f = new Array(); // ""
    
    

    call方法深入

    call这个方法是定义在Function.prototype的方法。那么我们定义任何一个函数我们都可以认为它是Function这个类的一个实例。那么就可以通过实例的__proto__属性找到所属类的原型。任何一个函数都可以调用call和apply等方法 eg: Object.prototype.toString.call(); 强制改变this关键字的
    call作用:
    函数实例找到call方法执行,call的执行过程中把调用call方法这个函数实例中的this都改变成call的第一个参数。接下来再把调用call方法的这个实例函数执行

        function fn() { //是Function这个类一个实例
            console.log(this); //obj
        }
        //fn(); // this==>window
        var obj = {
            fn: fn
        }
        //obj.fn();//this ==> obj
        //fn.call(obj); // 1 找到call方法并且运行  2 在运行之前把调用call方法的fn这个函数中的this都修改成call的参数,也就是obj  3 执行fn
    
    
        //假如在Function的原型上没有定义一个call,我们自己模拟呢??
        Function.prototype.myCall = function (obj) {
            //把这个函数体内的this都改成obj这个参数
            //执行fn就是this执行
            //console.log(this);
            this(); //因为这个this只有在调用call方法的时候才知道具体是那个函数实例
        }
        //fn.call(obj); //  用obj去借用fn这个方法
    
        //
        function fn1() {/*console.log(1)*/
           /* this();
            console.log(this)*/
            console.log(1)
        }
        function fn2() {
            console.log(2)
        }
        fn1.call(fn2); //1 在执行的过程中把fn1中的this改成fn2然后fn1()  ==> 1
        /*
        *   上面的fn1.call(fn2)是改变fn1中的this
        * */
        (function (){}).call/*function call()*/.call.call.call.call.call(fn2);
        /*
        *   上面的call是改变function.__proto__.call的call方法中的this
        * *///fn2  这里的fn1只是用来读取值。通过fn1来读取Function.prototype的属性
        //规律: 多个call就是相当于参数执行,而调用call的方法是用来读取call这个属性值的
        //Function.prototype.call(fn1); //Function.prototype是一个匿名函数,但是这个函数什么也没做
       // Function.prototype.call.call.call(fn1); //fn1 ==> fn2.call.call.call(fn1)
    
    

    call和apply和bind的区别

    call在执行的时候,call的第一个参数是用来改变this的,而从第二个参数开始都是传给调用call的函数的

    严格模式: call执行的时候和非严格模式不同 没有参数:undefined null:null undefined:undefined,非严格模式都是window
    在函数体内的arguments不随着参数变化而变化 arguments.callee arugmetns.caller 不能用
    this问题:严格模式自执行函数中的this是undefined,如果没有执行主体this也是undefined。非严格模式下都是window

        `/*'use strict';*/ //严格模式解析代码`
        function sum(num1, num2) {
            //console.log(num1 + num2);
            //console.log(this);
        }
        //sum(100,200); //300 window
        //sum.call(100,200); //从第二个参数开始是传个sum的,我们此时函数已经执行结束了
    
        //sum.call(); //window
        //sum.call(null); //window
        //sum.call(undefined); //window
        // !function (){console.log(this)}();
    

    apply:它跟call的用法是一样一样的。就是传参数的方式不相同而已
    call:是把从第二个参数开始一个一个传给调用call的函数主体
    同样也是相当于把数组中的每一项分别传给调用apply这个方法的函数实例

        function sum(num1, num2) {
            console.log(num2 + num1);
            console.log(this);
        }
        //sum.apply(null,[100,200]); //apply的用法,也是把数组参数中的每一项分别传给sum的
    

    绑定 bind: 同样也是用来改变this关键字的

       /* var temp = sum.bind(null, 100, 200);  预处理 中间量  假设 标识变量
        temp();*/
        var obj = {name : 'zx'}
        var temp = sum.bind(obj); //仅仅是改变了this,但是并没有执行 temp已经是被改变了this的函数
        temp(100,200); //当我们需要的时候才执行呢
    
    

    JSON操作

    JSON它是一个特殊的数据格式,是可以跨平台传输的数据

        var obj = {name: 'zf'};
        var jsonObj = {"name" : "tx"};
    
    

    JSON常用方法:
    JSON.stringify() 把json格式的对象转化为字符串的
    JSON.parse(); 把json格式的字符串转化为json格式的对象,低版本ie不兼容

        var str = JSON.stringify(jsonObj); //json格式的字符串
        console.log(JSON.parse(str)); //
    
    
    JSON.png

    正则及实战应用

    正则的作用

    用来判断字符串是否符合规则 处理字符串

    1. test 用来验证是否符合规则返回真和假 ==》 正则匹配
    2. exec 用来把当前字符串中所有符合规则的字符串获取到。 用来实现正则的捕获的。 返回的是一个数组 ==》 正则捕获
      正则的创建:var reg = /\d/; 实例创建: var reg = new RegExp('');
        var reg = /\d/;
        console.log(reg.test('1')); //
        console.log(reg.exec('x')); //
        console.log(reg.exec('1')); //
    

    正则的元字符

        /*
        *   正则由元字符和修饰符组成
        *   1 元字符: 具有一定意义的字符 eg:\d 代表0-9中间的一个数字
        *       特殊意义的元字符:
        *           1 \转义字符
        *           2 ^用某个元字符开头
        *           3 $ 用某个元字符结尾
        *       量词符:
           *       1 *
           *       2 +
           *       3 ?
           *       4 {n}
           *       5 {n,}
           *       6 {n,m}
        *       修饰符:
        *           1 g global全局
        *           2 i ignoreCase忽略大小写
        *           3 m multyline多行
        *
        * */
        var reg = /\\d/;
        reg.test('\d')
    

    编写简单的正则表达式

    
        var reg1 = /^\d+(ab|cd|xyz)\d+$/;
        var reg2 = /^\d+ab|cd|xyz\d+$/;
        var str1 = '400ab500';
        var str2 = '234ab';
        var str3 = '1324abcd';
        var str4 = 'cd8888ab';
        var str5 = 'xyz999ab';
    
        //验证邮箱
        //你的网站的邮箱规则
        /*
        *   可以包括数字 字母  下划线 @ 域名 . com/net/cc/cn只能是正常的字母
        *   '.'这个元字符匹配太多需要转义
        *   在[]里的单个的元字符不用转义,就表示这个字母表示的本身的意思
        * */
        var reg =  /^[\w.]+@\w+(\.[a-z]+)?$/i
        /*
        *   问号的几种意义?
        *       1 量词出现0-1次 出现在实际意义字符后边的时候是一个量词
        *       2 贪婪 or 非贪婪   出现在量词后面的问号是修饰贪婪还是非贪婪,如果不加问号那么就是把能匹配多少都拿回来,如果加一个问号。那么是尽可能少的去匹配和捕获 /\d+?/
        *       3 分组中的匹配不捕获也就是子正则中的匹配不捕获,那么就不会出现在exec捕获时候返回的数组中。?: 把问号和冒号放在括号的开始位置。表示不在把括号中的内容当成一个子正则。那么这个分组其实也已经取消了  /^\d(?:ab|cd|ef)\d$/
        *       4 正向预查询和负向预查询  带条件的正则表达式 ?=  ?!负向预查询
        *           eg: 一个字符串有连续多个数字,但是这些数字后边是字母。但是只把满足条件的数组取到,后面的字母忽略。只是一个以字幕结尾这是一个条件,但是不参与捕获      var str2 = 'adsf345qwe#'  这个不行
        *           var  str3 = 'adfa8888aaaa'
        *           var reg = /\d{2,}(?=[a-z]+$)/  切记$符号不要去修饰条件。正向预查询相当于加了一个条件。这个括号里根本就不参与捕获,只是这个正则成立的条件
        *
        * */
    
        /*
        *   [^a-z] 除了a-z以外的任意字符  var reg = /[^a-z]/;
        *   \d  是0-9  \D 除了0-9之外的任意字符
        *   \w  是[a-zA-Z0-9_]
        *   \W  也是取非集
        *   \s  一切不可见的字符集
        *   \S  取反
        *   . 除了匹配回车之外的单字符
        *
        *
        *   验证重复的字符串  var reg = /(\w)/;  reg.exec()'';
        *                    var reg = /(\w)\1+/
        *
        * */
    
    
    
        /*
        *
        *   分组: 难点+重点
        *       1 什么是分组
        *       2 分组的引用
        *       var reg = /^(\d)(\d)\1$/
        *
        *       用其他方式获取分组捕获的内容
        *       var reg = /(\w)(\w)(\w)/
        *       var str = 'abcdefghijklmn'
        *       reg.test(str);
        *       正则这个方法只要运行了就可以去访问RegExp.$1 - $9 当这个正则实例运行之后,如果此正则上有分组,则自动把捕获到的内容分别赋值给构造函数的$1-$9,如果不够是空字符串 如果是对象类型的找不到才是null 如果是值类型的找不到事空字符串
        *
        *
        *       模式修正符
        *           g
        *           i
        *           m
        *           匹配模式ip地址
        *           192.168.1.1
        *           reg.exec(); 即使你加了g也没有多次都匹配回来
        *           str.match   这个吧所有能匹配来的都匹配来的
        *           这里有一个reg.lastIndex在作怪
        *           str1 = 'qewrqewr8'
        *           str2 = '4adfaasd'
        *           因为上一次匹配的时候的lastIndex是8.下次从8开始找了。但是要用同一个reg实例
        *           正则是尽可能少的去匹配次数,但是却在每次尽可能多的去匹配
        *           加上了全文修饰符g每次lastIndex都会变成0,如果是验证就不要加g了。因为仅仅是为了验证而已
        *
        *           重点replace
        *           var a = [];
        *           str.replace(/\d/g,function (){
        *               return a[arguments[0]]
        *               arguments[0] 当前匹配结果
        *               arguments[1]  当前匹配结果在字符串中的索引
        *               arguments[2]  整个字符串
        *               String.fromCharCode(64+arguments[0]/1)
        *           })
        *
        *
        *
        *           把字符串反转的固定技巧
        *               'abc'.replace(/(\w)(\w)(\w)/,'$3$2$1')
        *
        *
        *            把不限长度的字符串反转 abcdefg
        *            str.replace(/\w/g,function (){
        *               找到第一个用最后一个替换掉
        *               第一个索引位置用arguments[1]; //length-1
        *               str.length-1-arguments[0]
        *               return str.charAt(str.length-1-arguments[1])
        *
        *            })
        *
        *
        *            replace实现字符串去重
        *            var str = '88888888889999999999999997777777777777'
        *
        *
        *
        *
        * */
        var ary = ['a','b','c','d','e'];
        var str = '12345';
        str = str.replace(/\d+/g,function (){
            //console.log(arguments);
            //console.log(]) ;
            return ary[arguments[1]];
        })
        console.log(str);
    
        var str = '888888888888999999999999997777777777';
        str =  str.replace(/(\d)\1+/g,function (a,b,c,d){
            //如果正则里有了分组就不是3个参数了 是4个参数
            //如果有分组,第一个参数是总正则匹配的记过,第二个参数是子正则匹配的结果
            return b;
        })
        console.log(str)
    
    

    项目实战-表格排序

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            *{ margin: 0; padding: 0; }
            .ul{ list-style: none; width: 200px; margin: 30px auto;  }
            .ul li{ border-bottom: 1px solid #ccc; height: 30px; line-height: 30px; }
        </style>
    </head>
    <body>
        <ul class="ul">
            <li>88</li>
            <li>89</li>
            <li>78</li>
            <li>92</li>
            <li>85</li>
            <li>97</li>
        </ul>
        <script  src="utils.js"></script>
        <script>
            var oul = document.getElementsByClassName('ul')[0];
            var oLis = document.getElementsByClassName('ul')[0].getElementsByTagName('li');
            console.dir(oLis);
            var ary = utils.listToArray(oLis);
            ary = ary.sort(function (a,b){
                return parseFloat(a.innerHTML) - parseFloat(b.innerHTML);
            })
            console.dir(ary);
            var frg = document.createDocumentFragment();
    
            for(var i=0; i<ary.length; i++){
                frg.appendChild(ary[i]);
            }
            oul.appendChild(frg);
            frg = null;
        </script>
    <!--
        工作中遇到的问题:
            1 由于网页内的元素变化,并且元素改变引起的bug考虑是不是有可能是dom映射
            2 网页内元素事件丢失考虑是不是由于innerHTML引起的bug
    -->
    
    </body>
    </html>
    
    var utils = {
        listToArray : function (similarArray){
            /*
            *   try catch js
            * */
            var a = [];
            try{
                a = Array.prototype.slice.call(similarArray);
            }catch (e){
                alert(); //ie7 和 8 弹出
                var a = [];
                for(var i=0; i<similarArray.length; i++){
                    a[a.length] = similarArray[i];
                }
            }
            return a;
        },
        jsonParse: function (jsonStr){
            return 'JSON' in window ? JSON.parse(jsonStr) : eval("(" + jsonStr+")");
        }
    
    }
    

    相关文章

      网友评论

          本文标题:JavaScript进阶教程-2.call apply 表格排序

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