一、变量提升的习题
1.下列代码的输出结果
console.log(a, b, c);
var a = 12,
b = 13,
c = 14;
function fn(a) {
console.log(a, b, c);
a = 100;
c = 200;
console.log(a, b, c);
}
b = fn(10);
console.log(a, b, c);
/*
undefined undefined undefined
10 13 14
100 13 200
12 undefined 200
*/
习题解析:
/*
* EC(G)中的变量提升
* var a;
* var b;
* var c;
* fn = 0x000; [[scope]]:EC(G)
*/
console.log(a, b, c); //=>undefined * 3
var a = 12,
b = 13,
c = 14;
function fn(a) {
/*
* EC(FN)私有上下文
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:a=10
* 变量提升:--
*/
console.log(a, b, c); //=>10 13 14
a = 100;//私有a赋值100
c = 200;//全局c赋值200
console.log(a, b, c); //=>100 13 200
}
b = fn(10);//全局b赋值undefined
console.log(a, b, c); //=>12 undefined 200
2.下列代码的输出结果
var i = 0;
function A() {
var i = 10;
function x() {
console.log(i);
}
return x;
}
var y = A();
y();
function B() {
var i = 20;
y();
}
B();
/*
10 10
*/
习题解析:
/*
* EC(G)变量提升
* var i;
* A = 0x000; [[scope]]:EC(G)
* var y;
* B = 0x001; [[scope]]:EC(G)
*/
var i = 0;
function A() {
/*
* EC(A)私有上下文
* 作用域链:<EC(A),EC(G)>
* 形参赋值:--
* 变量提升:
* var i;
* x = 0x002; [[scope]]:EC(A)
*/
var i = 10;
function x() {
/*
* EC(X1)私有上下文
* 作用域链:<EC(X1),EC(A)>
* 形参赋值:--
* 变量提升:--
*/
/*
* EC(X2)私有上下文
* 作用域链:<EC(X2),EC(A)>
* 形参赋值:--
* 变量提升:--
*/
console.log(i);
}
return x; //return 0x002;
}
var y = A(); //y=0x002;
y(); //=>10
function B() {
/*
* EC(B)私有上下文
* 作用域链:<EC(B),EC(G)>
* 形参赋值:--
* 变量提升:
* var i;
*/
var i = 20;
y();//=>10
}
B();
3.下列代码的输出结果
var a = 1;
var obj = {
name: "tom"
}
function fn() {
var a2 = a;
obj2 = obj;
a2 = a;
obj2.name = "jack";
}
fn();
console.log(a);
console.log(obj);
/*
1
{ name: 'jack' }
*/
习题解析:
/*
* EC(G)变量提升
* var a;
* var obj;
* fn = 0x000; [[scope]]:EC(G)
*/
var a = 1;
var obj = {
name: "tom"
}; //obj=0x001
function fn() {
/*
* EC(FN)
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:--
* 变量提升:var a2;
*/
var a2 = a; //私有a2=1
obj2 = obj;
//obj2不是私有的,向全局找,如果全局也没有
// 情况1:输出obj2 直接报错 Uncaught ReferenceError: obj2 is not defined
// 情况2:赋值操作 相当于给window设置一个obj2的属性,并且赋值 window.obj2=0x001
a2 = a; //私有a2=1
obj2.name = "jack"; //遇到obj2,但是发现全局没有这个变量,它会继续再看window下是否有这个属性,如果window下有这个属性,则获取属性值,如果window下也没有这个属性,则报错(未定义变量) ->把0x001中的name属性值改为'jack'
}
fn();
console.log(a);//=>1
console.log(obj);//=>{name:'jack'}
- VO(G):全局变量对象「全局上下文中声明的变量」
- GO「window」:全局对象 「浏览器默认开辟的一个堆内存,存储供JS调用的各种API的」
- 【console.log(a);】首先看VO(G)中是否有变量a,如果没有,则再看GO中有没有,如果也没有,则报错:a is not defined
- 在全局上下文中【var n = 10;】:
- 老版本机制:VO(G)中声明一个n的全局变量,赋值10;特殊:“全局上下文”中,“基于var/function声明”的变量,也相当于给GO新增私有属性;并且之间存在映射关系「一个修改,另外一个也跟着修改」;
- 新版本机制:“全局上下文”中,“基于var/function声明”的变量,直接都当做GO的属性存储起来;
- 基于let/const声明的变量,只是给VO(G)中设置全局变量,和GO没有任何的关系;
举例说明:1/2
var n = 10;
console.log(n); //=>10
console.log(window.n); //=>10
m = 10; //给GO设置一个属性m -> window.m=10
console.log(m); //=>10
console.log(window.m); //=>10
举例说明:3
//基于let/const声明的变量,只是给VO(G)中设置全局变量,和GO没有任何的关系;
let n = 10;
console.log(n); //=>10
console.log(window.n); //=>undefined
debugger调试
debugger;
var a1 = 10;
let a2 = 20;
function a3(){
初始状态:
第一步:
第二步:
第三步:
4.下列代码的输出结果
var a = 1;
function fn(a) {
console.log(a)
var a = 2;
function a() { }
}
fn(a);
/*
ƒ a() { }
[Function: a]
*/
解析如下:
/*
* EC(G)变量提升
* var a;
* fn=0x000; [[scope]]:EC(G)
*/
var a = 1;
function fn(a) {
/*
* EC(FN)
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:a=1
* 变量提升:
* var a; 「没用了:因为此时私有上下文中已经有a了,不会重复声明」
* a=0x001; [[scope]]:EC(FN) 「不会重复声明,但是需要重新赋值」
*/
console.log(a); //=>函数
var a = 2; //私有a重新赋值为2
function a() {}
console.log(a); //=>2
}
fn(a); //fn(1)
console.log(a); //=>1
5.下列代码的输出结果
console.log(a);
var a = 12;
function fn() {
console.log(a);
var a = 13;
}
fn();
console.log(a);
/*
undefined
undefined
12
*/
//----
console.log(a);
var a = 12;
function fn() {
console.log(a);
a = 13;
}
fn();
console.log(a);
/*
undefined
12
13*/
//----
console.log('ok');//'ok'
console.log(a);//Uncaught ReferenceError: a is not defined
a = 12;
function fn() {
console.log(a);
a = 13;
}
fn();
console.log(a);
解析如下:
/*
* EC(G)变量提升
* var a;
* fn=0x000; [[scope]]:EC(G)
*/
console.log(a); //=>undefined
var a = 12;
function fn() {
/*
* EC(FN)
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:--
* 变量提升:var a;
*/
console.log(a); //=>undefined
var a = 13;
}
fn();
console.log(a); //=>12
/*
* EC(G)变量提升
* var a;
* fn=0x000; [[scope]]:EC(G)
*/
console.log(a); //=>undefined
var a=12;
function fn(){
/*
* EC(FN)
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:--
* 变量提升:--
*/
console.log(a); //=>12
a=13;
}
fn();
console.log(a); //=>13
/*
* EC(G)变量提升
* fn=0x000; [[scope]]:EC(G)
*/
console.log(a); //先看VO(G)中是否有,没有再看GO中是否有,也没有 Uncaught ReferenceError: a is not defined
a=12;
function fn(){
console.log(a);
a=13;
}
fn();
console.log(a);
6.下列代码的输出结果
var foo = 'hello';
(function (foo) {
console.log(foo);
var foo = foo || 'world';
console.log(foo);
})(foo);
console.log(foo);
解析如下:
A||B A如果为假返回B的值,A为真返回A的值
A&&B A如果为假返回A的值,A为真返回B的值
同时存在 &&优先级高于|| 0||1&&2||3–>2
/*
* EC(G)变量提升
* var foo;
*/
var foo = 'hello';
(function (foo) {
/*
* EC(AN)
* 作用域链:<EC(AN),EC(G)>
* 形参赋值:foo='hello'
* 变量提升:var foo;【foo已经存在了,再声明就没用了,值依然是'hello',做错是因为:误以为重新声明值会变为undefined,实际是已经存在的变量浏览器就不会再重复声明且重复赋值为undefined了】
*/
console.log(foo); //=>'hello'
var foo = foo || 'world';
console.log(foo); //=>'hello'
})(foo); //自执行函数执行,把全局foo的值“hello”当做实参传递进来
console.log(foo); //=>'hello'
7.下列代码的输出结果
//老版本浏览器IE11及以下
{
function foo() { }
foo = 1;
}
console.log(foo);
图解:
//----
console.log(foo);
{
function foo() { }
foo = 1;
function foo() { }
console.log(foo);
}
console.log(foo);
//----
{
function foo() { }
foo = 1;
function foo() { }
foo = 2;
console.log(foo);
}
console.log(foo);
习题解析:
/*
* EC(G)中的变量提升
* function foo;
* function foo;
*/
console.log(foo); //=>undefined
{
/*
* EC(B)变量提升
* foo = 0x000;
* foo = 0x001;
*/
console.log(foo); //=>0x001
function foo() {0} //特殊:之前对foo的操作都给全局一份 全局foo=0x001
console.log(window.foo); //=>0x001
foo = 1;
function foo() {1} //特殊:之前对foo的操作都给全局一份 全局foo=1
console.log(foo); //=>1
}
console.log(foo); //=>1
//---------------------
{
function foo() {}
foo = 1;
function foo() {} //特殊:之前对foo的操作都给全局一份
foo = 2;
}
console.log(foo); //=>1
8.下列代码的输出结果
var x = 1;
function func(x, y = function anonymous1() { x = 2 }) {
x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
图解:
- 如果函数应用了“形参赋值默认值「不论赋值为啥,也不论是否传递实参」”:
- 并且函数体中出现了基于var/let/const等声明变量的方式(特殊: let/const声明的变量不能和形参一样,否则报重复声明的错误)【function声明的不会】
=>这样除了函数执行,会产生一个私有的上下文之外「步骤运行到形参赋值后就结束」
=>会把函数体及其中的代码当做一个“全新的块级上下文”
1)上级上下文是私有的上下文
2)如果块级上下文中声明的变量和函数私有上下文中的形参变量一致了,则在块级上下文代码执行之前,会把形参变量的值同步给块级上下文中的变量
最后打印出来的变量是私有上下文Local中的变量,与Block中的变量无关。
var x = 1;
function func(x, y = function anonymous1() { x = 2 }) {
var x = 3;
y();
console.log(x);
}
func(5);
console.log(x);
图解:
第一步:
第二步:
第三步:
第四步:
第五步:
第六步:
var x = 1;
function func(x, y = function anonymous1() { x = 2 }) {
var x = 3;
var y = function anonymous2() { x = 4 };
y();
console.log(x);
}
func(5);
console.log(x);
第一步:debugger Local:函数func的私有上下文。Block:块级上下文,block的上级上下文就 是local
第二步:debugger
第三步:debugger
第四步:debugger
第五步:
第六步:
第七步:
二、数据类型和基础知识习题
1.下列代码的输出结果
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result);
2.下列代码的输出结果
{}+0?alert('ok'):alert('no');
0+{}?alert('ok'):alert('no');
3.下列代码的输出结果
let res = Number('12px');
if(res===12){
alert(200);
}else if(res===NaN){
alert(NaN);
}else if(typeof res==='number'){
alert('number');
}else{
alert('Invalid Number');
}
4.下列代码的输出结果
let arr = [27.2,0,'0013','14px',123];
arr = arr.map(parseInt);
console.log(arr);
三、闭包作用域的习题
1.下列代码的输出结果
var a = 10,
b = 11,
c = 12;
function test(a) {
a = 1;
var b = 2;
c = 3;
}
test(10);
console.log(a, b, c);
2.下列代码的输出结果
var a = 4;
function b(x, y, a) {
console.log(a);
arguments[2] = 10;
console.log(a);
}
a = b(1, 2, 3);
console.log(a);
3.下列代码的输出结果
var a = 9;
function fn() {
a = 0;
return function (b) {
return b + a++;
}
}
var f = fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);
4.下列代码的输出结果
var test = (function (i) {
return function () {
alert(i *= 2);
}
})(2);
test(5);
5.下列代码的输出结果
var x = 4;
function func() {
return function(y) {
console.log(y + (--x));
}
}
var f = func(5);
f(6);
func(7)(8);
f(9);
console.log(x);
6.下列代码的输出结果
var x = 5,
y = 6;
function func() {
x += y;
func = function (y) {
console.log(y + (--x));
};
console.log(x, y);
}
func(4);
func(3);
console.log(x, y);
7.下列代码的输出结果
function fun(n, o) {
console.log(o);
return {
fun: function (m) {
return fun(m, n);
}
};
}
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);
8.简述你对闭包的理解,以及其优缺点?
9.简述let和var的区别?
10.下面代码输出的结果是多少,为什么?如何改造一下,就能让其输出 20 10?
var b = 10;
(function b() {
b = 20;
console.log(b);
})();
console.log(b);
- 实现函数fn,让其具有如下功能(百度二面)
let res = fn(1,2)(3);
console.log(res); //=>6 1+2+3
四、THIS的相关习题
1.下列代码的输出结果
var num = 10;
var obj = {
num: 20
};
obj.fn = (function (num) {
this.num = num * 3;
num++;
return function (n) {
this.num += n;
num++;
console.log(num);
}
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num);
2.下列代码的输出结果
let obj = {
fn: (function () {
return function () {
console.log(this);
}
})()
};
obj.fn();
let fn = obj.fn;
fn();
3.下列代码的输出结果
var fullName = 'language';
var obj = {
fullName: 'javascript',
prop: {
getFullName: function () {
return this.fullName;
}
}
};
console.log(obj.prop.getFullName());
var test = obj.prop.getFullName;
console.log(test());
4.下列代码的输出结果
var name = 'window';
var Tom = {
name: "Tom",
show: function () {
console.log(this.name);
},
wait: function () {
var fun = this.show;
fun();
}
};
Tom.wait();
5.下列代码的输出结果
window.val = 1;
var json = {
val: 10,
dbl: function () {
this.val *= 2;
}
}
json.dbl();
var dbl = json.dbl;
dbl();
json.dbl.call(window);
alert(window.val + json.val);
6.下列代码的输出结果
(function () {
var val = 1;
var json = {
val: 10,
dbl: function () {
val *= 2;
}
};
json.dbl();
alert(json.val + val);
})();