请看下题输出什么javascript
let i = 5;
for (let i = 0; console.log(i), i < 3; i++) {
let i = 'abc';
console.log(i);
}
// 输出
// 0
// abc
// 1
// abc
// 2
// abc
// 3
复制代码
上面的代码,首先最外层有一个let i = 5
; for循环体
里有let i = 0
; 若是这两个i在同一个做用域里确定会报错,这就说明这两个i不在赞成做用域,接着,咱们再看for循环体
里的i
和里面的i
是否在同一个做用域,经过输出内容,明显它们不在同一个做用域里。java
是的算法
const obj1 = {};
const obj2 = { name: 'xiaoming' };
Object.setPrototypeOf(obj1, obj2);
const { name } = obj1;
name // "xiaoming"
复制代码
// 错误的写法
let x;
{x} = {x: 1};
复制代码
上面代码的写法会报错,由于 JavaScript 引擎会将{x}
理解成一个代码块,从而发生语法错误,须要将整个结构语句放在圆括号里。数组
// 正确的写法
let x;
({x} = {x: 1});
复制代码
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
复制代码
上面代码中,length
属性的返回值,等于函数的参数个数减去指定了默认值的参数个数。promise
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
复制代码
若是设置了默认值的参数不是尾参数,那么length属性也再也不计入后面的参数了。浏览器
为何要提这个知识点呢,由于函数柯里化通用函数里,须要用到函数默认参数的个数,也就是length
属性,因此若是参数设置了默认值,会影响函数柯里化的结果。bash
Array.from方法用于将两类对象转为真正的数组:数据结构
定义提到Array.from
能够将类数组对象(注:类数组对象能够理解为有length属性的对象)能够转换为数组,那么以下:函数
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
复制代码
Array.from
还能够接受第二个参数,做用相似于数组的map
方法。学习
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)
复制代码
若是map
函数里面用到了this
关键字,还能够传入Array.from
的第三个参数,用来绑定this
。
if ([1, 2, 3].indexOf(2) !== -1) {
// ...
}
复制代码
indexOf
方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,因此要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)
进行判断,这会致使对NaN
的误判。
[NaN].indexOf(NaN)
// -1
复制代码
includes
使用的是不同的判断算法,就没有这个问题。
[NaN].includes(NaN)
// true
复制代码
[1, undefined, 2].join(); // "1,,2"
[1, undefined, 2].toString()]() // "1,,2"
[1, null, 2].join(); // "1,,2"
[1, null, 2].toString()]() // "1,,2"
复制代码
可枚举性
对象的每一个属性都有一个描述对象(Descriptor)
,用来控制该属性的行为。Object.getOwnPropertyDescriptor
方法能够获取该属性的描述对象。
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
复制代码
描述对象的enumerable属性,称为“可枚举性”,若是该属性为false,就表示某些操做会忽略当前属性。
属性的遍历
ES6 一共有 5 种方法能够遍历对象的属性。
for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys
返回一个数组,包括对象自身的(不含继承的)全部可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames
返回一个数组,包含对象自身的全部属性(不含 Symbol 属性,可是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols
返回一个数组,包含对象自身的全部 Symbol 属性的键名。
Reflect.ownKeys
返回一个数组,包含对象自身的全部键名,无论键名是 Symbol 或字符串,也不论是否可枚举。
以上的 5 种方法遍历对象的键名,都遵照一样的属性遍历的次序规则
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]
复制代码
上面代码中,Reflect.ownKeys方法返回一个数组,包含了参数对象的全部属性。这个数组的属性次序是这样的,首先是数值属性2和10,其次是字符串属性b和a,最后是 Symbol 属性。
是的
const obj = {
...(x > 1 ? {a: 1} : {}),
b: 2,
};
复制代码
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
复制代码
区别有两点
WeakSet
的成员只能是对象类型,而不能是其余类型的值。const ws = new WeakSet();
ws.add({a: 1}) // 正确
ws.add([1,2]) // 正确
wa.add(1) //错误
复制代码
同上,WeakMap和Map的区别也有两点
WeakMap
只接受对象做为键名(null除外),不接受其余类型的值做为键名。WeakMap
的键名所指向的对象,不计入垃圾回收机制为何下面的代码输出1
const handler = {
set: function(obj, prop, value, receiver) {
console.log(1)
}
};
const proxy = new Proxy({}, handler);
const myObj = {};
Object.setPrototypeOf(myObj, proxy);
myObj.foo = 'bar';
复制代码
缘由在于,若是myObj
的原型部署了set
方法,而且myObj
上没有foo
属性,此时,给myObj
的foo
属性赋值的话,会先看myObj
对象上是否有foo
属性,没有的话回去它的原型去找,此时就触发了proxy
的set
方法,因此打印了1
。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,由于x没有声明
resolve(x + 2);
});
};
someAsyncThing().then(function() {
console.log('everything is great');
});
setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123
复制代码
someAsyncThing
函数产生的 Promise
对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined
,可是不会退出进程、终止脚本执行,2
秒以后仍是会输出123
。Promise
内部的错误不会影响到 Promise
外部的代码,通俗的说法就是Promise 会吃掉错误
。代码以下,如何自动执行如下的generator函数(这种流程管理的代码适合同步任务,我认为能够称做js的职责责任链模式,很是方便流程管理)
function* runTask(value1) {
try {
var value2 = yield step1(value1);
var value3 = yield step2(value2);
} catch (e) {
}
}
复制代码
自动执行代码以下
scheduler(runTask(initialValue));
function scheduler(task) {
var taskObj = task.next(task.value);
// 若是Generator函数未结束,就继续调用
if (!taskObj.done) {
task.value = taskObj.value
scheduler(task);
}
}
复制代码