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()()); // avar 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.prototypeconst 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';// 输出 cconsole.log(a1[b1]);var a2={}, b2=Symbol('123'), c2=Symbol('123');// b2 是 Symbol 类型,不需要转换。a2[b2]='b';// c2 是 Symbol 类型,不需要转换。任何一个 Symbol 类型的值都是不相等的,所以不会覆盖掉 b2。a2[c2]='c';// 输出bconsole.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';// 输出cconsole.log(a3[b3]);// 扩展除了前边的Symbol,如果想要不被覆盖 可以使用ES6提供的Mapvar 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') // => yidengsafeGet(data, 'a.b.c.d') // => undefinedsafeGet(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
