美文网首页
2021-05-08 原型经典面试题Foo和Foo.getNam

2021-05-08 原型经典面试题Foo和Foo.getNam

作者: 半眼鱼 | 来源:发表于2021-07-27 22:05 被阅读0次

    题目

    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()//2
    getName()//4
    Foo().getName()//1 
    getName()//1
    new Foo.getName()//2
    new Foo().getName()//3
    new new Foo().getName()//3      
    
    //变量提升后
    function Foo(){
       getName=function(){
         console.log(1)
       }
       return this;
     }
     var getName;
     function getName(){console.log(5)}
     Foo.getName=function(){console.log(2)}
     Foo.prototype.getName=function(){console.log(3)}
     getName=function(){console.log(4)}
     //输出结果
     Foo.getName()//2
     getName()//4
     Foo().getName()//1 
     getName()//1
     new Foo.getName()//2
     new Foo().getName()//3
     new new Foo().getName()//3 
    

    运行结果

    image

    解释

    1、 Foo.getName()
    为什么输出2,不是3?这就得说说构造函数的静态属性与实例属性。 我们都知道函数属于对象,而对象拥有可以自由添加属性的特性,函数也不例外,构造函数也是函数:

    function Fn() {};
    Fn.person = '听风是风';
    Fn.sayName = function () {
        console.log(this.person);
    };
    Fn.sayName(); // 听风是风
    

    比如这个例子中,我为构造函数Fn添加了静态属性person与静态方法sayName,我们可以通过构造函数Fn直接访问。在JS中,我们将绑定在构造函数自身上的属性方法称为静态成员,静态成员可通过构造函数自身访问,而实例无法访问。

    let people = new Fn();
    people.sayName();// 报错,实例无法访问构造函数的静态属性/方法
    

    那有什么属性是实例可以访问而构造函数自身无法访问的呢,当然有,比如实例属性。这里我将实例属性细分为构造器属性与原型属性两种,看下面的例子:

    function Fn() {
        // 构造器属性
        this.name = '听风是风';
        this.age = 26;
    };
    // 原型属性
    Fn.prototype.sayName = function () {
        console.log(this.name);
    };
    let people = new Fn();
    people.sayName(); // 听风是风
    

    2、 getName()
    这里考的是变量提升与函数声明提升 ,function getName()变量提升,声明后被 getName= function(){...}覆盖,输出4

    3、 Foo().getName()

    getName是全局变量,所以在函数Foo内也能直接访问,于是getName被修改成了输出1的函数,之后返回了一个this。

    由于Foo().getName()等同于window.Foo().getName(),所以this指向window,这里返回的this其实就是window。

    4、 getName()
    这里输出1已经毫无悬念,上一分析中,getName的值在Foo执行时被修改了,所以再调用getName一样等同于window.getName(),同样是输出1。

    5、 new Foo.getName()
    等价于new (Foo.getName()),在分析一中我们已经知道了Foo.getName是Foo的静态方法,这里的getName虽然是Foo的静态方法,但是既没有继承Foo的原型,自身内部也没提供任何构造器属性(this.name这样的),所以new这个静态方法只能得到一个空属性的实例。
    因此这里new的过程就相当于单纯把Foo.getName执行了一遍输出2,然后返回了一个空的实例

    6、new Foo().getName()
    这里考了new基本概念,首先这个调用分为两步,第一步new Foo()得到一个实例,第二步调用实例的getName方法

    7、new new Foo().getName()
    第一眼也是看的我很懵,我们知道new一个函数都是new fn(),函数带括号的。所以这里其实可以拆分成这样:

    var a = new Foo();
    new a.getName();
    

    由于构造函数Foo自身啥构造器属性都没有,只有原型上有一个输出3的原型方法,所以实例a是一个原型上有输出3的函数getName。

    那么第二步,由于原型上的getName方法也没提供构造器属性,自身原型上也没属性,所以第二步也算是单纯执行a.getName()输出3,然后得到了一个什么自定义属性都没有实例。

    相关文章

      网友评论

          本文标题:2021-05-08 原型经典面试题Foo和Foo.getNam

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