导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

针对性攻坚(TODO)


下面代码输出的结果?

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

如何才能打印出 0 1 2

解决方法:

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

⭐下面代码打印结果是什么?为什么?

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})();

解析:

IIFE 内部机制:

当遇到具名的函数表达式的时,会创建一个辅助的特定对象,将函数表达式的名称作为唯一的 key,用来存储函数表达式的名称,然后添加到函数的作用域链中,该值只读,并且不可以被删除,所以不能对该值进行操作。

所以,在严格模式下,一个不可修改的常量被修改之后就会报 TypeError: Assignment to constant variable

分析非严格模式的输出,在非严格模式下会静默失败,所以不报错。针对如上的分析之后,会输出立即执行的具名函数b本身。

var b = 10;
(function b() {
   // 内部作用域,会先去查找是有已有变量b的声明,有就直接赋值20,确实有了呀。发现了具名函数 function b(){},拿此b做赋值;
   // IIFE的函数无法进行赋值(内部机制,类似const定义的常量),所以无效。
  // (这里说的“内部机制”,想搞清楚,需要去查阅一些资料,弄明白IIFE在JS引擎的工作方式,堆栈存储IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();
// 严格模式下能看到错误:Uncaught TypeError: Assignment to constant variable

其他情况例子:

// 有window:
var b = 10;
(function b() {
  window.b = 20;
  console.log(b);
  console.log(window.b);
})();

// 有var:
var b = 10;
(function b() {
  var b = 20; // IIFE内部变量
  console.log(b);
  console.log(window.b);
})();

解析来源 ←

⭐ 输出以下代码执行的结果并解释为什么

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
};
obj.push(1);
obj.push(2);
console.log(obj);

解析参考:

结果最后变为一个稀疏数组[,,1,2]。 因为在对象中加入splice属性方法,和length属性后。这个对象变成一个类数组。属性名称可转换为数字时,会映射成为索引下标。所以对象实际可这样描述:[,,3,4],然后继续执行length 属性复制,length 原来值为4,length:2 语句将数组截断成为长度为2的数组。此时数组为[,,]。接着push(1)、push (2)。数组追加两个值,[,,1,2]。小菜看法,有错望指正!!!

参考来源:

下面代码中 a 在什么情况下会打印 1?

var a = ?;
if (a == 1 && a == 2 && a == 3) {
 	console.log(1);
}

解析:因为 == 会进行隐式类型转换 所以我们重写 toString 方法就可以了

答案:

var a = {
  i: 1,
  toString() {
  	return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3){
 	console.log(1);
}

⭐ 输出以下代码的执行结果并解释为什么

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };
console.log(a.x);
console.log(b.x);

解析:

var a = { n: 1 }; // a保持对{n:1}对象的引用
var b = a; // b保持对{n:1}对象的引用
a.x = a = { n: 2 }; // a的引用被改变

a.x 	// --> undefined
b.x 	// --> {n: 2}

// 画图
var a = { n: 1 }; // a 是个对象
var b = a;
a.x = a = { n: 2 };
console.log(a.x); // undefined
console.log(b.x); // { n: 2 }

/**
 * 栈             堆
 * a:002            001: { n: 1, x: 002 }
 * b:001            002: { n: 2 }
 */
  1. . 运算符优先,a.x 此时保持对 {n: 1} 的引用,也就是 b 也保持对 {n: 1} 的引用,于是 {n: 1} => {n: 1, x: undefined},此时 ab 还是对原来对象的引用,只不过原来对象增加了 x 属性
  2. = 从右往左,a = {n: 2},此时a的引用已经变成了 {n: 2} 这个对象
  3. a.x = a,此时 a.x 是保持对 { n: 1, x: undefined } 中的 x 引用,也就是 b.x ,于是 { n: 1, x: undefined } => {n: 1, x: { n: 2}},即 b.x = { n: 2 }题目来源:Daily-Interview-Question 第53题

输出以下代码运行结果

// example 1
var a = {}, b = '123', c = 123;
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
---------------------
// example 2
var a = {}, b = Symbol('123'), c = Symbol('123');
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
---------------------
// example 3
var a = {}, b = { key:'123' }, c = { key:'456' };
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);

分析:这题考察的是对象的键名的转换。

解答:

// example 1
var a = {}, b = '123', c = 123;
a[b]='b';
// c 的键名会被转换成字符串'123',这里会把 b 覆盖掉。
a[c]='c';
// 输出 c
console.log(a[b]);
// example 2
var a = {}, b = Symbol('123'), c = Symbol('123');
// b 是 Symbol 类型,不需要转换。
a[b]='b';
// c 是 Symbol 类型,不需要转换。任何一个 Symbol 类型的值都是不相等的,所以不会覆盖掉 b。
a[c]='c';
// 输出 b
console.log(a[b]);
// example 3
var a = {}, b = {key:'123'}, c = {key:'456'};
// b 不是字符串也不是 Symbol 类型,需要转换成字符串。
// 对象类型会调用 toString 方法转换成字符串 [object Object]。
a[b]='b';
// c 不是字符串也不是 Symbol 类型,需要转换成字符串。
// 对象类型会调用 toString 方法转换成字符串 [object Object]。这里会把 b 覆盖掉。
a[c]='c';
// 输出 c
console.log(a[b]);

题目来源:Daily-Interview-Question 第76题

以下代码中,当 foo 是哪些值的时候,会执行 alert ?

var foo = 'false';
    foo = 'true';
    foo = 1;
    foo = 0;
    foo = -1;
    foo = "";
    foo = undefined;
    foo = null;
    foo = NaN;
    foo = false;
    foo = [];
    foo = {};

if (!foo) { alert('foo') }

答案:

var foo = 'false'; // 不行 	非空字符串的字符串,Boolean() 后为真
    foo = 'true'; // 不行
    foo = 1; // 不行
    foo = 0; // 行
    foo = -1; // 不行				只有数字 0 Boolean 后才为 false ,其余数字都为 true
    foo = ""; // 行
    foo = undefined; // 行
    foo = null; // 行
    foo = NaN; // 行
    foo = false; // 行
    foo = []; // 不行
    foo = {}; // 不行

⭐ 以下代码运行输出结果是什么

var num = 100;
var fn = function() {
  var num = ++num;
  console.log(num);
}
fn();

解析:

函数执行时,寻找变量和形参提升,发现只有 num
所以 fn 的 ao 中 num: undefined
接着 num = ++num 也就是 num = ++undefined;
++undefined 为 NaN
所以最终打印 NaN

下面打印是什么

var obj1 = Object.create(null); 
obj1.a = 1;

var obj2 = Object.create(obj1);
obj2.b = 2;

console.log(obj2.__proto__);

原型存在在原型链上,但现在链不存在了(就是最终到达 Object.prototype 的这个链儿 在 obj1 这断掉了)

Untitled

⭐ 打印预测

var p1 = Promise.resolve( 1 );
var p2 = Promise.resolve( p1 );
var p3 = new Promise(function(resolve, reject){
  resolve(1);
});
var p4 = new Promise(function(resolve, reject){
  resolve(p1);
});

console.log(p1 === p2);
console.log(p1 === p3);
console.log(p1 === p4);
console.log(p3 === p4);

p4.then(function(value) {
  console.log('p4=' + value);
});

p2.then(function(value){
  console.log('p2=' + value);
})

p1.then(function(value){
  console.log('p1=' + value);
})
// 答案在下

// true
// false
// false
// false
// p2=1
// p1=1
// p4=1

Promise.resolve(...)可以接收一个值或者是一个Promise对象作为参数。
当参数是普通值时,它返回一个resolved状态的Promise对象,对象的值就是这个参数;
当参数是一个Promise对象时,它直接返回这个Promise参数。因此,p1 === p2。
但通过new的方式创建的Promise对象都是一个新的对象,因此后面的三个比较结果都是false。
另外,为什么p4的then最先调用,但在控制台上是最后输出结果的呢?
因为p4的resolve中接收的参数是一个Promise对象p1,resolve会对p1”拆箱“,获取p1的状态和值,
但这个过程是异步的

⭐ 预测结果