zoukankan      html  css  js  c++  java
  • 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的话就可以找到了

  • 相关阅读:
    sfs2x 连接 mongodb
    java websocket
    webstorm 4.0 注册码
    解决 sfs2 admin tool 找不到扩展
    window 注册表五大类
    opengl 学习第二日
    java google Protobuf
    扩展 java sencha touch PhonegapPlugin
    sencha touch2 kryonet socket phonegap 通信 作者:围城
    sencha touch2 layout 笔记
  • 原文地址:https://www.cnblogs.com/SCAU-gogocj/p/13220085.html
Copyright © 2011-2022 走看看