说明
在刚开始学习JS的时候,经常被同名变量的优先级判断面试题搞蒙了,也尝试过使用流行的优先级口诀去解决这些问题
变量申明 > 普通函数 > 函数传参 > 变量提升
但对于自己来说,只要是死记硬背的东西都会记不住,时间久了遇到有可能还会出现懵逼的情况。对于JS的初学者来说,我觉得这类问题还是要靠理解的思路去解决,才记得牢。
以下列举几个题目,并放上自己不严谨的解题思路,希望有错误大家都能及时的指出,也能让其他正在学习的小白一起科学的攻克这类问题。
变量的提升
变量的提升是在一个作用域内的代码开始执行时,会先把var声明的变量名提升到作用域的最顶部去(本次变量的提升只针对es5的var)。例如:
function fn(){
console.log(bar);
var bar = 1;
}
// 实际会是这个样子
function fn(){
var bar // 变量提升上来了,但是只有声明并没赋值
console.log(bar); // 从上往下执行到这句 undefined
var bar = 1;
}
函数传参
function fn(bar){
console.log(bar);
var bar = 1;
}
fn(5) // 本来变量提升是undefined,结果传入参数,就有值了
// 实际上
function fn(bar){
var bar // 此时有参数传入,让只声明的变量知道值了
console.log(bar); // 从上往下执行到这句 5
var bar = 1;
}
函数的提升
先提两个函数定义的概念:
- 函数声明(式):
function fn(){}
- 函数表达式
var fn = function(){}
函数声明(式)
一个作用域中的函数声明(式)会在代码执行前,提升到仅次于变量提升的位置,且相同名称的函数声明(式)一定是后者覆盖前者。例如:
function fn(bar){
console.log(bar);
function bar(){ //相同名称的函数
return '函数1';
}
console.log(bar);
var bar = 1;
function bar(){ //相同名称的函数
return '函数2';
}
}
fn(5)
// 实际是这样
function fn(bar){
var bar // 变量提升 , 传参赋值5
function bar(){ // 函数变量提升,其实也就是变量提升,把bar = 5 覆盖
return '函数2';
}
console.log(bar); // 从上往下执行到这句 直接把bar函数2整个代码打印出来
console.log(bar); // 从上往下执行到这句 直接把bar函数2整个代码打印出来
var bar = 1;
}
函数表达式
注意:函数声明(式)和函数表达式是有区别的!
function bar(){
return '函数1';
}
// 不同于
var bar = function(){
return '函数1';
}
例如:
function fn(bar){
var bar = 1;
var bar = function(){
return '函数1';
}
console.log(bar);
function bar(){
return '函数2';
}
}
fn(5);
// 实际上
function fn(bar){
var bar // 变量提升 传入参数赋值 bar=5
function bar(){ // 函数提升 bar = 这个函数
return '函数2';
}
var bar = 1; // 从上到下执行到这里 bar被重新声明并赋值 bar = 1
var bar = function(){ // 注意注意! 这里也是变量的赋值声明, bar = 这个函数
return '函数1';
}
console.log(bar); // 从上到下执行到这里,直接把bar函数1整个代码打印出来
}
小练习
来来来,做点练习巩固一下
习题一:
console.log(a) // 打印出个啥?
function a(){
return '芜湖'
}
var a = 1
习题二:
alert(a)
a()
var a = 3;
function a() {
alert(10)
}
alert(a)
a = 6;
a();
//什么?你说这题又懵了?别急再分析一下**************************
var a // 老规矩,变量提升一波 undefined
function a() { // 有名函数提升 a = 这个函数
alert(10)
}
alert(a) // 是不是就弹出出上面函数的代码啦?
a() // 到这里a还是那个函数,直接执行,弹出10
var a = 3; // 芜湖,a变量声明赋值了 a=3
alert(a) // 是不是就弹出3了
a = 6; // a被重新赋值为6 a=6
a(); // 一个非函数怎么执行?直接报错
习题三:
alert(a)
// a() 如果这题作对了,把这句取消注释再试试
var a = 3;
var a = function() {
alert(10)
}
alert(a)
a = 6;
a();
// 这题需要解析就给我评个论哈哈!
习题四:
var foo = function(){
console.log(1);
}
function foo(){
console.log(2);
}
foo();
习题五:
function fn() {
var b = 1;
function a() {
console.log('1', b);
var b = 2;
console.log('2', b);
}
a();
console.log('3', b);
}
fn();
// 这题解析一下吧
function fn() {
var b // 不说了吧
function a() {
var b // 在这个函数作用域内变量提升 undefined
console.log('1', b); // 打印 1 undefined
var b = 2; // 声明赋值 b = 2
console.log('2', b); // 打印 2 2
}
var b = 1;
a(); // 执行a函数,去看看a函数有啥
console.log('3', b); // 这个b不是函数a内的哦,打印 3 1
}
习题六:这题比较复杂,需要JS基础稍微扎实一些(当然,不懂也没啥事,可以跳过)
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()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
// 问:执行结果的顺序是怎么样的?
****************步骤解答
function Foo() { // 给window对象绑定一个函数Foo
getName = function() {
console.log(1)
}
return this;
}
Foo.getName = function() { // 给函数Foo添加一个属性getName,是个函数
console.log(2)
}
Foo.prototype.getName = function() { //给函数Foo的原型添加一个属性getName,是个函数
console.log(3)
}
var getName = function() { // 给window对象绑定一个对象,是个函数
console.log(4)
}
function getName() { // 一个有名函数getName,默认提升,然后又被var getName声明覆盖了
console.log(5)
}
Foo.getName();// 执行Foo上的getName属性 -------2
getName();//执行window对象上的getName --------4
Foo().getName(); //先执行了Foo,把window对象的getName修改了,然后返回this,指向window,也就是window.getName() -------1
getName(); //--------1
new Foo.getName(); //.点的优先级比new运算符高,new (Foo.getName)() --------2
new Foo().getName(); //()执行优先级比.高,所以(new Foo()).getName(),this指向构造函数的实例,所以是执行原型上的getName -------3
new new Foo().getName(); //同理,new [【new Foo()】.getName()] ----------3
习题七:从掘金哪里看来的,挺不错的题
var foo = function () {
console.log("foo1")
}
foo()
var foo = function () {
console.log("foo2")
}
foo()
function foo() {
console.log("foo1")
}
foo()
function foo() {
console.log("foo2")
}
foo()
尾巴
初学者学这块的时候其实完全没必要担心时间久了记不住,因为在真正工作中,基本遇不到因为同名变量引起的不好影响,谁没事会在同一个作用域里声明这种东西。大多数都是面试出的题罢了,所以能理解变量提升、函数提升就可以了哈。
大伙来个赞呗~