整理下之前做的有点疑惑的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