Foo.getName

这篇博客详细分析了一段JavaScript代码,涉及到函数作用域、变量声明提升、函数表达式以及this的指向问题。Foo函数内部的getName赋值、Foo上的静态getName属性、原型链上的getName方法以及全局的getName变量相互影响,导致不同调用方式下getName的输出结果不同。通过实例解释了new操作符的优先级以及其对this的影响。
摘要由CSDN通过智能技术生成

水群的时候看到 这样一道题

<script>
    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();
</script>

分析:

Foo.getName()

        访问Foo函数上存储的,一个叫做getName的静态属性,该属性保存的值是匿名函数,这里输出2。

getName()

        直接调用那么就是访问当前上文作用域内的叫getName的函数,但是此处有两个坑,一是变量声明提升,二是函数表达式。

       变量声明提升

        函数声明提升指所有声明变量或者是声明函数都会被提升到当前函数的顶部。

// 样例
console.log('x' in window);//true
var x;
x = 0;

// 代码执行时js引擎会将声明语句提升至代码最上方,变为:
var x;
console.log('x' in window);//true
x = 0;

       函数表达式

         var getName 与 function getName 都是声明语句,区别在于 var getName 是函数表达式,而 function getName 是函数声明

// 样例
console.log(x);    //输出:function x(){}
var x=1;
function x(){}

// 实际执行的代码为,先将 var x=1 拆分为 var x; 和 x = 1; 两行,再将 var x; 和 function x(){} // 两行提升至最上方变成
var x;
function x(){}
console.log(x);
x=1;
// 所以最终函数声明的x覆盖了变量声明的x,log输出为x函数

// 举一反三
 var x=1;
 function x(){}
 console.log(x);    //输出:1

        再来看这道题

function Foo() {
    getName = function () { alert (1); };
    return this;
}
var getName;//只提升变量声明
function getName() { alert (5);}//提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName = function () { alert (4);};//最终的赋值再次覆盖function getName声明

getName();//最终输出4

Foo().getName()

        Foo函数的第一句  getName = function () { alert (1); };  是一句函数赋值语句,注意它没有var声明,所以先向当前Foo函数作用域内寻找getName变量,没有。再向当前函数作用域上层,即外层作用域内寻找是否含有getName变量,找到了,也就是第二种情况中的alert(4)。在找到后将外层作用域内的getName进行修改。此处若依然没有找到会一直向上查找到window对象,若window对象中也没有getName属性,就在window对象中创建一个getName变量。在当前情况下全局window中的getName已经被修改成了alert(1)。

       之后Foo函数的返回值是this,简单的讲,this的指向是由所在函数的调用方式决定的。而此处的直接调用方式,this指向window对象,相当于执行 window.getName(),而window中的getName已经被修改为alert(1),所以最终会输出1。

getName()

       直接调用getName函数,相当于 window.getName() ,因为这个变量已经被Foo函数执行时修改了 ,遂结果与上一问相同,为1。

new Foo.getName()

        涉及到了优先级的问题,这句话相当于是 new (Foo.getName)(),结果为2。

new Foo().getName()

         这句话相当于是 (new Foo()).getName(),也许会好奇为什么不是new (Foo().getName()),new Foo() 可以理解为两种运算:new 带参数(即 new Foo())和函数调用(即 先 Foo() 取值之后再 new),而 new 带参数的优先级是高于函数调用的,因此先执行了 new Foo(),获得 Foo 类的实例对象,再进行了成员访问 .getName。

 new new Foo().getName()

          这句话相当于是new ((new Foo()).getName)()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值