zoukankan      html  css  js  c++  java
  • 关于一道面试题

     1 var foo,bar1,bar2;
     2 function Foo(){
     3     this.counter={i:0};
     4     this.counter2=0;
     5 }
     6 function Bar(){};
     7 foo=new Foo();
     8 Bar.prototype=foo;
     9 Bar.prototype.sayHello=function(){
    10     console.log(this.counter.i,this.counter2);
    11     this.counter.i+=1;
    12     this.counter2+=1;
    13 }
    14 var bar1=new Bar();
    15 var bar2=new Bar();
    16 foo.sayHello();
    17 bar1.sayHello();
    18 bar2.sayHello();
    19 foo.sayHello();
     1 一眼瞟过,大概的意思是:
     2 
     3 声明了3个变量:foo,bar1,bar2; 
     4 
     5 接着声明了2个构造函数:Foo,Bar; 
     6 
     7 接着构造函数Foo的实例对象(new Foo)赋值给foo这个变量,
     8 
     9 接着foo这个变量又赋值给构造函数Bar的原型,即Bar.prototype; 
    10 
    11 接着在构造函数Bar的原型上添加了一个sayHello的方法;
    12 
    13 接着构造函数Bar的实例对象赋值给变量bar1
    14 
    15 接着构造函数Bar的实例对象赋值给变量bar2
    16 
    17 接着执行foo.sayHello();
    18 
    19 接着执行bar1.sayHello();
    20 
    21 接着执行bar2.sayHello();
    22 
    23 接着执行foo.sayHello();
    1 //其中bar.prototype = foo就是对象引用  同时bar也继承了foo的所有属性和方法
    2 
    3 Bar.prototype.counter2=10;//修改Bar原型上的属性 counter2 =10;原本是 0;
    4 
    5 console.log(foo.counter2);//Foo的实例对象foo下面的counter2 却跟着同时 变成10了

    第一个foo.sayHello()执行的结果:

    执行第一个foo.sayHello()的时候,因为console.log(this.counter.i,this.counter2)在 this.counter.i+=1;this.counter2+=1;前面,用的值自然就是初始值this.counter={i:0};this.counter2=0;
    第一个foo.sayHello()执行的结果就是 0 0

    bar1.sayHello()执行的结果:

    执行bar1.sayHello()时,由于已经执行过foo.sayHello(),引用地址中的变成 this.counter={i:1}; this.counter2=1;因此执行结果就是 1,1

    bar2.sayHello()执行的结果:

    执行bar2.sayHello()时,由于已经执行过foo.sayHello()由于是bar2又是一个实例化对象,由于每次实例化时,构造函数里的基本数据类型也会被初始化(this.counter2=0),复合数据this.counter不会被初始化({i:2});因此执行bar2.sayHello()的结果:2 1

    第二个foo.sayHello()执行的结果:

    执行第一个foo.sayHello()后,foo实例下的属性已经变成this.counter={i:1} this.counter2=1,经过bar1.sayHello()和bar2.sayHello()的执行,改变了只是复合属性this.counter的i值,而this.counter2是基本数据类型,不会影响到,因此,执行第二个foo.sayHello(),由于this.counter={i:3} this.counter2=1,结果就是 3 1

     ps:

    基本类型和引用类型的值及使用有什么区别?
    
    此处主要考察ECMAScript变量包含的两种不同数据类型的值:
    - 基本类型值, 指的是简单的数据段
    - 引用类型值, 指的是那些可能由多个值构成的对象
    
    解析过程有什么不同?
    
    答:将一个值赋给变量时,解析器必须确定这个值是基本类型值(Undefined,Null,Boolean,String,Number),还是引用类型值。
    基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值
    引用类型的值是保存在内存中的对象,与其他语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是操作对象的引用而不是实际的对象,为此,引用类型的值是按引用访问的。注意JS中,Sring不是引用类型
    
    基本类型与引用类型对动态属性的支持的区别有哪些?
    
    答:定义基本类型值和引用类型值的方式是类似的:创建一个变量并为该变量赋值
    当这个值保存到变量之后,对不同类型值可以执行的操作则大相径庭。对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法,例如:
    var person = new Object();
    person.name = "Jack";
    console.log(person.name); // "Jack"
    以上代码创建了一个对象并将其保存在了变量person中。
    我们不能给基本类型的值添加属性,尽管这样做不会导致任何错误(严格模式下会报错)
    var name = "Jack";
    name.age = 27;
    console.log(name.age);   // undefined
    通过上述例子,表明只能给引用类型值动态地添加属性
     1 var fullname="Joh Don";
     2 var o={
     3     fullname:'colin Ihrig ',
     4     prop:{
     5         fullname:'Aureio De Rose ',
     6         getFullname:function(){
     7             return (()=>this.fullname)()
     8         }
     9     }
    10 }
    11 
    12 
    13 console.log(o.prop.getFullname())//Aureio De Rose 
    14 var test=o.prop.getFullname;
    15 console.log(test())//Joh Don
     1 var fullname="Joh Don";
     2 var o={
     3     fullname:'colin Ihrig ',
     4     prop:{
     5         fullname:'Aureio De Rose ',
     6         getFullname:function(){
     7             return (function(){return this.fullname})()
     8         }
     9     }
    10 }
    11 
    12 console.log(o.prop.getFullname())//Joh Don
    13 var test=o.prop.getFullname;
    14 console.log(test())//Joh Don
     1 var fullname="Joh Don";
     2 var o={
     3     fullname:'colin Ihrig ',
     4     prop:{
     5         fullname:'Aureio De Rose ',
     6         getFullname:function(){
     7             return this.fullname
     8         }
     9     }
    10 }
    11 
    12 console.log(o.prop.getFullname())//Aureio De Rose
    13 var test=o.prop.getFullname;
    14 console.log(test())//Joh Don
     1 var fullname="Joh Don";
     2 var o={
     3     fullname:'colin Ihrig ',
     4     prop:{
     5         fullname:'Aureio De Rose ',
     6         getFullname:function(){
     7             // console.log(this) // {fullname: "Aureio De Rose ", getFullname: ƒ},也即是prop对象
     8             return this.fullname
     9         }
    10     }
    11 }
    12 
    13 console.log(o.prop.getFullname())//是谁在调用getFullname()方法 :o对象下面的prop对象,
    14 var test=o.prop.getFullname;//function(){return this.fullname}
    15 console.log(test())//Joh Don
     1 for(var i=0;i<5;i++){
     2 
     3     setTimeout(function(){
     4 
     5         console.log(i)
     6 
     7     },1000)
     8 
     9 }
    10 
    11 //输出5个5
    12 
    13 // setTimeout是异步执行的,遇到setimeout首先会向任务队列里添加1个个任务,只有主线上的全部任务全部执行完了才会去去执行队列的里的任务,
    14 // 所以主线执行完后的是i等于5,再去执行队列任务里的定时任务,实际是执行(循环多少次)个setTimeout里的函数
     1 for(let i=0;i<5;i++){
     2 
     3     setTimeout(function(){
     4 
     5         console.log(i)
     6 
     7     },1000)
     8 
     9 }
    10 
    11 //输出0 1 2 3 4
    12 
    13 // setTimeout是异步执行的,遇到setimeout首先会向任务队列里添加这个任务,只有主线上的全部任务全部执行完了才会去去执行队列的里的任务,
    14 // 这个是let,就有作用域了,那么作用域怎么看呢? 一次循环就是一个域,在这个域里,每次循环后对应的i值也是不一样,因此最后执行setTimeout里的(循环次数)个函数时就有对应的i值,所以输出0 1 2 3 4
     1 function F(){
     2 
     3     this.conuter={n:0}
     4 
     5     this.number=0
     6 }
     7 
     8 function B(){}
     9 
    10 B.prototype=new F();
    11 
    12 B.prototype.change=function(){
    13     console.log(this.conuter.n,this.number)
    14     this.conuter.n+=1
    15     this.number+=1
    16 }
    17 
    18 console.log(B.prototype.constructor===F)//true  共用一个内存地址 
    19 
    20 
    21 var a=new B()
    22 
    23 var b=new B()
    24 
    25 a.change()// 0 0
    26 
    27 a.change()// 1 1
    28 
    29 b.change()// 2 0
    30 
    31 a.change()// 3 2
    32 
    33 //实例化一次 就会初始化一次,引用类型的conuter是保存在内存中的对象,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,因此复合属性conuter下面的n是无法被实例初始化的
    34 //基本数据类型number是按值访问的,因为可以操作保存在变量中的实际的值,number是会在实例化的时候初始化
    1 function a(){
    2     console.log('b=>',b)//b=> undefined
    3     var b=10;
    4     var b=function(){}
    5 }
    6 a()

    词法分析,执行a(),a函数的作用域里,又开始预解析,预解析阶段都不执行代码的,遇到var b=undfined, 又遇到var b 还是赋值undfined,开始执行阶段,从上往下依次,执行,由于预解析var b等于undefined,因此打印出undefined,

    1 function a(){
    2     console.log('b=>',b)//b=> ƒ b(){}
    3     var b=10;
    4     function b(){}
    5 }
    6 a()

    依旧先词法分析,执行a(),a函数又是一个作用域,又得预解析,遇到var的function开头,或是参数,就会很敏感,首先,遇到var b赋值undefined,遇到function 开的b函数,由于变量提升,就相当于下面:

    1 function a(){
    2     var b=function(){}
    3     console.log('b=>',b)//b=> ƒ b(){}
    4     var b=10;
    5 }
    6 a()

    变量提成是提升到作用域顶部,可以再修改下例子

    1 console.log(a)//function a(){}
    2 function a(){}
    3 <=>
    4 var a=function(){}
    5 console.log(a)//function(){}
     1 var o={
     2     obj:{
     3         getFullname:function(){
     4             setTimeout(()=>console.log(this),1000)//obj
     5         }
     6     }
     7      
     8 }
     9 
    10 o.obj.getFullname()

    定时器里的箭头函数this 指向的是上一级的父对象

    var fullname="Joh Don";
    var o={
        fullname:'colin Ihrig ',
        prop:{
            fullname:'Aureio De Rose ',
            getFullname:function(){
                return ()=>this.fullname
            }
        }
    }
    
    
    console.log(o.prop.getFullname()())//Aureio De Rose 
    var test=o.prop.getFullname;
    console.log(test()())//Joh Don
  • 相关阅读:
    SQL学习笔记六之MySQL数据备份和pymysql模块
    SQL学习笔记五之MySQL索引原理与慢查询优化
    SQL学习笔记四之MySQL数据操作
    SQL学习笔记四(补充-2)之MySQL多表查询
    SQL学习笔记四(补充-2-1)之MySQL SQL查询作业答案
    SQL学习笔记四(补充-1)之MySQL单表查询
    SQL学习笔记四(补充-1-1)之MySQL单表查询补充部分:SQL逻辑查询语句执行顺序
    Python Web学习笔记之为什么设计GIL
    SQL学习笔记三之MySQL表操作
    buffer小解
  • 原文地址:https://www.cnblogs.com/studyshufei/p/9053012.html
Copyright © 2011-2022 走看看