javascript中函数问题

javascript中函数问题

1.代码执行后弹出:100 50

var age=100;
function test()
{
    this.age=50;
    return function()
    {
        return this.age;
    }
}
var m=new test(); 
alert(m());
var n=test();
alert(n());

解析:

var m=new test(); 
//构造函数改变上下文this变为m;改变了m的age值为50,此时m=function(){return this.age}
alert(m());
//此时上下文环境为window,得出window.age=100;
var n=test();
alert(n());
//等同于alert(test()())
//因为上下文环境一直是window,test()时改变了age的值为50,所以test()()时返回50

new运算符的时候会生成一个对象,叫做空对象。然后调用new运算符后面的函数,也就是类,执行的过程,会把this绑定到空对象上。所以第一个把this是绑定到了生成的空对象上。
所以这个空对象有了age=50的属性。但返回的是函数,不是这个对象。函数中的函数这是闭包,闭包里面的函数的this指向跟是不是闭包没有关系,它依然指向window,于是,你的第一个显示100.
第二个没有生成对象。依然是闭包跟this没有关系,两个函数的调用都指向了window,所以第一次执行 修改为50了,第二次执行显示50。

2.下面代码输出: Goodbye Jack

var name="World!";       
(function(){       
var name;      
if(typeof name=== 'undefined'){       
name='Jack';  
console.log('Goodbye'+name);      
 }else{       
console.log('hello'+name);       
}       
})() 

解析:

var name="World!";       
(function(){       
var name; //undefined;       
console.log(name==="undefined")//false       
console.log(typeof name==="undefined")//ture       //这里是隐形转换        
//只有 null ""  0  -0  null  undefined  false  才是false        
//而此处的 typeof false 是Boolean类型 所以 隐形转换是ture        
if(typeof name=== 'undefined'){       
name='Jack'; //进入if       
console.log('Goodbye'+name);      
 }else{       
console.log('hello'+name);       
}       
})() 

(function() { … })();是块级作用域,独立于外部执行环境。
局部覆盖全局,name未定义,所以输出Goodbye Jack

3.下面代码输出:10

function test(a){
a=a+10;
}
var a=10;
test(a);
console.log(a);

解析:
a是形参,属于局部变量,不影响全局变量a的值,以不带参数的形式的修改才是全局修改,因此输出的a是全局变量的值10

4.下面代码输出: 1 2 3

var foo = {n:1};
(function(foo){
 console.log(foo.n); 
  foo.n = 3;  
 var foo = {n:2}; 
  console.log(foo.n);
})(foo);
console.log(foo.n);

解析:

var foo = {n:1};
(function(foo){//形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1    
 var foo; //优先级低于形参,无效。    
 console.log(foo.n);  //输出1   
  foo.n = 3; //形参与实参foo指向的内存空间里的n的值被改为3    
  foo = {n:2}; //形参foo指向了新的内存空间,里面n的值为2.   
  console.log(foo.n); //输出新的内存空间的n的值
})(foo);
console.log(foo.n);//实参foo的指向还是原来的内存空间,里面的n的值为3.

5.x的值是:foo

function A() { 
    this.do=function() {return ‘foo’;};
   }
   A.prototype=function() {
   this.do=function() {return ‘bar’};
   };
   var x=new A().do();
  1. 题目中由于A()构造函数中已经存在了do()方法,所以不用再到原型上去找do,并且就算是去原型上找do方法也是找不到的。 原因是:
A.prototype=function() {           
	this.do=function() {return ‘bar’};       
}; 

将A的原型重写成了一个函数,如果想要调用到A.prototype中的do,至少是要执行一次A.prototype()的 所以希望在这种定义下打印出"bar",这样写可以实现,但是感觉没什么意义

var x=new A.prototype().do()   //"bar"  
  1. 为了更好说明原型上也不存在do,再换一种写法
var x=new A();
console.log(x.__proto__);  
//x.__proto__==A.prototype,打印出来的是一个方法,而不再是一个原型对象
console.log(x.__proto__.do())    //报错

其实,不仅仅是说不能再在原型上找到do,就连正常的原型对象都不存在了

  1. 如果想要定义原型上的方法,
function A() {
     this.do=function() {return 'foo';};
 }
 A.prototype=new function() {
     this.do=function() {return 'bar'};
 };      
 //使用new,构造函数
 var x=new A();
 console.log(x.__proto__);       
 console.log(x.__proto__.do())

在这里插入图片描述

6.以下代码执行后, num 的值是? -1

var foo=function(x,y){ 
	return x-y; 
} 
function foo(x,y){ 
	return x+y; 
} 
var num = foo(1,2);   

解析:

//会被javascript编译器处理为: 
//variable hoisting变量提升 
var foo;//foo#1 
var num; 
//function declaration hoisting函数声明提升 
function foo(x, y){//foo#2 
   return x + y; 
} 
//function expression NOT hoisted函数表达式不会被提升 
foo =function(x, y){//foo#3 
   return x - y; 
} 
num = foo(1, 2);//这里使用foo#3 

规则
4. 变量声明、函数声明都会被提升到作用域顶处;
5. 当出现相同名称时,优先级为:变量声明(foo#1) < 函数声明(foo#2) < 变量赋值(foo#3)
6. 因此,num计算时是用的foo#3。答案为-1。

7.控制台打印的结果是? 0 1 2 2

for(let i=0;i<2;i++){
	setTimeout(function(){
	console.log(i)
	},100
	);
}
for(var i=0;i<2;i++){
	setTimeout(function(){
	console.log(i)
	},100
	);
}

解析:
第一个:let将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;输出为0,1.
第二个:settimeout是异步执行,1s后往异步任务队列里面添加一个任务,只有同步的全部执行完,才会执行异步任务队列里的任务,当主线执行完成后,i是2,所以此时再去执行任务队列里的任务时,所以输出两次2.

8.在浏览器控制台执行以下代码,输入的结果是: 4400 4401 4399 4400

function test(){
    var n = 4399;
    function add(){
     n++;
     console.log(n);
    }
    return {n:n,add:add}
   }
   var result = test();
   var result2 = test();
   result.add();
   result.add();
   console.log(result.n);
   result2.add();

解析:
在这里插入图片描述
从内存说起。
本数据类型(String,Number,Boolean,Undefined,Null)进行复制的时候,在栈中创建一个新变量,再将值赋给这个新变量;
引用数据类型(Object,数组,函数)复制的时候,在栈中创建一个新变量,再将引用数据类型的堆地址赋值给这个新变量,也就是说这个地址副本和原地址指向的是同一个数据类型。
题目中,test函数返回的{n:n,add:add}中,n是新创建的变量,add是原函数的引用。
执行两次test函数后会生成 两个 不会互相干预的对象。
执行result.add时,相当于执行test()函数中的add(),而add()中有未声明的变量n,程序会解析add的作用域链(这里形成了闭包),向上寻找一个作用域环境,找到test()的环境中的n。最后执行的部分就很简单了。
所以,result.n所代表的的n与result.add()输出的n不是同一个n,第三个是不会变的4399

9.以下代码,在浏览器中执行的结果是 9999 4400

var A={n:4399};
   var B=function(){    
    this.n=9999
    }    
    var C=function(){
     var n=8888
    }
    B.prototype=A;
    C.prototype=A;
    var b=new B();
    var c=new C();
    A.n++;
    console.log(b.n);
    console.log(c.n);

解析:
new运算的具体执行过程:
1)创建一个空对象
2)把这个空对象的__proto__指向构造函数的prototype
3)把这个空对象赋值给this
4)执行构造函数内的代码,注意此时的this指向新对象,this.n=9999 等价于b.n=9999;
然后访问b.n,存在,直接输出b.n。
再去访问c.n,不存在,通过原型链__proto__向上寻找,c.__proto__指向C.prototype也就是A,所以就是输出A.n

var c = new C();
  上面这个语句的实际运行过程是这样的。 
var c = function() {
    var o = new Object();
    //第一个参数改变函数的作用域,即相当于在函数内部设置this = o
    C.apply(o, argumens);
    return o;
}
这样,由于C()函数中 
var n = 8888;
这样只是在函数中创建了一个私有变量,并没有为对象执行任何操作,
因此C的实例中不存在名字为“n”的属性。所以,c.n会访问原型中的属性名为“n”的值。 

10.以下代码执行后,a.x 和 b.x 的结果分别是 2 undefined

 function A(x){  
 	this.x = x;
 }
 A.prototype.x = 1;
 function B(x){
 	this.x = x;
 }
 B.prototype = new A();
 var a = new A(2), b = new B(3);
 delete b.x;

解析:
在这里插入图片描述
var a = new A(2), //a.x首先要在自己的构造函数中查找,没有采取原型上找,这里有this.x = x.所以a.x = 2;
b = new B(3); //B.prototype = new A();形成原型链
delete b.x; //但是delete只能删除自己的x不能删除父级的x.
//b.x通过原型链找到构造函数A里面的this.x=x但是没有赋值,所以undefined

发布了24 篇原创文章 · 获赞 0 · 访问量 748

猜你喜欢

转载自blog.csdn.net/weixin_45846263/article/details/104235672
今日推荐