导航
for(var i = 0; i < 3; i++){
setTimeout(function(){
console.log(i);
},0);
};
解决方法:
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]。小菜看法,有错望指正!!!
参考来源:
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 }
*/
.
运算符优先,a.x
此时保持对 {n: 1}
的引用,也就是 b
也保持对 {n: 1}
的引用,于是 {n: 1} => {n: 1, x: undefined}
,此时 a
和 b
还是对原来对象的引用,只不过原来对象增加了 x
属性=
从右往左,a = {n: 2}
,此时a的引用已经变成了 {n: 2}
这个对象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题
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 这断掉了)
自己.__proto__
找到原型,为 undefined(也就是指针不指向任何原型了,就是 undefined 了)__proto__
是原型链的指针,原型链都被破坏了,这个指针也断了__proto__
是 Object 的 属性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的状态和值,
但这个过程是异步的