new运算符和变量提升详解:一道多考点的面试题

本文详细探讨了JavaScript中的new运算符的工作原理,包括它创建对象、设置原型链和调用函数的过程。同时,文章还阐述了new运算符的优先级以及变量提升的规则,特别是函数声明和变量声明的提升顺序。通过对这些概念的深入理解,有助于解答相关的面试题。
摘要由CSDN通过智能技术生成

new运算符和变量提升详解:一道多考点的面试题

话不多说 , 先看题 .

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

你需要的知识:

  • 作用域
  • new的用法
  • new的优先级
  • 原型链
  • 变量提升

关于 作用域,原型链 的详尽知识小伙伴们要是还是没有摸透, 赶紧回去看高程啦~这里主要讲一下其他几个比较容易忽视的知识点.

new运算符

new运算符具体干了什么?发现其实很简单,就干了三件事情.

var obj  = {};
obj.__proto__ = F.prototype;
F.call(obj);

第一行,我们创建了一个空对象obj;

第二行,我们将这个空对象的__proto__成员指向了F函数对象prototype成员对象;

第三行,我们将F函数对象的this指针替换成obj,然后再调用F函数.

我们可以这么理解: 以 new 操作符调用构造函数的时候,函数内部实际上发生以下变化:

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

2、属性和方法被加入到 this 引用的对象中。

3、新创建的对象由 this 所引用,并且最后隐式的返回 this.

new运算符优先级

MDN运算符优先级 这里只截下来new的优先级 , 其他的太长了 可以自行复习哦.

在这里插入图片描述

我们看到new运算符的优先级是很高的 , 而且带参数和无参数是有区别的 , 但是 "."的优先级是比 "new"高

那好我们先分析后面三个表达式

 new Foo.getName();
 new Foo().getName();
 new new Foo().getName();

秒解方法: new匹配最近的函数执行的括号 , 如同左括号匹配右括号一样 .

new Foo.getName()//Foo.getName这个函数在执行new

new Foo().getName();// Foo函数在执行new 如同(new Foo()).getName()

new new Foo().getName();// 先 Foo函数执行new 返回值的getName方法再执行new函数 
//如同 new (new Foo()).getName()
变量提升

我们看看变量提升的规则 , 有两种提升

  • 函数声明 如: foo(){};
  • 变量声明 如: var a = 1; 或 var foo = function(){};

注意: 变量声明的第二个例子 , 它是属于变量声明的 .

具体是怎么提升呢?

  • 变量声明: 把声明和赋值拆解 , 声明提升到作用域最前面 , 赋值保留在原位

  • 函数声明: 把函数声明 如同剪切一般, 整个提升到作用域最前面(在变量声明后面).

其中 , 变量声明是先于函数声明的 看一个例子你就明白

var getName = function(){
     console.log(2);
 }
 function getName (){
     console.log(1);
 }
 getName();//输出2

经过拆解 它应该是这样的

var getName;//拆解第一步:变量提升至最前面
function getName (){
     console.log(1);
} //声明函数整块剪切
getName = function(){
     console.log(2);
}//拆解第二步:赋值,把函数的声明覆盖了
getName();//输出2

注意: if 中变量声明也同样会提升 , 函数声明是不会提升的

函数的形参是一种特殊的情况 , 函数形参在声明时 , 就已经完成了对参数的赋值 . 这个赋值是在声明函数变量提升之前的 .

function fn(n) {
    function n(){
	console.log(2);
	} ;
    n() // 
}
fn();//虽然没传参但是不报错 , 打印出来 2 .
fn(1);// 2
fn(()=>{console.log(1)}) //2

准备工作做好了

开始解题
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();

先解决变量提升

var getName;
function Foo(){
 	getName = function{alert(1);}
 	return this;
}
function getName(){alert(5);}
Foo.getName = function(){alert(2);}
Foo.prototype.getName = function(){alert(3)} 
getName = function(){alert(4);}
 Foo.getName();//2
 getName();//4
 Foo().getName();//1
 //Foo函数 `return this`  this指向什么? 因为Foo在全局作用域声明 , 所以它是由`window`调用 
 //在非严格模式下 , this指向 `window`  ,  就是在执行`window.getName()` 
 //但是注意了这里有个小坑 , Foo执行中把全局的getName函数更改了
 //因为内部没有定义getName函数, 所以向作用域链找,找到了全局的的getName并更改了.所以此处是1不是4 
 getName();//1
 new Foo.getName();//2
 new Foo().getName();//1 3  new Foo() 返回 this 是一个实例 , 这个实例找到了原型链上的getName方法
 new new Foo().getName();//1 3 同第六个
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值