欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

一道面试题 包含了new的细节 和运算符的优先级 还有属性访问机制

程序员文章站 2022-06-24 16:06:41
这是在网上看到的一道面试题 嗯 考察的知识点挺多 其他的就不多说了 我用我的理解与解题方式来解答这道题 1.首先是变量提升 变量提升包括var 声明的变量和fucntion 声明 举个例子 1.var a=4; 2.function test(){ console.log(456); }; 函数变量 ......
 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); }

  这是在网上看到的一道面试题  嗯 考察的知识点挺多  其他的就不多说了

  我用我的理解与解题方式来解答这道题

  1.首先是变量提升

   变量提升包括var 声明的变量和fucntion 声明

   举个例子

      1.var a=4; 

      2.function test(){

       console.log(456);

     };

     

   函数变量声明会先于普通变量之前,并且不会被后面的同名覆盖

   但是会被后面的同名赋值覆盖!

   就是 function a(){};

       var a;

       这样不会覆盖函数a

       但是如果 var a=4;

       函数a就会被覆盖

 

      接下来从第一个开始分析

         foo.getname();

首先变量提升之后是这个样子滴

//变量提升

          第一题function foo(){

                 getname = function () { alert(1); }//foo函数执行的时候 会覆盖全局中的getname
                 return this;

                 /* 

                      new 运算符的时候会执行以下

                      var obj={};//创建一个空对象

                      将构造函数的作用域赋给新对象

                      这个新对象的内置原形指向构造函数的原形对象

                      obj.__proto__=foo.prototype;

                      执行构造函数中的代码

                      返回这个对象(如果显示返回基本数据类型 无效 还是会返回这个对象

                                  如果返回的是引用类型 那么这个对象将没用了)

                     

               */

              }

           //变量提升

          //2.function getname () { alert(5); }

         //变量提升

           3.var getname;


           4.foo.getname = function () { alert(2); }
           5.foo.prototype.getname = function () { alert(3); }
           6.getname = function () { alert(4); }

 

           之前的2 会被6覆盖 所以2就可以注释掉了

          第二题 foo.getname(); //弹出窗口值为2 不用解释了吧
第三题 getname();//弹出窗口值为4
第四题 foo().getname();

先执行foo();
里面的getname=function(){alert(1);} 会覆盖全局作用域中的6
因为是在全局作用域下调用foo函数 所以this就是window
window.getname(); //弹出窗口值为6

第五题 new foo.getname();

new (foo.getname)(); //弹出窗口值为2
笨想:肯定不会是执行foo.getname 之后才new 会报错
优先级问题 .(成员访问的优先级高于new 并且从左到右
于是就把foo.getname这个函数当做构造函数执行
                            

第六题
new foo().getname();
.运算符从左到右
new foo(); 返回一个foo类型的对象 {}
{}.getname();
找不到 然后去构造它的函数foo的prototype上找
foo.prototype.getname = function () { alert(3); }
所以结果 3


第七题
也是运算符优先级的问 new new foo().getname(); 在这里面.的优先级最高
           new ((new foo()).getname)(); 
先执行.左 然后.右
先执行foo(); 然后new 返回一个foo类型的对象
然后得到getname的函数体
然后当做构造函数执行 alert(3) 然后返回一个foo.getname类型的对象


可能有些地方不是让所有人懂
毕竟我也是一直菜鸟


// foo.getname(); //2
// getname(); //4
// foo().getname(); //1
// getname(); //1
// new foo.getname();//2
// new foo().getname();//3
// new (new foo().getname)()//3;

优先级

运算类型

关联性

运算符

20

圆括号

n/a

( … )

19

成员访问

从左到右

… . …

需计算的成员访问

从左到右

… [ … ]

new (带参数列表)

n/a

new … ( … )

函数调用

从左到右

… ( … )

18

new (无参数列表)

从右到左

new …

17

后置递增(运算符在后)

n/a

… ++

后置递减(运算符在后)

n/a

… --

16

逻辑非

从右到左

! …

按位非

从右到左

~ …

一元加法

从右到左

+ …

一元减法

从右到左

- …

前置递增

从右到左

++ …

前置递减

从右到左

-- …

typeof

从右到左

typeof …

void

从右到左

void …

delete

从右到左

delete …

15

从右到左

… ** …

14

乘法

从左到右

… * …

除法

从左到右

… / …

取模

从左到右

… % …

13

加法

从左到右

… + …

减法

从左到右

… - …

12

按位左移

从左到右

… << …

按位右移

从左到右

… >> …

无符号右移

从左到右

… >>> …

11

小于

从左到右

… < …

小于等于

从左到右

… <= …

大于

从左到右

… > …

大于等于

从左到右

… >= …

in

从左到右

… in …

instanceof

从左到右

… instanceof …

10

等号

从左到右

… == …

非等号

从左到右

… != …

全等号

从左到右

… === …

非全等号

从左到右

… !== …

9

按位与

从左到右

… & …

8

按位异或

从左到右

… ^ …

7

按位或

从左到右

… | …

6

逻辑与

从左到右

… && …

5

逻辑或

从左到右

… || …

4

条件运算符

从右到左

… ? … : …

3

赋值

从右到左

… = …

… += …

… -= …

… *= …

… /= …

… %= …

… <<= …

… >>= …

… >>>= …

… &= …

… ^= …

… |= …

2

yield

从右到左

yield …

yield*

从右到左

yield* …

1

展开运算符

n/a

... …

0

逗号

从左到右

… , …