javascript关于函数声明和函数表达式的一道题?解释一下为什么?

查看:98
本文介绍了javascript关于函数声明和函数表达式的一道题?解释一下为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

function Foo() {
    getName = function () { console.log (1); };
    return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}

//以下输出值为多少?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

解析一下为什么?

解决方案

 1        function Foo() {
 2            getName = function () { console.log (1); };
 3            return this;
 4        }
 5        Foo.getName = function () { console.log (2);};
 6        Foo.prototype.getName = function () { console.log (3);};
 7        var getName = function () { console.log (4);};
 8        function getName() { console.log (5);}
 9
10        //以下输出值为多少?
11        Foo.getName(); 
12        getName();
13        Foo().getName();
14        getName();
15        new Foo.getName();
16        new Foo().getName();
17        new new Foo().getName();

浏览器执行Js程序的时候,分两步:

(1)预解析
    在代码解读之前发生,相当于一个"仓库",放一些东西,比如var、function、参数等。
    预解析时变量都是未定义的,函数则是整个函数块。
    预解析时遇到重名的,会覆盖。变量与函数,留函数;函数与函数,留后面解析的。
    当代码在一个环境中执行时,会创建变量对象的一个作用域链。是域就要预解析。

(2)执行代码
    代码自上而下,从左往右的执行,读到表达式时,预解析仓库中的东西发生改变。

我们来分析题目
先预解析,预解析仓库里有:

注意预解析时getName重名了,留函数。

function Foo() {
    getName = function () { console.log (1); };
    return this;
}
function getName() { console.log (5);}

执行代码:

        注意下面这个:
        function fn(){console.log(1)}
        console.log(fn())  //  2  
        function fn(){console.log(2)}

前4行由于是函数声明,所以没卵用
第5行:给Foo对象添加getName方法
第6行:给Foo的原型对象添加getName方法
第7行: *注意*遇到了表达式,域解析仓库中getName变为第7行的赋值语句
    此时预解析仓库变为:
        function Foo() {
            getName = function () { console.log (1); };
            return this;
        }
        getName = function () { console.log (4);};
第8行:*注意*由于是函数声明,所以不影响预解析仓库

下面我们来分析这几个题:

Foo.getName(); //2 
    相当于执行第5行的console
    
getName(); //4
    预解析里直接取,相当于执行第7行的console
    
Foo().getName(); // 1
    Foo执行了,函数内部发生预解析,然而内部预解析仓库里什么都没有。
    执行函数Foo,第2行是个表达式,影响外面的预解析仓库,外面的预解析仓库变为:
        function Foo() {
            getName = function () { console.log (1); };
            return this;
        }
        getName = function () { console.log (1); };
    然后返回this,由于Foo()相当于window.Foo(),所以this指向window,
    Foo().getName()相当于window.getName(),window作用域下一切变量都可以看作他的属性,
    相当于执行第2行的console
    
getName(); //1
    跟window.getName()一样,
    当于执行第2行的console
    
new Foo.getName(); // 2
    执行第5行的Foo.getName(),

    new操作符调用构造函数创建对象的步骤?
    (1)创建一个新对象;
    (2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
    (3)执行构造函数中的代码(为这个新对象添加属性)
    (4)返回新对象

    new操作符是要执行构造函数中的代码的,打印2
    执行第5行的console

new Foo().getName(); // 3
    Foo()执行返回this,此时this指向new出来的新实例对象,
    实例对象从本身找不到getName属性,顺着原型链找到第6行的getName,打印3
    执行第6行console

new new Foo().getName(); // 3
    以实例的getName方法为构造函数new实例,执行构造函数,打印3
    执行第6行

这题不错,欢迎指正。

这篇关于javascript关于函数声明和函数表达式的一道题?解释一下为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆