• [Python自学] day-16 (JS、作用域、DOM、事件)


    一、JS中的三种函数

    1.普通函数

    function func(){
        console.log("Hello World");
    }

    func()

    2.匿名函数

    setInterval(function(){
        console.log(123)
    },5000)

    中间的function()就是匿名函数。

    3.自运行函数

    (function(arg){
        console.log(arg)
    })(1)

    (1)是传递给arg的参数,该函数会在导入JS时自动执行。(可以用来作为容器,包含第三方库,避免命名冲突)

    二、序列化

    将一个对象转化为字符串形式:

    var li = [1,2,3,4,5];
    JSON.stringify(li);  //"[1,2,3,4,5]"

    将一个字符串转换为对象:

    var str = "[1,2,3,4,5]";
    JSON.parse(str);  //[1,2,3,4,5]

    三、URL转义

    当URL中出现特殊字符(包含中文、空格等),在存入cookie或写入磁盘时,需要将其转义。如下代码:

    url = "https://search.jd.com/Search?keyword=手机"
    newurl = encodeURI(url)  // "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA"

    反转义:

    url = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA";
    newurl = decodeURI(url);  // "https://search.jd.com/Search?keyword=手机"

    encodeURLComponent和decodeURLComponent:

    url = "https://search.jd.com/Search?keyword=手机";
    newurl = encodeURIComponent(url);  // "https%3A%2F%2Fsearch.jd.com%2FSearch%3Fkeyword%3D%E6%89%8B%E6%9C%BA"
    
    url = "https%3A%2F%2Fsearch.jd.com%2FSearch%3Fkeyword%3D%E6%89%8B%E6%9C%BA";
    newurl = decodeURIComponent(url);  // "https://search.jd.com/Search?keyword=手机"

    和encodeURL不同的是encodeURLComponent会将所有的其他符号,例如":" "/" "?"等转换为%n的形式。

    除了encodeURL 、encodeURLComponent意外,还有escape、unescape:

    url = "https://search.jd.com/Search?keyword=手机";
    escape(url);  //"https%3A//search.jd.com/Search%3Fkeyword%3D%u624B%u673A"
    url = "https%3A//search.jd.com/Search%3Fkeyword%3D%u624B%u673A";
    unescape(url);  //"https://search.jd.com/Search?keyword=手机"

    一样可以达到差不多的效果。

    四、JS中的eval

    在Python中我们学过两个可以通过字符串执行程序的函数,eval()和exec():

    Python中的eval,只能执行表达式,eval(表达式):

    val = eval("1+2")
    print(val)

    exec(执行代码):

    li = [1, 2, 3, 4, 5]
    
    loop = """
    for i in li:
        print(i)    
    """
    
    exec(loop)

    在JS中,eval()是Python中eval和exec的合体:

    val = eval("1+10")
    console.log(val)
    
    li = [1,2,3,4,5]
    eval("for(var i = 0;i<li.length;i++){console.log(li[i]);}")

    五、JS中的时间

    d = new Date()  //Fri Dec 06 2019 12:59:38 GMT+0800 (中国标准时间)

    获取年份、月份、日、时、分、秒:

    d.getFullYear();  // 2019年
    d.getYear();  // 119,返回的是2019-1900的值
    d.getMonth();  //注意月份总是少1,也就是12月获取到的是11
    d.getDate();  // 6 (12月6日)
    d.getDay();  // 5 (星期五)
    d.getHours();  // 13 (下午1点)
    d.getMinutes();  // 39 (39分)
    d.getSeconds();  // 50 (50s)

    修改时间属性:

    d.setFullYear(2022);  // 设置为2022年
    d.setMonth(3);  // 设置为4月
    d.setDate(23);  // 设置为23日
    ......

    六、JS的作用域(重要)

    1.首先看一下其他变成语言的作用域,例如C++、JAVA:

    void Func(){
        if(1 == 1){
            int age = 22;
        }
        cout<<age<<endl;   
    }

    Func(); //报错

    上述C++代码中,age实在if的作用域里面的,所以无法在if之外使用。

    总结:C++、C#、JAVA等变成语言的作用域是以大括号决定的。

    2.Python的作用域

    def func():
        if 1 == 1:
            age = 12
        print(age)
    
    
    func()  //正常执行

    Python的作用域是以函数为范围的,if判断是在func函数内部,所以与print是在一个作用域,只要在执行print时,age存在,则不会报错。

    3.JS的作用域

    JS的作用域与Python比较相似,也是以函数作为作用域的。

    function func() {
        if (1 == 1) {
            var name = "alex"
        }
        console.log(name);
    }
    
    func();  //正常运行

    4.JS中的作用域链

    当函数中定义函数时:

    // 全局变量
    myname = "jone";
    
    function func() {
        // func函数作用域中的局部变量
        var myname = "Tony";
    
        function inner() {
            // inner函数作用域中的局部变量
            var myname = "alex";
            console.log(myname);
        }
    
        inner();
    }
    
    func();

    inner函数执行时,首先会从自己函数内部查询是否存在myname变量,如果存在则直接打印。所以上述代码打印alex。

    如果inner函数内部不存在myname,则会查找上一层函数作用域中的myname,打印Tony。

    如果inner和func的作用域都没有myname,则会打印全局变量myname,打印jone。

    5.考虑下面特殊情况

    // 全局变量
    myname = "jone";
    
    function func() {
        // func函数作用域中的局部变量
        var myname = "Tony";
    
        function inner() {
            console.log(myname);
        }
    
        return inner;
    }
    
    ret = func();
    ret();

    如上述代码所示,我们在执行func()的时候,inner函数实际上是没有被执行的,func函数返回了inner函数对象,用ret接收。

    此时,我们运行ret(),相当于运行inner(),那么此时,inner中打印的myname是打印jone还是Tony???

    实验结果,打印Tony,为什么呢??

    答案是:在JS中,函数的作用域和作用域链都是在函数执行之前就已经建立了(也就是函数定义后,解释器解释到这个函数定义,并对其进行编译的时候)。所以,虽然这里的ret指向inner函数,看似处于func函数外部,但实际上作用域已经在之前就确定了,所以调用ret的时候,找myname还是在func函数内部找。

    6.变量覆盖的情况

    function func() {
        // func函数作用域中的局部变量
        var myname = "Tony";
    
        function inner() {
            console.log(myname);
        }
        var myname = "Leo";
    
        return inner;
    }
    
    ret = func();
    ret();

    我们可以看到在inner函数后面,我们重新定义了myname,这里的myname实际上覆盖了前面的Tony(这个过程是在确定作用域的时候就覆盖了)。多以当我们执行ret的时候,func作用域中的myname就是Leo,所以ret会输出Leo。

    7.变量的提前声明

    在JS中如果直接调用未定义的变量会报错:

    function func(){
        console.log(myage);
    }

    但是如果在func函数中存在myage的定义(可能在console.log之后):

    function func(){
        console.log(myage);  // 这里打印undefined
        var myage = 22;
    }

    console.log(myage)打印undefined。

    这是因为当解释器在生成作用域时,会检查一个函数作用域中所有的变量,然后在前面自动声明一下该变量,类似于:

    function func(){
        var myage;
        console.log(myage);
        var myage = 22;
    }

    代码中,var myage;就是声明了变量myage,但没有赋值,此时打印该变量就是undefined。这就叫做变量的提前声明。

    七、JS的面向对象

    // 定义一个JS类
    function Foo(){
        this.name = "Leo";
        this.printName = function(){
            console.log(this.name);
        }
    }
    
    //创建一个Foo实例对象
    f = new Foo();
    f.printName();

    从上述代码中可以看到,JS中类的定义和函数定义很相似,不同的是变量使用this,这里的this就相当于Python中的self,他指向对象本身(Foo创建出的对象)。

    在上述代码中,如果我们创建多个实例对象,每个对象除了有自己的this.name属性以外,在内存空间中各自还有一份this.printName代码。所以这是不合理的。我们改写一下:

    // 定义一个JS类
    function Foo(arg) {
        this.name = arg;
    }
    // 定义Foo的原型(原型只会定义一次)
    Foo.prototype = {
        'printName': function () {
            console.log(this.name);
        }
    }
    
    //创建两个Foo实例对象
    f1 = new Foo("Alex");
    f2 = new Foo("Leo");
    f1.printName();
    f2.printName();

    使用定义Foo的原型,来将成员方法定义成一份(存放于类的一个单独空间,而不是每个对象中)。

    总结:JS的面向对象中,我们只要看到方法中的变量用this.来开头,就表示这个函数定义的是一个类,并且这个函数可以认为是该类的构造函数。然后所有的成员方法都定义到类的原型中。

    八、DOM

    DOM中对标签的查找,参照 https://www.cnblogs.com/leokale-zz/p/10314031.html

    innerText和innerHTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <div id = 'd1'>
            <a id = "a1">Hello</a>
            <a id = 'a2'>World</a>
        </div>
    
        <script>
            d1 = document.getElementById("d1");
            console.log(d1.innerText);
            console.log(d1.innerHTML);
        </script>
    </body>
    </html>

    得到的输出结果:

    Hello World
    
            <a id="a1">Hello</a>
            <a id="a2">World</a>

    可以看出innerText会将所有的HTML标签全部屏蔽掉,只打印div中的所有文本信息。而innerHTML就打印div下的所有标签和内容。

    修改innerText内容:

    a1 = document.getElementById("a1");
    a1.innerText = "Hi";

    页面上显示"Hi World"

    修改innerHTML内容:

    d1 = document.getElementById("d1");
    d1.innerHTML = "<a href='http://www.baidu.com'>BAIDU</a>";

    页面显示BAIDU超链接。

    用value来获取Input类控件的值:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <div>
            <input id='in1' type="text" value = 'Leo'/>
        </div>
    
        <script>
            in1 = document.getElementById('in1');
            in1.value = 'Kale';
        </script>
    </body>
    </html>

    这样,就将文本框中的值从'Leo'修改为了'Kale'。

    使用value来取select控件的值:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <select id = "sele1">
            <option value="11">成都</option>
            <option value="12">简阳</option>
            <option value="13" selected="selected">青白江</option>
            <option value="14">新都</option>
        </select>
        <script>
            sele1 = document.getElementById('sele1');
            console.log(sele1.value);
        </script>
    </body>
    </html>

    "青白江"是默认被选中的,所以在console中打印13。我们就可以通过该取到的值来判断控件选中的是哪个选项。

    select标签还有一个特殊的selectedIndex值,表示当前选中的选项的index:

    sele1 = document.getElementById('sele1');
    console.log(sele1.selectedIndex);

    默认是"青白江",对应的index为2(从0开始),也就是第三个。

    value获取textarea控件的值:

    <textarea id = 'ta1'>my name is leo</textarea>
    <script>
        ta1 = document.getElementById('ta1');
        console.log(ta1.value);
    </script>

    对于textarea来说,他的value的值是写在标间之间的。

    九、DOM样式操作

     我们在JS中通过DOM可以操作标签的样式。

    1.通过className操作

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
        <style>
            .c1{
                color: red;
            }
            .c2{
                background-color: gray;
            }
        </style>
    </head>
    <body>
        <textarea id = 'ta1'>my name is leo</textarea>
        <script>
            obj = document.getElementById('ta1');
            obj.className = "c1";
        </script>
    </body>
    </html>

    通过obj.className = 'c1'将textarea中文本的样色设置为红色。

    效果如下:

    2.通过classList设置多个style:

    obj = document.getElementById('ta1');
    obj.classList.add("c1");
    obj.classList.add("c2");

    效果:

    剔除classList中的样式:

    obj.classList.remove("c2");

    3.通过style直接操作样式细节

    obj = document.getElementById('ta1');
    obj.style.backgroundColor = 'pink';
    obj.style.color = 'blue';

    效果如下:

    注意,在html和css中,background-color是用"-"隔开的,而在JS中,我们要将其变为backgroundColor,这是个规律。

    十、DOM属性操作

    DOM对标签的属性进行操作:

    obj = document.getElementById('ta1');
    obj.setAttribute('myname', 'Leo');  //<textarea id = 'ta1' myname = 'Leo'>my name is leo</textarea>
    obj.removeAttribute('myname'); // <textarea id="ta1">my name is leo</textarea>
    obj.attributes;  // NamedNodeMap {0: id, 1: myname, id: id, myname: myname, length: 2}

    十一、JS动态添加标签

    在标签内部动态添加其他标签:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <!-- "+"按钮,点一下,添加一个input框 -->
        <input type="button" value="+" onclick="addTag();"/>
        <div id='d1'>
            <p><input type="text"/></p>
            <!-- 点击"+"按钮,就在这里添加一个 <p><input type="text"/></p>  -->
        </div>
        <script>
            function addTag() {
                var obj = document.getElementById('d1');
                var tag = "<p><input type="text" /></p>";
                obj.insertAdjacentHTML("beforeEnd", tag);
            }
        </script>
    </body>
    </html>

    效果:

    注意,obj.insertAdjacentHTML("beforeEnd",tag),这里的参数有4种:

    beforeBegin、beforeEnd、afterBegin、afterEnd。

    分别表示:该标签的前面(外部)、该标签的最后(内部)、该标签的最前面(内部)、该标签的后面(外部)。

    在上面代码中,我们向div中动态添加的tag是用字符串形式给出的。我们也可以使用DOM来生成标签:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <!-- "+"按钮,点一下,添加一个input框 -->
        <input type="button" value="+" onclick="createAndAddTag();"/>
        <div id='d1'>
            <p><input type="text"/></p>
            <!-- 点击"+"按钮,就在这里添加一个 <p><input type="text"/></p>  -->
        </div>
        <script>
            function createAndAddTag(){
                var ptag = document.createElement("p");
                var tag = document.createElement("input");
                tag.setAttribute('type','text');
                ptag.appendChild(tag)
                var obj = document.getElementById('d1');
                obj.appendChild(ptag);
            }
        </script>
    </body>
    </html>

    效果和使用字符串是一样的,但要注意这种方式添加标签要使用obj.appendChild(),因为在这里tag是对象

    十二、利用DOM提交表单

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <form id="form1" action="http://www.baidu.com">
            <input type = "text" />
            <input type="submit" value="提交"/>
            <a onclick="submitForm();">提交</a>
        </form>
        
        <script>
            // 点击a标签,出发该函数
            function submitForm(){
                obj = document.getElementById('form1');
                obj.submit();
            }
        </script>
    </body>
    </html>

    上述代码通过<a>标签实现了表单的提交,功能和点击提交按钮是一样的,除了<a>标签,任何标签都可以通过JS来实现submit功能。

    十三、信息提示

    console.log():打印在浏览器F12的console中。

    <body>
        <input type="button" value="输出" onclick="printMsg();"/>
        <script>
            function printMsg(){
                console.log("print on console")
            }
        </script>
    </body>

    alert():在页面中弹出警告框。

    <body>
        <input type="button" value="输出" onclick="printMsg();"/>
        <script>
            function printMsg(){
                alert("This is a alert window!")
            }
        </script>
    </body>

    confirm():弹出一个确认框。

    <body>
        <input type="button" value="输出" onclick="printMsg();"/>
        <script>
            function printMsg(){
                var ret = confirm("Are you sure?");
                console.log(ret);
            }
        </script>
    </body>

    当我们选择确定时,返回值ret为true,点击取消时,返回值是false。

    十四、JS获取当前URL并实现跳转

    <body>
        <input type="button" value="打印当前URL" onclick="printURL();"/>
        <input type="button" value="跳转到百度" onclick="jumpBaidu();"/>
        <script>
            // 打印当前URL到console中
            function printURL(){
                var url = location.href;
                console.log(url);
            }
            // 修改当前URL,即跳转到指定的URL
            function jumpBaidu(){
                location.href = "http://www.baidu.com";
            }
        </script>
    </body>

    如果点击"跳转到百度",浏览器则会直接跳转到baidu首页:

    页面刷新:

    <body>
        <input type="button" value="页面刷新" onclick="refreshPage();"/>
        <script>
            function refreshPage(){
                location.reload(); // 相当于 location.href = location.href;
            }
        </script>
    </body>

    十五、定时器

    使用setInterval()设置定时循环执行:

    <body>
        <input type="button" value="开始执行" onclick="startLoop();"/>
        <input type="button" value="结束" onclick="endLoop();"/>
        <script>
            function startLoop(){
                // 开始1s打印一个Hello
                obj = setInterval(function(){
                    console.log("Hello");
                },1000)
            }
            function endLoop(){
                clearInterval(obj);
            }
        </script>
    </body>

    点击开始执行按钮,则开始循环在console中打印Hello。点击停止按钮,则停止循环打印。

    使用clearInterval来清楚定时器。

    只执行一次的定时器:

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

    打开页面后(出发这个函数),等待5s,会在console中打印timeout字符串。

    该函数主要用于一些需要延迟处理的效果,例如QQ邮箱删除邮件后,会给你5秒钟的时间来撤销,5秒之后,撤销提示就会消失,就是使用这种方式来实现的。

    同样的,使用setTimeout来设置定时器,也可以使用clearTimeout来清除定时器(在等待时间完之前,否则就没意义了)。

    十六、事件

    事件就是我们为一个控件加上的行为,例如点击、光标、鼠标悬停等。

    具体的事件,可以参照 HTML事件属性

    我们在写前段代码的时候,尽量将代码写成 行为 样式 结构 相分离的形式

    什么叫行为、样式、结构相分离??

    就是在html标签中,我们不要使用style属性设置样式(css样式),不要使用onclick等属性设置事件(行为)。这样就将css、JS、HTML分离了。

    例子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
    </head>
    <body>
        <div style="background-color: red;" onclick="f1();">Hello</div>
        <script>
            function f1(){
                console.log("This is function f1().");
            }
        </script>
    </body>
    </html>

    上述代码就是行为、样式、结构没有分离的形式,在业界被称为DOM0,是比较low的形式。

    我们将其修改为行为、样式、结构相分离的形式:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
        <style>
            #div1{
                background-color: red;
            }
        </style>
    </head>
    <body>
        <div id="div1">Hello</div>
        <script>
            var d1 = document.getElementById('div1');
            d1.onclick = function(){
                console.log("This is onclick function.");
            }
        </script>
    </body>
    </html>

    这样的好处是什么?

    当HTML中有大量的标签需要添加事件,我们无需在每个标签中添加事件属性。例如表格,表格中有大量的标签,而且可以规律的获取(循环index),如果表格中每一个格子td都需要一个事件,那么我们就可以采用这种方式:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test1</title>
        <style>
            #tb,td{
                border: 1px solid black;
            }
            #tb td{
                width: 100px;
            }
        </style>
    </head>
    <body>
        <table id="tb">
                <tr><td>1</td><td>2</td><td>3</td></tr>
                <tr><td>1</td><td>2</td><td>3</td></tr>
                <tr><td>1</td><td>2</td><td>3</td></tr>
        </table>
        <script>
            var trs = document.getElementsByTagName('tr');
    
            for(var i = 0;i<trs.length;i++){
                var tds = trs[i].children;
                console.log(tds);
                for(var k = 0;k<tds.length;k++){
                    var td = tds[k];
                    td.onmouseover = function () {
                        this.style.backgroundColor = "red";
                    }
                    td.onmouseout = function () {
                        this.style.backgroundColor = "";
                    }
                }
            }
        </script>
    </body>
    </html>

    上述代码事件了,为每一个td添加一个onmouseover和onmouseout事件。

    特别注意:在事件函数中,我们使用this.style.backgroundColor来设置样式,这里this代表调用这个事件函数的对象,当我们的鼠标移到某个td上时,就是这个td调用的这个函数。

    这里一定注意,this不能替换为td,因为在循环绑定事件的时候,这个匿名函数是没被执行的,当循环到最后一个td时,这个function就变成了 最后的td.style.backgroundColor = "red"。那么在以后触发事件,调用该函数的时候,一直都是最后一个td发生样式的变化,和初衷违背。

    记住:谁调用事件,this就是谁。。。

    十七、事件的三种绑定方式

    这里聊一下三种绑定方式中的this。

    第一种(DOM0不推荐):

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test2</title>
    </head>
    <body>
        <input type="button" value="点击" onclick="clickOn(this);" />
        <script>
            function clickOn(ths){
                //这是的参数ths,就是通过onClick传递过来的this,this代表当前被点击的按钮
                ths.style.backgroundColor = "green";
            }
        </script>
    </body>
    </html>

    第二种(DOM1推荐):

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test2</title>
    </head>
    <body>
        <input id="ipt1" type="button" value="点击" />
        <script>
             var ipt1 = document.getElementById("ipt1");
             ipt1.onclick = function(){
                 this.style.backgroundColor='red';
             }
        </script>
    </body>
    </html>

    这种通过DOM来给标签绑定事件的方式,匿名函数中的this就直接代表当前动作标签。

    第三种(DOM2比较高级):

    这种绑定方式可以为一个标签同时绑定多个事件(事件可以相同)。

    <body>
        <input id="ipt1" type="button" value="点击" />
        <script>
             var ipt1 = document.getElementById("ipt1");
             ipt1.addEventListener("click",function(){console.log("aaa")},false);
             ipt1.addEventListener("click",function(){console.log("bbb")},false);
        </script>
    </body>

    可以看到,我们为按钮绑定了2个click事件,也就是说,我们在点击按钮时,console中会同时打印aaa和bbb。

    在addEventListener函数中,第一个参数是事件的类型,第二个参数是绑定的函数,第三个参数是模式(分为捕捉型true和冒泡型false)。

    捕捉型和冒泡型:

    捕捉型就是从最上层先触发事件,然后依次往下。冒泡型就是从底层标签开始触发事件,依次往上。例如:

    <head>
        <meta charset="UTF-8">
        <title>test2</title>
        <style>
            #d1{
                background-color: red;
                width: 300px;
                height: 400px;
            }
            #d2{
                background-color: pink;
                width: 150px;
                height: 200px;
            }
        </style>
    </head>
    <body>
        <div id="d1">
            <div id="d2"></div>
        </div>
        <script>
             var div1 = document.getElementById("d1");
             var div2 = document.getElementById("d2");
             div1.addEventListener("click",function(){console.log("div1")},false);
             div2.addEventListener("click",function(){console.log("div2")},false);
        </script>
    </body>

    上述代码中,div1中有div2,div2属于底层标签,div1是上层标签。如下图,粉色为div2,红色为div1。

    当我们第三个参数使用false时,我们点击粉色部分(粉色部分是重叠的),这里先打印div2,后打印div1。

    当我们第三个参数使用true时,我们点击粉色部分(粉色部分是重叠的),这里先打印div1,后打印div2。

    十八、JS的词法分析(重要理论)

    函数在定义的时候解释器会对其进行词法分析,分析的时候会由一个active object(AO)来记录函数中有哪些变量,例如形参、实参、局部变量、函数声明表达式等。

    例如:

        <script>
             function func1(age){
                 console.log(age);
                 var age = 27;
                 console.log(age);
                 function age(){}
                 console.log(age);
             }
             func1(3);
        </script>

    我们来看看func1的词法分析过程:

    1.AO分析形参,发现有一个形参age,所以AO.age == undefined

    2.AO分析实参,发现实参为3,所以AO.age == 3

    3.AO分析局部变量,发现有一个age,但是函数未运行,无法赋值27,所以AO.age == undefined (这里覆盖了前面的AO.age==3)

    4.AO分析函数声明表达式,发现有一个age(),所以AO.age==function age()

    5.分析完毕后,函数开始执行

    6.执行时遇到第一个console.log(age),所以打印f age(){}

    7.然后遇到age赋值27,所以AO.age ==27

    8.再遇到第二个console.log(age),所以打印27

    9.跳过函数声明

    10.遇到第三个console.log(age),所以还是打印27

    最终在console的打印结果为:

    我们再用此理论分析之前的一个简单例子:

    function func2(){
        console.log(name);
        var name='alex';
    }
    func2();

    分析过程:

    1.AO发现没有形参,也没有实参。

    2.AO发现局部变量name,但这个阶段是布管值的,所以AO.name == undefined

    3.函数执行

    4.遇到console.log(name),所以打印undefined

    5.遇到局部变量赋值,AO.name == "alex"

  • 相关阅读:
    1434. Buses in Vasyuki 夜
    SAP
    目标
    组合数
    KM算法模板
    网络流
    CodeForces 43E
    B. Unsorting Array codeforces 127
    Colorful Rainbows 127
    C. Anagram codeforces
  • 原文地址:https://www.cnblogs.com/leokale-zz/p/11994121.html
Copyright © 2020-2023  润新知