1.看下面代码将会输出什么?
var foo = 1;
(function (){
console.log(foo);//undefined
var foo = 2;
console.log(foo);//2
})();
函数的声明与变量声明会被js引擎隐式地提升到当前作用域的顶部,但是只提升名称赋值留在原地
2. 完成整个原型链(Student.proto、Student.prototype.__proto__等又是指向谁,原型链的顶端到底是什么,在图中做出体现
function Student(sname, sage){
this.sname = sname;
this.sage = sage;
}
Student.prototype.intr = function(){
console.log(I'm ${this.sname},I'm ${this.sage}
);
}
var lilie = new Student(“Li Lei”, 12);
var hmm = new Student(“Han Meimei”, 12);
console.log(lilie,hmm);
**3.下面代码 将会输出的结果?(并解析)**
function f1(){
var n =999;
nAdd = function(){n+=1}
function f2(){
alert(n);
}
(function (n){
alert("remove:"+n);
})(n);
return f2;
}
var result = f1();
result();
nAdd();
f1();
result();
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。
这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,
因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,
因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),
而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
4.求输出的结果
var i = 10;
function b(){
i = 20;
console.log(i);//20
for(var i = 0;i < 6;i++){
console.log(i);//输出0-5
}
console.log(this.i);//10
console.log(i);//6 当前的局部变量在循环时被赋值为6
}
b();//等于window.b() 函数里面的this纸袋window对象
console.log(i)//10 不能向下搜索作用域而进入另一环境
5.解析下面代码并求出结果
function aaa(){
a=10;
}
aaa();
alert(a); //结果为10;
//等价于:
var a;
function aaa(){
a=10;
};
aaa();
alert(a);
给未声明的变量赋值,此变量就会变成全局变量;var a=b=10; 可以解析成 b=10;var a=b; 也就是b为全局变量,a为局部变量,所以外部访问a访问不到,访问b结果为10;
所以为了避免出现这种隐患,我们在定义变量的时候把所有要定义的变量都加上var;
6.alert(a)结果为什么是undefined?
function aaa(){
var a=b=10;
}
aaa();
alert(a);//结果为,无法访问到
alert(b);//结果为10;
变量的查找是就近原则去寻找,定义的var变量;第二点,变量的声明被提前到作用域顶部,赋值保留在原地,
7.求各部分的输出结果并解释
function aaa(){
alert(a);
var a=20;
}
aaa(); //结果为:undefined
var a=10;
function aaa(){
alert(a);
var a=20;
}
aaa(); //结果为:undefined
可以解析为是:
var a=10;
function aaa(){
var a; //声明提前了
alert(a);
a=20; //赋值扔留着原地
}
aaa();
8. result=? 并解析
function test(){
var n=4399;
function add(){
n++;
console.log(n);//4400
}
return {
n:n,
add:add
}
}
var result=test(); //设置result的属性为:{n:4399,add:add()}
var result2=test(); //设置result2的属性为:{n:4399,add:add()}
result.add(); //调用result的add方法,执行n++,所以n=4399+1=4400,输出4400
result.add(); //再次调用result的add方法,此时n=4400,所以执行n++后,所以n=4401
console.log(result.n); //这是输出result属性n的值,所以输出4399
result2.add(); //调用result2的add方法,此时n=4399,所以执行n++后,所以n=4400
9.解释下面代码的输出结果
var color=‘green’;
var test4399={
color:‘blue’,
getColor:function(){
var color=‘red’;
alert(this.color);
}
}
var getColor=test4399.getColor;
getColor();
test4399.getColor();
输出 green blue
解析:
考察点一:js函数调用时加括号和不加括号的区别,加括号是把函数返回值赋给等号左边,而不加括号相当于把函数代码赋给等号左边。所以代码var getColor=test4399.getColor;相当于var getColor=function(){var color='red';alert(this.color);}
考察点二:js中this的用法,this总是指向调用它的对象。所以getColor();执行时,相当于Windows调用的,this指向Windows,所以找到的是全局变量中的color,为green。同理,test4399.getColor()是test4399调用的,this指向test4399,所以找的是test4399里的color,为blue。
10.求下面代码输出结果
function Foo(){
var i=0;
return function(){
document.write(i++);
}
}
var f1=Foo();
f2=Foo();
f1();//0
f1();//1
f2();//0
输出的结果是 0 1 0
解析:这是一个闭包,闭包的作用有两个,一是可以读取函数内部的变量,二是让这些变量的值始终保存在内存中。当f1()和f2()调用时,会创建两个执行环境,保存各自的变量对象,之间是没有相互影响的。而同一个函数多次调用时返回值会被保存到同一个变量对象中,因为闭包i会保存在内存中没有被释放。另外i++是先调用再+1,++i是先+1再调用,所以输出为 0 1 0。
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);//9999
console.log(c.n);//4400
输出为 9999 4400
理解:由题目可知,B和C的原型都指向A;b c 分别是B C的实例;然后A的n进行了一次自增,再分别调用两个实例对象看看输出n的值是多少。
解析:首先我们要知道new运算的具体执行过程:
(1)创建一个空对象
(2)把这个空对象的_proto_指向构造函数的prototype
(3)把这个空对象赋值给this
(4)执行构造函数内的代码
所以当执行var b=new B()时,此时的this指向了新对象,this.n=9999等价于b.n=9999,然后访问b.n,在查找b.n时首先是查找b对象自身有没有n属性,如果没有再去原型(prototype)上找,这里存在,所以返回9999;
同理,执行var c=new C()时,由于C()函数中只是定义了一个私有变量var n=8888,并没有为对象执行任何操作,也就是说这个变量属性没有绑定到new出来的对象c上,所以c实例中不存在名字为n的属性。因此,c.n会访问原型中的n属性。