-
['1', '2', '3'].map(parseInt)的结果是什么?
Answer -
函数参数对象
arguments
与ES6新增的rest
参数都是数组吗?
Answer:arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,需先使用Array.prototype.slice.call先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。 -
箭头函数有几个使用注意点。
详细资料
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。(
箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。因为箭头函数没有 this,所以也不能用 call()、apply()、bind() 这些方法改变 this 的指向).
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
(2)不可以当作构造函数,即不可以使用new命令,否则会抛出一个错误。也就没有new.target
、原型
、super
。
(3)没有自己的 arguments 对象,可以用 rest 参数代替。但箭头函数可以访问外围函数的 arguments 对象。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
- super: 指向当前对象的原型对象。super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。(目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。)
// 报错
const obj = {
foo: super.foo
}
// 报错
const obj = {
foo: () => super.foo
}
// 报错
const obj = {
foo: function () {
return super.foo
}
}
// 正常
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
-
Object.assign: 将源对象(source)的所有可枚举属性(不包括继承属性),复制到目标对象(target)。
特点:
(1)属于浅拷贝:如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
(2)同名属性的替换。
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
(3)对数组的处理:将数组视为对象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
Object.assign把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1。
(4) 取值函数的处理: Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
上面代码中,source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去。
用途:
(1)为对象添加属性;
(2)为对象添加方法;
(3)克隆对象:将原始对象拷贝到一个空对象,就得到了原始对象的克隆。不过这样不会克隆原始对象继承的属性。如果想要保持继承链,可以采用下面的代码。
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
(4)合并多个对象;
(5)为属性指定默认值。
-
Symbol:ES6新引入的一种原始数据类型,表示独一无二的值。
详细资料
let s=Symbol();
typeof s; // symbol
Symbol函数前不能使用new命令,这是因为生成的 Symbol 是一个原始类型的值,不是对象。由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
-
js扩展运算符
...
:ES6新增,内部使用for...of循环,可将一个数组(或数组类似结构)转为用逗号分隔的序列。可用于:
(1)复制数组(对原数组无影响)
var a = ['1','2','3']
var b = [...a]
console.log(b) // ['1','2','3']
(2)拼接数组
var a = [1,2,3]
var a = [4,5,6]
a = [...a, ...b]
console.log(a) // [1,2,3,4,5,6]
(3)便于使用Math方法获取数组最大最小值
var a = [1,2,3,4,5]
var max = Math.max(...a)
console.log(max) // 5
(4)字符串转换为字符数组
var a = 'helloworld'
var b = [...a]
console.log(b) // ['h','e','l','l','o','w','o','r','l','d']
8-1. Set:字面意思就是集合,ES6新增的数据结构,类似于数组,但其中的元素不重复。
(1)可利用Set去除数组的重复元素:
[...new Set(array)]
// or
Array.from(new Set(array));
(2)可利用Set去除字符串中的重复字符:
[...new Set('abbccd')].join(''); // 'abcd'
(3)求集合的并集、交集、差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
8-2: WeakSet, Map, WeakMap:详细介绍
WeakSet
和 WeakMap
相比较对于的Set
和Map
,不同点:(1)成员(for Set)或键名(for Map)都只能是对象;
(2)成员或键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,(WeakSet)WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用,WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏。.
一个典型应用场景是,在网页的 DOM 元素上添加数据(例如说明性的信息),就可以使用WeakMap结构。当该 DOM 元素被清除,其所对应的WeakMap记录就会自动被移除。
const wm = new WeakMap();
const element = document.getElementById('example');
wm.set(element, 'some information');
wm.get(element) // "some information"
上面的 DOM 节点对象 element 的引用计数是1,而不是2。这时,一旦消除对该节点的引用,它占用的内存就会被垃圾回收机制释放。Weakmap 保存的这个键值对,也会自动消失。
注意,WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。
const wm = new WeakMap();
let key = {};
let obj = {foo: 1};
wm.set(key, obj);
obj = null;
wm.get(key); // Object {foo: 1}
上面代码中,键值obj是正常引用。所以,即使在 WeakMap 外部消除了obj的引用,WeakMap 内部的引用依然存在。
-
Proxy:可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Proxy 对象可以拦截目标对象的任意属性,这使得它很合适用来写 Web 服务的客户端。
this
问题:虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。
const target = {
m: function () {
console.log(this === proxy);
}
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m() // true
10.Reflect:详细介绍
Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。
(1) 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。)
(2) 修改某些Object方法的返回结果,让其变得更合理。
(3) 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
(4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Note:Reflect.apply
方法等同于Function.prototype.apply.call(func, thisArg, args)
,用于绑定this对象后执行给定函数。
一般来说,如果要绑定一个函数的this对象,可以这样写fn.apply(obj, args),但是如果函数定义了自己的 apply 方法,就只能写成Function.prototype.apply.call(fn, obj, args),采用Reflect对象可以简化这种操作。
利用 Proxy 和 Reflect 实现观察者模式
:
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。
下面,使用 Proxy 写一个观察者模式的最简单实现,即实现observable和observe这两个函数。思路是observable函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数。
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
上面代码中,先定义了一个Set集合,所有观察者函数都放进这个集合。然后,observable函数返回原始对象的代理,拦截赋值操作。拦截函数set之中,会自动执行所有观察者。
11.Promise:详细资料
简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,通过它可以获取异步操作的消息。(Promise一旦新建后就会立即执行)。
特点:
(1)Promise对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
缺点:
(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。
(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
(3)当处于pending状态时,无法得知具体进度信息(刚刚开始还是即将完成)。
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved
上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
then: then方法定义在原型对象Promise.prototype上,它的作用是为 Promise 实例添加状态改变时的回调函数。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
catch:是 then(null, rejection) 或 then(undefined, rejection) 的别名,用于指定发生错误时的回调函数。
(1)Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被catch语句捕获为止。(在有 catch 的前提下,如果没有catch,错误不会被捕获,也不会传递到外层。因为Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。)
(2)一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
(3)catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。(而且catch方法之中,还能再抛出错误。)
-
排序算法稳定性:不稳定:快选堆希
稳 定:插冒归基
13.iterator:详细介绍
它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
作用:
(1)为各种数据结构,提供一个统一的、简便的访问接口;
(2)使得数据结构的成员能够按某种次序排列;
(3) ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
原生具备 Iterator 接口的数据结构如下:
Array Map Set String TypedArray 函数的 arguments 对象
NodeList 对象
(除了Array、Map、Set,其他的都属于类数组结构(所谓类数组,就是存在数值键名和 length
属性))。
只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。
-
http常见简单例子:
(1)输入URL打开网页;
(2)AJAX获取数据;
(3)img标签加载图片; -
数组的reduce方法:缩小方法,接收两个参数,一个在每一个数组元素上调用的函数,一个(可选的)作为缩小基础的初始值。第一个参数是一个函数,它有4个参数:前一个值(prev),当前值(cur),当前项的索引,数组对象。这个函数的返回值会作为下一项的 prev。
如果指定了 reduce 方法中作为缩小基础的第二个参数(init),即初始值,那么第一次迭代发生在数组第一项上,即 prev=init, cur=arr[0].
否则,第一次迭代发生在数组第二项上,即 prev=arr[0], cur=arr[1].
网友评论