*每日一题(三六)function fn(){ getValue = function(){ console.log(1) } return this} fn.getValue

题目描述:写出执行结果并解释原因

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

//请写出下面结果:
getValue();
fn().getValue();
getValue();
new fn.getValue();
new fn().getValue();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

答案:

4
1
1
2
3

知识点:

  • 变量定义的提升、this 指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等

解析:

第一问:getValue()

1.直接调用 getValue 函数,就是访问当前上下文作用域内叫 getValue 的函数,所以关注点就是在 4 5 上

2.两个坑:

  • 一是变量声明提升,JavaScript 解释器中存在一种变量声明被提升的机制,也就是说函数声明会被提升到作用域的最前面,即使写代码的时候写在最后面,也还是会被提升至最前面
  • 二是函数表达式和函数声明的区别,函数声明在 JS 解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用。而函数表达式的值是在 JS 运行时确定,并且在表达式赋值完成后,该函数才能调用

3.所以第二问的答案就是 4,  5  的函数声明被 4 的函数表达式覆盖了

第二问:fn().getValue()

1.fn().getValue(),先执行 fn 函数,然后调用 fn 函数的返回值对象的 getValue 属性函数

2.注意,fn 函数的第一句,getValue = function(){console.log(1)} 没有用 var 进行声明,执行到这时,实际上将外层作用域的 getValue 函数修改了

3.之后,fn 函数返回了 this,this 的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定 this 到底指向谁,而此处的直接调用方式,this 指向了 window 对象,所以此处相当于执行 window.getValue(),现在 getValue 已经被修改成 console.log(1) 所以输出 1

第三问:getValue()

第二问中,执行完 fn 函数,getValue 函数已经被修改了,现在已经是 console.log(1),所以这里输出 1

第四问:new fn.getValue()

1.这里是考察 JS 运算符优先级问题,可以参考 MDN 的运算符优先级

2.点的优先级是 18 ,new 无参数列表优先级是 17,点的优先级高,所以这里相当于 new (fn.getValue())

3.当点运算完后又因为有一个括号,此时变成 new 有参数列表,new 有参数列表的优先级是 18,所以直接执行 new ,因为函数调用的优先级是 17,优先级低于 new 有参数列表的优先级

4.最终就是相当于将 getValue 函数 function(){console.log(2);} 作为构造函数来执行,所以输出 2

第五问:new fn().getValue()

1.与第四问的区别就是 fn 有无括号,这里带括号是 new 有参数列表,new 有参数别表的优先级是 18 ,点的优先级也是 18,优先级相同按照从左到右的执行顺序

2.所以这里是先执行有参数列表,在执行点的优先级,最后再函数调用

3.这里设计到一个知识点, fn 作为构造函数有返回值,在 JS 中构造函数可以有返回值也可以没有

  • a.没有返回值,返回实例化的对象
  • b.有返回值,检查其类型是否是引用类型,非引用类型,如基本类型(String,Number,Boolean,Null,Undefined,Symbol,BigInt)则与无返回值相同,实际返回其实例化的对象。引用类型,实际返回值为这个引用类型

4.这里 fn 函数的返回值是 this,this 在构造函数中本来就代表着当前实例化对象,最终 fn 返回实例化对象。最终调用这个实例化对象的 getValue 函数,因为在 fn 构造函数中没有为实例化对象添加任何属性,就到当前对象的原型对象(prototype)中寻找 getValue 函数,所以输出 3

猜你喜欢

转载自blog.csdn.net/MFWSCQ/article/details/105206458