js高级 重要知识点:原型链、闭包、自定义模块

原型链(别名:隐式原型链)

作用: 查找对象的属性(方法)
访问一个对象的属性时:

  1. 先在自身属性中查找,找到返回
  2. 如果没有,再沿着__proto__这条链向上查找,找到就返回
  3. 如果最终没有找到,放回undefined

在这里插入图片描述

  1. 函数的显示原型指向的对象是空Object实例对象(但Object不满足)
  2. 所有的函数都是Function的实例(包含Function)
  3. Object 原型对象是原型链的尽头

读取对象的属性值时:会自动到原型链中查找
设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
方法一般定义在原型中,属性一般通过构造函数定义在对象本身上

    function AA() {

     }
     AA.prototype.a = 'xxx';
     var fn1 = new AA();
     console.log(fn1.a, fn1);

     var fn2 = new AA();
     fn2.a = 'yyy';
     console.log(fn2.a, fn2);

在这里插入图片描述



        // 函数的显示原型指向的对象是空Object实例对象(但Object不满足)

        console.log(myfn.prototype instanceof Object);
        console.log(Function.prototype instanceof Object);
        console.log(Object.prototype instanceof Object);

        // 所有的函数都是Function的实例(包含Function)
        console.log(Function.__proto__ === Function.prototype);
        // Object 原型对象是原型链的尽头
        console.log(Object.prototype.__proto__);//值为null

在这里插入图片描述

变量提升与函数提升

       var a = 3;

        function test() {
            console.log(a);
            var a = 4;
        }
        test();

输出是undefined 函数体内相当于执行了
var a; console.log(a); a=4;

     var a = 3;

        function test() {
            console.log(a);
            // var a = 4;
        }
        test();
//此时输出3

变量(声明)提升 :通过var定义的变量,在定义语句之前就可以访问到,只不过此时值为undefined
函数(声明)提升: 通过function声明的函数,在之前就可以直接调用,值是函数定义(对象)



        console.log(b); //变量声明提升

        fn2(); //可调用  函数(声明)提升
        var b = 3;

        function fn2() {
            console.log("fn2()");
        }

全局执行上下文

  1. 在执行全局代码前将window确定为全局执行上下文
  2. 对全局数据进行预处理: var定义的全局变量===》undefined,添加为window的属性 function声明的全局函数,添加为window的方法 this赋值为window 然后开始执行全局代码。

函数执行上下文

  1. 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟)
  2. 对局部数据进行预处理: 形参–> 实参(赋值)–>添加为执行上下文的属性
    arguments --》实参列表(赋值)–> 添加为执行上下文的属性
    var定义的局部变量–> undefined ,添加为执行上下文的属性
    function声明的函数–> 赋值(fun),添加为执行上下文的方法
    this–》赋值(调用函数的对象)
    开始执行函数体代码


        console.log("函数执行上下文");

        function myfn(a1) {
            console.log(a1); //2
            console.log(a2); //undefined
            a3(); //a3()
            console.log(this); //window
            console.log(arguments); // 伪数组(2,3)

            var a2 = 3;

            function a3() {
                console.log("a3()");
            }

        }
        myfn(2, 3);

在这里插入图片描述

函数闭包

产生闭包的条件:
函数嵌套
内部函数引用了外部函数的数据(变量/函数)

闭包的生命周期:

产生 在嵌套内部函数定义执行完时就产生了(不是在调用)
死亡 在嵌套内部函数成为垃圾对象时

闭包的缺点

  1. 容易造成内存泄露
  2. 函数执行完后,函数内的局部变量没有被释放,占用内存时间会边长

如何解决

及时释放 让某个对象=null,召唤垃圾回收器
例如 var f = fn1(); f(); f=null ; 让内部函数成为垃圾对象 —> 回收闭包

哪些情况可能会造成内存泄露

意外的全局变量
没有及时清理的定时器或者回调函数
闭包

闭包的应用 自定义js模块

推荐使用闭包 调用方便

function myModule1() {
    var str = "zhOUdage";

    function dosomething() {
        console.log("dosomething()" + str.toUpperCase());

    }

    function doother() {
        console.log("doother()" + str.toLowerCase());

    }
    return {
        dosomething: dosomething,
        doother: doother
    };
}


// 使用闭包
(function() {
    var str = "zhOUdage";

    function dosomething() {
        console.log("dosomething()" + str.toUpperCase());

    }

    function doother() {
        console.log("doother()" + str.toLowerCase());

    }

    window.myModule2 = {
        dosomething: dosomething,
        doother: doother
    };
})()

  <script src="myModule.js"></script>
    <script type="text/javascript">
        var module = myModule1();
        module.dosomething();
        module.doother();

        // 上面是方式一

        myModule2.doother();
        myModule2.dosomething();
    </script>

继承

子类型的原型为父类型的一个实例对象

在这里插入图片描述

定时器真的是定时执行的吗

定时器并不能保证真正定时执行
一般会延迟一点儿(可以接受),但做一个长时间的工作,会延迟不能接受的时间


<head>

        window.onload = function() {
            var btn = document.getElementsByClassName("btn")[0];
            btn.onclick = function() {
                var date = Date.now();
                console.log("定时器执行前");
                setTimeout(function() {
                    console.log("延时", Date.now() - date);
                }, 200);

                console.log("定时器执行后");


                for (var i = 0; i < 1000000000; ++i) {}

            }



        }
    </script>
</head>

<body>

    <button class="btn">点我延迟200</button>
</body>



在这里插入图片描述

js单线程执行,如何证明

代码如下

 setTimeout(function() {
                console.log("timeout 2222");
            }, 2000)

            setTimeout(function() {
                console.log("timeout 111");
            }, 1000);


            setTimeout(function() {
                console.log("timeout 000");

            }, 0);

            function fn() {
                console.log("fn()");
            }

            fn();

            console.log("alert之前");

            alert("----------------");
            // 暂停主线程执行  同时暂停计时
            console.log("alert之后");

代码分类:
初始化代码 回调代码

js引擎执行代码的基本流程

  • 先执行初始化代码:例如:绑定事件监听、设置定时器、发送ajax请求
  • 后面在某个时刻才执行回调代码

在这里插入图片描述

为什么js使用单线程而不是多线程:
与它的用途有关,作为脚本语言,主要是与用户互动,以及操作dom,决定了它只能是单线程,否则会带来很复杂的同步问题

js分线程,不更新界面,适用于后台数据处理部分(算菲薄拉契数列例子)

主代码


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">

    <title>Document</title>

    <script type="text/javascript">
        window.onload = function() {
            var btn = document.getElementById("btn");
            var num = document.getElementById("number");
            //  1 1 2 3

            btn.onclick = function() {
                // // alert("hello");
                // alert(cal(parseInt(num.value)));

                // 创建一个worker,并向他传递将在新线程中执行的脚本名
                var worker = new Worker("worker.js");
                // 向分线程发送消息
                worker.postMessage(num.value);

                // 接受worker传过来的数据函数
                worker.onmessage = function(event) {
                    console.log("主线程收到的数据" + event.data);
                }

            }
        }
    </script>
</head>

<body>
    <input type="text" id="number" placeholder="要计算的值">
    <button id="btn">计算菲薄拉起数列</button>

</body>

</html>

分线程代码

function cal(n) {
    return n <= 2 ? 1 : cal(n - 1) + cal(n - 2);
}


var onmessage = function(event) {
    console.log("分线程收到的数据", event.data);
    var tmp = cal(parseInt(event.data));

    //  将处理后的数据发送给主线程
    postMessage(tmp);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值