• Day14-JS进阶-


    一、回调函数

    二、IIFE

    三、函数中的this

    四、关于语句分号问题

    五、原型与原型链

    六、探索instanceof

    七、执行上下文

    八、作用域与作用域链

    一、回调函数

     

    二、IIFE(立即调用函数表达式)

     也可用于编写 js 模块

      var a = function (){
                console.log("a");
            }
            function b(){
                console.log("b");
            }
            (function c(){ //匿名函数自调用这个和IIFE其实是同一个概念的
                console.log("c");
            })()

    最后打印出来的 只有 c

    那就有一个疑惑了,为什么不能直接把这个匿名函数的内部代码直接在外面写了,而是要用这个“包”起来呢?

    因为包起来的话,就是一个局部了,里面的变量就是一个局部变量,不会影响全局变量

    (function d(){
                var a = 1;
                function test(){
                    console.log(++a);
                }
                 function test2(){
                    console.log("test2");
                }
                window.$ = function(){
                    return {
                        test: test
                    }
                }
            })();
    
            $().test()

    这种的话,就是把test向外暴露了,暴露为一个全局函数,但是test2没暴露出来,这也是匿名函数的一个功能了

    其中不要被$里面了,在匿名函数d中,我们给这个$定义了一个函数,$其实就是一个函数,这个函数执行之后,就会返回一个对象

    这个对象的名字叫做test,然后就可以通过test()来调用这个test函数了

    三、函数中的this 

    扩展:函数call

    https://www.w3school.com.cn/js/js_function_call.asp

    <script>
            //函数外面全局的this就是window
            function Person(color){
                console.log(this);//这个this不是Person,它代表的是谁来调用这个Person
                this.color = color;
                this.getColor = function(){
                    console.log(this);
                    return this.color;
                };
                this.setColor = function(color){
                    console.log(this);
                    this.color = color;
                };
            }
            Person("red"); //这个时候就输出语句一个,this是window,因为没人调用,就是用window直接调用了
            var p = new Person("yello");//这个时候的this 是 Person,也可以说是p,因为p指向这个对象
    
            p.getColor();//这个时候的this 是 p
    
            var obj = {};
            p.setColor.call(obj , "black");//这里的this是obj,把obj打印出来就是一个对象,有一个color属性值为black
            // console.log(obj);
    
            var test = p.setColor;
            test();//这个时候的this是 window,因为test是一个函数,没东西调用,就是window调用
            //全局调用的话this都是window
    
            function fun1(){
                function fun2(){
                    console.log(this);
                }
                fun2();//this是window
            }
            fun1();
        </script>

    四、关于语句分号问题

     

     一般在做项目的时候,如果用到很多js文件的话,都是在这个文件开始的时候添加上一个分号,防止代码合并的时候会出错的

    五、原型与原型链

      1、原型prototype

    下面是打印 Date.prototype 的结果

     可以看到是一个object类型的,然后里面有很多内置的方法,这些方法都是给实例对象使用的

     如果是这样打印的话,就是一个龙的object,但是我们可以人工的给这个函数原型添加方法

     

     

     ②

     返回了两个 true

     也就是说构造函数和它的原型对象是有一种相互引用的关系,也就是构造函数的一个叫做prototype的属性可以找到这个构造函数的原型

    并且这个构造函数的原型里面也有一个属性 叫做 constructor 可以找到这个构造函数本身

    2、显示原型和隐式原型

    <script>
            function Fn(){
    
            };
            console.log(Fn.prototype);
            var fn = new Fn();
            console.log(fn.__proto__);

     

     原因就是第三句话,要验证的话,直接用===来判断即可,prototype和__proto__共同指向原型对象,都是引用值,保存 地址值的

    函数的prototype这个属性是在函数创建的时候就写入了,而__proto__这个属性是在实例对象创建的时候生成的-new的时候(都是js引擎自动帮我们加的)

    new Fn()也就是这个创建这个函数对象的时候,内部执行了一个赋值就是把这个函数的prototype属性的值赋值给了这个实例对象的__proto__属性的值

    function Fn(){}的时候就是一个创建函数对象的时候,就是给了这个函数的prototype属性赋值为了一个空的object

    这个图的左边是一个栈,右边是堆

    1、function Fn(){} 定义了一个函数对象(放在堆里面),然后这个函数名Fn放在栈空间里面

     其中Fn:0x123,表示的是他存了一个值(地址值)是ox123,也就是说在堆中这个函数对象的地址就是0x123

    prototype是一个引用变量属性,他的值是地址值,他指向的是一个原型对象 { }

    ===第一条语句 执行之后,绘制的图是 

     

     2、console.log(Fn.prototype)输出的就是这个对象了

     3、 var fn= new Fn()这个fn也是一个引用类型,在栈中fn的值就是一个地址值了

    4、最后的fn.test其实是,以为fn.的话有一个点,就会找到Fn实例对象:

     但是这个对象里面没有这个test方法,但是最终还是找到了,所以说它的原理就是

    如果在 fn 。也就是实例对象中找不到这个方法的话,就会根据这个实例对象的
    __proto__属性来找到原型对象object,再在这个原型对象里面找这个test方法

     5、原型链

     即使是后面才给这个函数添加test2方法的,但是在那之前就打印出来了,因为我们拿到的是最总的函数)

    这个空的Object也是object的一个原型

    Object本身就是存在的,并且是全局的,一开始就有的,

    先有了原型才有实例对象

    1、第一个语句 

    function Fn(){

    this.test1 = function() {

    console.log("test1()")

    }

    这个语句 就画了下面这个图片了

     上面的Object 那三个图,都是一上来就有的所以js引擎一开始的时候是把js内置的一些函数和方法加载进来了

     

    补充:

    4、原型链-属性问题

    ==前面都是给这个函数添加方法,1这里就是给这个函数添加属性

     这两个输出的都是 xxx ,但是打印fn2.a的时候就会显示yyy了

    ===为什么后面通过 fn2.a=‘yyy’没有把前面的xxx覆盖掉了呢

    我们把修改之后的fn2打印可以看到

     自身多了一个a属性,然后原型也有一个a属性的

    注意:原型链是在查找的时候用到的,但是在设置原型链的时候是不看的

     六、探索instanceof

     

     如果是B的话就走一部,也就是找prototype的显示原型属性,如果是a的话就可以走很多步,但是每一步都要走隐式原型属性的__proto__

     

    面试题:

     它的思路是,先生成了一个 n==2,m==3的对象,之后再赋值给a的原型的,并不是直接修改原来a原型指向的东西

    因为a的原型保存的是地址值,所以就不是一个东西了,因为地址改变了,指向就不同了4

     所以结果就是:b.n==1 b.m=undefined    c.n==2 c.m==3

    第一个f.a可以和object本身就有的 toString 方法类比,因为直接对了object的原型添加了方法和属性,那么f就可以直接访问它们了

    这个a属性和tostring是放在一个容器里面的

     

     这个就是打印出来的f,也就是原型链了,因为找到proto的时候是找到了这个F函数,但是里面没有a,所以再找下一个proto就找到了Object的原型,就可以找到a这个属性了

    但是f.b是找不到的,就会报错了

     

     

     上面这个部分就比较重要了

     

     其中的除了 f.b()是会报错之外(因为找不到这个属性),其他的都是可以执行打印出来的

    七、执行上下文

    执行上下文栈

     这个代码其实是没问题的,

    因为在bar里面的调用f00的时候,其实下面的foo函数定义已经执行了,因为函数定义执行并不待变前面的foo的调用已经执行了

     就是前面的bar和foo是两条赋值语句,并不代表函数就执行了,最后面才调用了bar函数的

    在上面那个函数中 产生了三个执行上下文对象,一个是window作为全局执行上下文 两个函数对象function

    (函数被调用的时候就会产生函数执行上下文对象,定义的时候是没有产生的)

    也就是

     这两个语句执行的时候,就会产生函数的执行上下文了

    所以执行上下文栈中的话,就是n+1层,其中n就是函数被执行的语句(调用函数的次数),1就是window产生的全局执行上希望了

    同理:

     如果代码是这样的话,执行上下文栈中就有5层了,因为一个bar调用然后引发一个foo调用,两个bar的话,就有4词被调用了,再加上wondow全局调用

     

    一个函数被调用,就会在执行上下文栈中添加,然后执行完了之后,就会出栈的了,就被释放出来了(正在执行的都是栈顶的对象的)

    也就是说全部的代码都执行完了之后, 执行上下文栈中留下的就只有 window了

    那么栈底有没有可能不是window呢?--不可能,因为第一个产生的就是window(全局执行上下文和当前执行上下文均只能由一个,其他都是要进行等待的了)

    (小扩展)如果用f1里面调用f2和f3的话,执行上下文栈中最多由三个执行上下文,因为在f1中调用f2的时候,不会调用f3,当执行晚了f2之后才会调用f3,所以同时最多的话只能是3个了

    面试题:

    面试题:

    1、

     输出的要么是undefined 要么就是 function==这里就涉及到了变量提升和函数提升顺序了

    ====先执行变量提升,再执行函数提升

    所以最终打印出来的就是 function 了

    2、

     在就涉及到,在if之前对b进行了声明定义,还是在先if再对b声明了

      实际上的代码实现是这样的

    所以说就会报错了,因为c不是函数来的,(先是变量提升之后才是函数提升)

     也就是c是变量了,c(2)的话就会报错了,也就是说 定义的函数c里面的代码都是没有执行的

    八、作用域与作用域链

    1、块作用域就是在 大括号里面的作用域了

     这里有几个作用域呢?

    外面的全局作用域+定义了几个函数

     注意:

     这里的b其实,会打印20的,因为b是全局的,在里面也是可以访问到的

    因为b是先在这个函数里面找的,如果没有的话,就去外面找的

    2、作用域 与 执行上下文

     

     作用域链 就是嵌套的作用域 由内向外的一个过程

    相关面试题:

     打印出来的答案 是 10

    因为相当于是直接调用了fn,也就是要在fn里面找有没有x,如果没有的话,就在外部作用域里面找了,(注意 并不是在show函数里面执行,而是会回到上面的fn作用域中执行的)

    面试题二:

    如果是输出fn的话,就会吧赋值给fn的这个函数打印出来了

    在输出fn2的时候,开始在函数里面找不到,所以在外部作用域里面找,想要找到fn2的话,就是要找obj这个对象里面找才行,也就是this.fn2才行

    所以在外面是找不到的

     就是在沿着作用域找的时候没找到

    但是如果打印this的话就可以找到了

  • 相关阅读:
    网页表单项Input的高级限制级用法
    程序员从初级到中级10个秘诀
    AspNet2.0页面生命周期(转载)
    WebService大讲堂之Axis2(4):二进制文件传输
    WebService大讲堂之Axis2(9):编写Axis2模块(Module)
    WebService大讲堂之Axis2(7):将Spring的装配JavaBean发布成WebService
    WebService大讲堂之Axis2(10):使用soapmonitor模块监视soap请求与响应消息
    WebService大讲堂之Axis2(5):会话(Session)管理
    lucence(补)
    WebService大讲堂之Axis2(6):跨服务会话(Session)管理
  • 原文地址:https://www.cnblogs.com/SCAU-gogocj/p/13220085.html
Copyright © 2020-2023  润新知