美文网首页
2023-03-23_DOMDAY08-JS高级-递归

2023-03-23_DOMDAY08-JS高级-递归

作者: 远方的路_ | 来源:发表于2023-03-23 21:29 被阅读0次

    1. bind方法

    bind() 函数会创建一个新函数(称为绑定函数)

    • bind是ES5新增的一个方法
    • 传参和call类似
    • 不会执行对应的函数,call或apply会自动执行对应的函数
    • 返回对函数的引用
    • 语法 fun.bind(thisArg[, arg1[, arg2[, ...]]])
    <script>
        var obj = {
                name: "阿马"
        }
        function add(a, b) {
                console.log(this);
                console.log(a + b)
        }
        var new1 = add.bind(obj, 1, 2)
        new1();
        //返回的不是同一个函数
        console.log(new1 === add);
    </script>
    

    2. querySelector和getxxxByxxx的区别

    getXXXByXXX 获取的是动态集合,querySelector获取的是静态集合。

    简单的说就是,动态就是选出的元素会随文档改变,静态的不会,取出来之后就和文档的改变无关了。

    3. 函数的递归

    前提:arguments.callee 打印出来的就是函数本身,它可以在函数递归调用的时候,派上用场
    arguments.callee 打印出来的就是函数本身,它可以在函数递归调用的时候,派上用场
    function fn(){
    console.log(arguments.length);
    console.log(arguments.callee);
    }
    fn();

    能用递归的地方都可以不用。
    函数的递归调用,就是函数在内部自己调自己
    函数的递归调用是一把双刃剑,如果设计的好,可以帮我们简单的处理事情,如果设计不好就是灾难

    • 函数的递归要想设计好必须有两个条件
      • 必须有一个明显的结束条件,不能一直递归下去
      • 每一次调用都要有一个趋近结束条件的趋势
    // 递归实现阶乘
     function f(n){
           if(n == 1){
                return 1
           }
                return n * f(n-1);
           }
    var a = f(5);
    console.log(a); // 120
    

    4. 终极原型链

    任何的函数对象的prototype都和这个函数对象实例化的对象proto都指向同一个对象

    原型链.jpg 终极原型链.png

    5. 闭包

    为什么要学习闭包?
    先必须理解Javascript特殊的变量作用域。

    变量的作用域无非就是两种:全局变量和局部变量。

    • 全局变量 可以在局部作用域内访问
    • 局部变量 不可以在全局作用域内访问的
    • 函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量
    • 闭包的产生条件/使用步骤
      1. 在外部函数f1内 嵌套一个内部函数f2
      2. 内部函数f2 引用外部函数f1的局部变量a
      3. 外部函数f1 返回内部函数f2的函数体
      4. 内部函数f2和外部函数f1都要执行
     function f1(){
        var a = 1;
        function f2(){
           return a;
        }
        return f2;
    }
    // 返回的是就是f2的函数体
    var result = f1();
    var aaaa = result();
    console.log(aaaa);
    
    • 闭包到底是什么?

      • 理解一: 闭包是嵌套的内部函数(绝大部分人)
      • 理解二: 闭包是包含外部函数的局部变量的对象(极少数人)
      • 理解三: 所谓的闭包是一个引用关系,该引用关系存在于内部函数中,引用的是外部函数的局部变量的对象(深入理解)
    • 常见的闭包

      • 将函数作为另一个函数的返回值
      • 将内部函数作为外部函数的返回值
    • 闭包的作用 ( 企业开发中我们不允许使用全局变量 )

      • 延长外部函数变量的生命周期
      • 让函数外部可以操作(读写)到函数内部的数据(变量/函数)/函数外部可以引用函数内部的变量
      • 注意: 浏览器为了性能,后期将外部函数中不被内部函数使用的变量清除了
    function buyLip(){
        var money = 500;
        function f2(){
            money -= 100;
            console.log(money);
        }
        return f2;
    }
    var result = buyLip();
    result(); // 400
    result(); // 300
    
    • 闭包使用中的坑点 ( ()()会重置初始化原始外部变量的值 )
    function buyLip(){
        var money = 500;
        function f2(){
            money -= 100;
            console.log(money);
        }
        return f2;
    }
    buyLip()(); // 500
    buyLip()(); // 500
    
    • 闭包的缺点和解决(内存泄漏和内存溢出)
      • 内存泄漏 : 内存无法释放;
      • 内存溢出 : 内存被撑爆;
      • f = null; 解决方式;
    function fn(){
        var a = 0;
        function fn1(){
            a++;
            console.log(a);
        }
        return fn1;
    }
    var f =  fn();
    f();
    f();
    f = null;//释放闭包
    

    6. 面向对象

    面向对象三大特性:封装、继承、多态

    • 原型继承-方法继承
      • 让父类的实例作为子类的原型,将子类的原型构造器补充完整 (为了让子类继承方法)
    <!DOCTYPE html>
    <html lang="zh-CN">
        <head>
            <meta charset="UTF-8" />
            <title>面向对象-原型继承-方法继承</title>
        </head>
        <body>
            <script>
                function Dog(){
                }
                Dog.prototype.eat = function(){
                    console.log('翔');
                }
    
                function Teddy(){
                }
                Teddy.prototype = new Dog();
                Teddy.prototype.constructor = Teddy;
    
                function ChaiQuan(){
                }
                ChaiQuan.prototype = new Dog();
                ChaiQuan.prototype.constructor = ChaiQuan;
    
                var t = new Teddy();
                t.eat();
                var c = new ChaiQuan();
                c.eat();
    
            </script>
        </body>
    </html>
    
    原型继承(方法继承).png
    • 构造器(函数)继承-属性继承

      • 在子类当中去调用父类的构造函数(为了让子类继承属性)
    • 组合继承

      • 原型继承方法,借用构造函数继承属性一起使用
    • 方法重写和方法重载(多态的表现形式)
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <script type="text/javascript">
                //父类
                function Dog(name,age){
                    this.name = name;
                    this.age = age;
                }
                
                //子类
                function Teddy(name,age){
    //              this.name = name;
    //              this.age = age;
                    //借助父类的构造函数实现属性的继承
                    Dog.call(this,name,age);
                }
                
                Dog.prototype.run = function(){
                    console.log('跑的很快~');
                }
                
                //为了让子类去继承父类原型当中的方法
                //我们需要用到原型继承,原型继承主要就是为了让子类继承方法使用的
                //让子类的原型变成父类的一个实例
                //手动给原型对象添加一个构造器,因为原型对象里面都是有构造器的,指向和自己匹配的构造函数
                Teddy.prototype = new Dog();
                Teddy.prototype.constructor = Teddy;
                
                
                //方法重写和方法重载   是多态的两个表现形式
                //方法重写;和父类同名方法功能不同,被称作方法重写
                Teddy.prototype.run = function(flag){
                    //方法重载
                    if(typeof flag === 'number'){
                        console.log('跑的很慢~');
                    }else{
                        console.log('跑的很快~');
                    }
                }
                
    
                var d1 = new Dog('旺财',3);
                d1.run();
                
                var t1 = new Teddy('小黑',2);
                t1.run(10);
                
                console.log(t1);
                
            </script>
        </body>
    </html>
    

    7. web Workers

    • H5规范提供了js分线程的实现, 取名为: Web Workers

    • 相关API

      • Worker: 构造函数, 加载分线程执行的js文件

      • Worker.prototype.onmessage: 用于接收另一个线程的回调函数

      • Worker.prototype.postMessage: 向另一个线程发送消息

      • 每个线程可以向不同线程发送消息 也可以接收不同线程传来的消息

      • 主线程操作

        • 发送消息: worker.postMessage(消息可以是任何数据)

        • 接受消息: worker.onmessage = function(e){

                    console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中
          
                }
          
      • 子线程操作

        • 发送消息: worker.postMessage(消息可以是任何数据)

        • 接受消息: worker.onmessage = function(e){

                    console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中
          
                }
          
    • 不足

      • worker内代码不能操作DOM
      • 不能跨域加载JS
      • 不是每个浏览器都支持这个新特性
    • 计算得到fibonacci数列中第n个数的值

      • 在主线程计算: 当位数较大时, 会阻塞主线程, 导致界面卡死
    function fib(n){
        if(n <= 2){
            return 1;
        }
        return fib(n- 1) + fib(n - 2);
    }
    
    • js代码-myThread.js :
    function fib(n){
        if(n <= 2){
            return 1;
        }
        return fib(n- 1) + fib(n - 2);
    }
                
    self.onmessage = function(e){
        e = e || window.event;
    //  console.log(e.data);//就 可以拿到主线程给我 发过来的消息内容
        
        var result = fib(e.data);
        self.postMessage(result);//分线程接受到主线程的消息,然后开始计算,把计算后的记过发消息再给主线程
    }
    
    • html代码 :
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <script type="text/javascript">
                //第一步:实例化一个对象,初始化主线程和分线程关联对象
                
                
                var worker = new Worker('./myThread.js');
                
                worker.postMessage(100);//主线程发送消息给分线程,消息内容可以是任意类型
                
                worker.onmessage = function(e){
                    e = e || window.event;
                    //等待接受分线程计算完的结果
                    console.log(e.data);
                }
    
                console.log('大哥 js Ending~');
        
            </script>
        </body>
    </html>
    

    面试题

    // 当发生连等的时候  那么属性的优先级更高
    var a = { n: 1 };
    var b = a;
    a.x = {n:2}
    a = {n:2}
    a.x = a = { n: 2 };
    console.log(a.x); // 报错
    console.log(b.x); // {n:2}
    
    var b1 = {
            b2:[2,'atguigu',console.log],
            b3:function () {
            alert('hello')
            }
    }
    console.log(b1, b1.b2, b1.b3); // {b2: Array(3), b3: ƒ}  b2: (3) [2, 'atguigu', ƒ]  b3: ƒ ({alert('hello')})
    console.log(b1 instanceof Object, typeof b1); // true 'object'
    console.log(b1.b2 instanceof Array, typeof b1.b2); // true  'object'
    console.log(b1.b3 instanceof Function, typeof b1.b3); // true  'function'
    console.log(typeof b1.b2[2]); // 'function'
    console.log(typeof b1.b2[2]('atguigu')); // 'atguigu' undefined 
    b1.b2[2]('atguigu'); // 'atguigu'
    
    var a = {};
    var obj1 = {
        m: 2,
    };
    var obj2 = {
        n: 2,
    };
    var obj3 = function () {};
    
    a[obj1] = 4;
    a[obj2] = 5;
    a.name = 'kobe';
    a[obj3] = 6;
    
    console.log(a[obj1]); // 5
    console.log(a); // {[object Object]: 5, name: 'kobe', function () {}: 6}
    
    var name = 'The Window';
    var object = {
        name: 'My Object',
        getNameFunc: function () {
            return function () {
                return this.name;
            };
        },
    };
     console.log(object.getNameFunc()); //  f () { return this.name }
    console.log(object.getNameFunc()()); // The Window
    
    var name2 = 'The Window';
    var object2 = {
        name2: 'My Object',
        getNameFunc: function () {
            var that = this;
            return function () {
                return that.name2;
            };
        },
    };
    console.log(object2.getNameFunc()); // f () {return that.name2;}
    console.log(object2.getNameFunc()()); // My Object
    

    相关文章

      网友评论

          本文标题:2023-03-23_DOMDAY08-JS高级-递归

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