尝试解析js面试题(一)

作者: 小pxu | 来源:发表于2016-05-23 21:53 被阅读2069次

    说明:这是一道比较典型的综合考察js中作用域this指向对象解析顺序运算符优先级等概念的综合性考题;话不多说,先上题;

    原作者解析:小小沧海(博客园)

    function Foo() {
        getName = function () {
            alert (1); 
        };
        return this;
    }
    Foo.getName = function () {
        alert (2);
    };
    Foo.prototype.getName = function () {
        alert (3);
    };
    var getName = function () {
        alert (4);
    };
    function getName() {
        alert (5);
    }
    
    //请写出以下输出结果:
    Foo.getName();
    getName();
    Foo().getName();
    getName();
    new Foo.getName();
    new Foo().getName();
    new new Foo().getName();
    

    解析:

    1、Foo.getName(); //2

    1)结果执行的是Foo对象的一个叫做getName()的属性,而1、4、5中的getName都是作为函数存在,所以可以排除1、4、5

    2)剩下两个中,2是Foo对象自身的属性,3是Foo对象原型链上的属性,而自身属性的优先级高于原型链上的属性,所以执行结果是2

    2、getName(); //4

    1)结果执行的是getName函数,而题目代码中有3个相关函数,分别是1、4、5

    2)1中的getName是定义在Foo函数中的函数,由于Foo尚未执行,因此它没有暴露出来,无法被外部调用,可以排除

    3)4和5都可以被正常调用,关键在调用先后问题

    4)由于5是普通函数(优先级最高),4是匿名函数;js解析时会将5提前至最上方优先解析,而后面解析的4会将5覆盖,所以执行结果是4

    3、Foo().getName(); //1

    1)结果执行的是Foo函数,Foo函数中有个返回值是this;this被普通函数调用后,指向的对象一定是window对象,所以此处的结果已经可以解析为window.getName(),即调用getName()函数

    2)由于window.getName()已经被修改为1,所以执行结果是1(??)

    上面那句话是原作者的解释,此处还没理解透彻为什么1没有被2覆盖;下面举个例子对比下:

    //第一个例子是题目的类型,不明为何上边fn1的结果未被覆盖??
    function fn1 (){
        a = 1;
        return this
    }
    fn1()
    var a = 2
    console.log(fn1().a) //1
    
    //第二个例子是我理解的会正常出现覆盖的情况
    function fn1 (){
        a = 1;
    }
    fn1()
    var a = 2
    console.log(a) //2
    

    4、getName(); //1

    1)执行getName即是执行window.getName;所以执行结果同上题是1

    5、new Foo.getName(); //2

    1)此处考察到了运算符优先级的问题,就题目所需来看,成员访问".">new(带参数)>函数调用"()"(注意,"()"分为函数调用及优先运算两种,优先级是不同的;原作者开始的解释就出现了错误)

    2)结果先执行Foo.getName(),结果同第一题为2;而new 2不会有任何变化,因此这里的结果也是2

    6、new Foo().getName(); //3

    1)从结果来看,应该理解成(new Foo()).getName()这样执行

    2)根据成员访问".">new(带参数)>函数调用"()";成员访问优先执行,右侧是.getName()没问题

    3)左侧分为两种可能:一种是new(带参数),即(new Foo());此处结果是构建一个函数

    4)另一种是先执行Foo()函数后再将其结果new

    5)因为new(带参数)>函数调用"()",所以是执行的(new Foo()),此对象Foo()自身没有getName这个属性,所以会向上追溯其原型链上的属性,即在此处执行了3;因此结果是3

    //这里就是模拟new Foo()的结果
    function F(){return this}
    new F() //F {}
    

    关于这点,原作者有解释如下(还是可以理解的):

    构造函数的返回值

    在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。

    而在js中构造函数可以有返回值也可以没有。

    1、没有返回值则按照其他语言一样返回实例化对象。

    2、若有返回值则检查其返回值是否为引用类型。如果是非引用类型,如基本类型(string,number,boolean,null,undefined)则与无返回值相同,实际返回其实例化对象。

    3、若返回值是引用类型,则实际返回值为这个引用类型。

    原题中,返回的是this,而this在构造函数中本来就代表当前实例化对象,遂最终Foo函数返回实例化对象。

    7、new new Foo().getName(); //3

    1)这题我其实是懵逼的(懵逼脸😳)

    2)求高手指教了 _ (:з」∠)_

    还是贴下原作者解释,感觉有点不对

    第七问, new new Foo().getName(); 同样是运算符优先级问题。

    最终实际执行为:

    new ((new Foo()).getName)();

    先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new。

    遂最终结果为3


    最后,引用一张原作者提供的相当实用的运算符优先级表格(鼓掌)

    运算符优先级--博客园

    相关文章

      网友评论

        本文标题:尝试解析js面试题(一)

        本文链接:https://www.haomeiwen.com/subject/alzarttx.html