20
["1", "2", "3"].map(parseInt)
21
[typeof null, null instanceof Object]
答案:[“object”, false]
22
function f() {};const a = f.prototype,b = Object.getPrototypeOf(f);console.log(a === b);
答案:false
24
console.log([2,1,0].reduce(Math.pow));
console.log([].reduce(Math.pow));
==>
[2, 1, 0].reduce((acc, cur) => {
return Math.pow(acc, cur)
})
答案:1 报错
26
const value = 'Value is' + !!Number(['0']) ? 'yideng' : 'undefined';
console.log(value);
// 解答:+的优先级大于?
答案:yideng
28
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
执行流程分析
- 1.首先,事件循环从宏任务(macrotask)队列开始,这个时候,宏任务队列中,只有一个script(整体代码)任务;从宏任务队列中取一个任务出来执行。
- a.首先执行console.log(‘script start’) ,输出 ‘script start’ 。
- b.遇到setTimeout 把 console.log(‘setTimeout’) 放到macroTask队列中。
- c.执行async1(), 输出 ‘async1 start’ 和 ‘async2’ ,把 console.log(‘async1 end’) 放到micro 队列中。
- d.执行到promise , 输出 ‘promise1’ , 把 console.log(‘promise2’) 放到micro 队列中。
- e.执行 console.log(‘script end’) 。输出 ‘script end’
- 2.macrotask 执行完会执行microtask ,把 microtask quene 里面的 microtask 全部拿出来一次性执行完,所以会输出 ‘async1 end’ 和 ‘ promise2’
- 3.开始新一轮事件循环,去除一个macrotask执行,所以会输出 “setTimeout”。
下面代码的输出是什么?
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]); // 456
解析:
对象键自动转换为字符串。我们试图将一个对象设置为对象a
的键,其值为123
。
但是,当对象自动转换为字符串化时,它变成了[Object object]
。 所以我们在这里说的是a["Object object"] = 123
。 然后,我们可以尝试再次做同样的事情。 c
对象同样会发生隐式类型转换。那么,a["Object object"] = 456
。
然后,我们打印a[b]
,它实际上是a["Object object"]
。 我们将其设置为456
,因此返回456
。
下面代码的输出是什么?
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
// 1 undefined 2
解析:catch
块接收参数x
。当我们传递参数时,这与变量的x
不同。这个变量x
是属于catch
作用域的。
之后,我们将这个块级作用域的变量设置为1
,并设置变量y
的值。 现在,我们打印块级作用域的变量x
,它等于1
。
在catch
块之外,x
仍然是undefined
,而y
是2
。 当我们想在catch
块之外的console.log(x)
时,它返回undefined
,而y
返回2
。
闭包
var name = "a";
var object = {
name : "b",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); // a
var name = "c";
var object = {
name : "d",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); // d
num值?
const num = parseInt("7*6",10);
// 7
只返回字符串的第一个字母,检查字符串中合法的字符,一旦遇到一个在设置进制下不合法的字符,停止解析并忽略后面所有的字符
下面代码的输出是什么?
返回属性的时候,属性的值等于 返回的值,而不是构造函数中设定的值。
function Car() {
this.make = "a";
return {
make: "b"
}
}
const myCar = new Car();
console.log(myCar.make);
// b
作用域
var a = 1;
(function a () {
a = 2;
console.log(a);
})();
解释:立即执行函数,有自己独立的作用域,如果函数名称和内部变量名称冲突,就会永远执行函数本身
new一个函数,如果返回值是这个函数本身
function f(){
return f;
}
console.log(new f() instanceof f); // false
// new f() 返回的是f的函数对象
function f(){}
console.log(new f() instanceof f);
// 答案:true
getPrototypeOf
function f(){}
const a = f.prototype
const b= Object.getPrototypeOf(f)
console.log(a === b)
// false
// a === Object.getPrototypeOf(new f()) true
解析:
f.prototype
是new创建的f实例的原型Object.getPrototypeOf(f)
是f函数的原型
隐式转换
var a = ?;
if(a == 1 && a== 2 && a== 3){
console.log(1);
}
答案:
// 1.
var a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('1');
}
// 2.
var a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
// 3.
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("1");
}
// 4.
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('1');
}
object作为对象的key
var a1={}, b1='123', c1=123;
a1[b1]='b';
a1[c1]='c';
console.log(a1[b1]);
var a2={}, b2=Symbol('123'), c2=Symbol('123');
a2[b2]='b';
a2[c2]='c';
console.log(a2[b2]);
var a3={}, b3={key:'123'}, c3={key:'456'};
a3[b3]='b';
a3[c3]='c';
console.log(a3[b3]);
// 答案
c b c
// 考察知识点
- 对象的键名只能是字符串和 Symbol 类型。
- 其他类型的键名会被转换成字符串类型。
- 对象转字符串默认会调用 toString 方法。
// 解析
var a1={}, b1='123', c1=123;
a1[b1]='b';
// c1 的键名会被转换成字符串'123',这里会把 b1 覆盖掉。
a1[c1]='c';
// 输出 c
console.log(a1[b1]);
var a2={}, b2=Symbol('123'), c2=Symbol('123');
// b2 是 Symbol 类型,不需要转换。
a2[b2]='b';
// c2 是 Symbol 类型,不需要转换。任何一个 Symbol 类型的值都是不相等的,所以不会覆盖掉 b2。
a2[c2]='c';
// 输出b
console.log(a2[b2]);
var a3={}, b3={key:'123'}, c3={key:'456'};
// b3 不是字符串也不是 Symbol 类型,需要转换成字符串。对象类型会调用 toString 方法转换成字符串 [object Object]
a3[b3]='b';
// c3 不是字符串也不是 Symbol 类型,需要转换成字符串。对象类型会调用 toString 方法转换成字符串 [object Object]。这里会把 b3 覆盖掉。
a3[c3]='c';
// 输出c
console.log(a3[b3]);
// 扩展
除了前边的Symbol,如果想要不被覆盖 可以使用ES6提供的Map
var a=new Map(), b='123', c=123;
a.set(b,'b');
a.set(c,'c');
a.get(b); // 'b'
a.get(c); // 'c'
/*
Objects 和 Maps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Maps 使用。不过 Maps 和 Objects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择:
1.一个Object的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值,包括函数、对象、基本类型。
2.Map 中的键值是有序的,而添加到对象中的键则不是。因此,当对它进行遍历时,Map 对象是按插入的顺序返回键值。
*/
原型方法
function Foo() {
Foo.a = function () {
console.log(1);
};
this.a = function () {
console.log(2);
};
}
Foo.prototype.a = function () {
console.log(3);
};
Foo.a = function () {
console.log(4);
};
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
解析:
Foo.a()
这个是调用 Foo 函数的静态方法 a,虽然 Foo 中有优先级更高的属性方法 a,但 Foo 此时没有被调用,所以此时输出 Foo 的静态方法 a 的结果:4let obj = new Foo()
使用了 new 方法调用了函数,返回了函数实例对象,此时 Foo 函数内部的属性方法初始化,原型方法建立。
obj.a()
调用 obj 实例上的方法 a,该实例上目前有两个 a 方法:一个是内部属性方法,另一个是原型方法。当这两者重名时,前者的优先级更高,会覆盖后者,所以输出:2
Foo.a()
根据第2步可知 Foo 函数内部的属性方法已初始化,覆盖了同名的静态方法,所以输出:1
引用类型 函数传递
function user(obj) {
obj.name = "a"
obj = new Object()
obj.name = "b"
}
let person = new Object();
user(person);
console.log(person.name);
// a
解析: 对象作为参数,传递进去的是这个对象的地址,
obj.name
是给person这个对象赋值;obj = new Object()
把obj指向另一个对象,obj.name
现在是给这个新对象赋值,不影响person这个变量指向的对象;两个obj指向的对象的引用地址不同。
迭代
var obj = { x: 1, y: 2, z: 3 };
[...obj]; // TypeError
// 能否以某种方式为上面的语句使用展开运算而不导致类型错误
// 如果可以,写出解决方式
解析:
var obj = { x: 1, y: 2, z: 3 };
obj[Symbol.iterator] = function(){
// iterator 是一个具有 next 方法的对象,
// 它的返回至少有一个对象
// 两个属性:value&done。
return {
// 返回一个 iterator 对象
next: function () {
if (this._countDown === 3) {
const lastValue = this._countDown;
return { value: this._countDown, done: true };
}
this._countDown = this._countDown + 1;
return { value: this._countDown, done: false };
},
_countDown: 0,
};
};
// 还可以使用 generator 函数来定制对象的迭代行为:
var obj = { x: 1, y: 2, z: 3 };
obj[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
};
reduce
// 请你完成一个safeGet函数,可以安全的获取无限多层次的数据,一旦数据不存在不会报错,会返回 undefined,例如
var data = { a: { b: { c: 'yideng' } } }
safeGet(data, 'a.b.c') // => yideng
safeGet(data, 'a.b.c.d') // => undefined
safeGet(data, 'a.b.c.d.e.f.g') // => undefined
答案:
// 参考答案
const safeGet = (o, path) => {
try {
return path.split('.').reduce((o, k) => o[k], o)
} catch (e) {
return undefined;
}
}
质数算法
console.time('s')
function isPrime(number) {
if (typeof number !== "number" || !Number.isInteger(number)) return false;
if (number < 2) return false;
if (number === 2) {
return true;
} else if (number % 2 === 0) {
return false;
}
var squareRoot = Math.sqrt(number);
for (var i = 3; i <= squareRoot; i += 2) {
if (number % i === 0) {
return false;
}
}
return true;
};
console.log(isPrime(2711));
console.timeEnd('s')
连等
a=b=5 相当于 a = (b = 5)
首先
b
被赋值为 5,然后a
也被赋值为b = 5
的返回值,也就是 5