整理下之前做的有点疑惑的js基础题目和大家分享以下,如果大家觉得有用,别忘了点一下赞哦
new
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 flag1
Foo().getName()//1 flag2
getName()// 1 flag3
new Foo.getName()//2 flag4
new Foo().getName()//3 flag5
new new Foo().getName()//3 flag6
flag1处:访问 Foo函数的属性getName,打印 2
flag2处:
这里分为两步
->第一步:Foo() —> Foo()执行把window.Foo,由 打印 4 变为了 打印 1,然后返回 this函数本身
->第二步:Foo().getName() —> 相当于 Foo.getName(),而作用域内没有 getName函数,这里可以理解为未声明,函数Foo变量归window所有,就拿window.getName,所以打印1
flag3处:window.getName,打印 1
flag4处:
这里需要扩展下,建议先看一下扩展,根据优先级,函数调用的优先级大于 new(无参数列表),这里分两步
->第一步:Foo.getName —> 先执行 Foo.getName,注意这里new的函数打印 2
->第二步:new Foo.getName() —> 构造函数执行,打印2,返回个空对象{}
flag5处:
这里分两步,我们要知道new(带参数列表)的优先级大于函数调用
->第一步:new Foo() —> 先执行new Foo(),返回一个空对象{}
->第二步:new Foo().getName()—>在空对象{}上找getName函数,自己的私有属性没有,会沿着__proto__原型链,找所属类的prototype原型上的公共方法,所以打印 3。
flag6处:
这里分三步,思路和上面一样,从优先级考虑
->第一步:new Foo() —> 先执行new Foo(),返回一个空对象{}
->第二步:new Foo().getName —> 在空对象{}上找getName函数,自己的私有属性没有,会沿着__proto__原型链,找所属类的prototype原型上的公共方法
->第三步:new new Foo().getName() —> 执行类(构造函数),打印 3 ,返回空对象{},注意:这一步和flag5处不同的是,这里使用new 执行构造函数(类),返回类的实例,flag5处用的是函数执行,返回undefined,这一步我没弄懂之前一直认为它会报错,现在这题通透了,点个赞呗。
扩展
new Fn()和new Fn的 区别
相同点:两者都能让类(构造函数)执行
不同点:
1.前者可以传参数,后者不行
2.优先级,前者优先级更高,前者优先级低
不同点1:参数
function fn(a,b){
this.a = a
this.b = b
}
console.log(new fn(1,2))//fn { a: 1, b: 2 }
console.log(new fn)//fn { a: undefined, b: undefined }
不同点1:优先级
这里我们针对上面这题
new Fn的优先级19是比函数调用Fn.xxx的优先级 20 更低的
new Fn()的优先级和 函数调用Fn.xxx同为20,但js优先级汇总表中明确排序了,函数调用在new Fn()后面,即new Fn()的优先级19是比函数调用Fn.xxx更高的。

这里附了一个js优先级表的链接:可以自己查看
JavaScript优先级汇总表链接 MDN
本文深入解析JavaScript中new关键字、函数作用域和原型链的应用,通过实例探讨了getName函数的不同调用方式和优先级,以及new与函数调用的差异。理解了函数原型和继承机制在实际编程中的关键作用。
365

被折叠的 条评论
为什么被折叠?



