嵌套箭头函数
前一个函数的输出是后一个函数的输入
function insert(value) { return {into: function (array) { return {after: function (afterValue) { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }}; }}; } insert(2).into([1, 3]).after(1); //[1, 2, 3]
如上的例子
intro传入的[1,3]是after函数 after中的输入
let insert = (value) => ({into: (array) => ({after: (afterValue) => { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }})}); insert(2).into([1, 3]).after(1); //[1, 2, 3]
this的绑定
函数绑定运算符是并排的两个双冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); const hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) { return obj::hasOwnProperty(key); }
对象的扩展
var foo = ‘bar‘; var baz = {foo}; baz // {foo: "bar"}等同于
var baz = {foo: foo};
function f(x, y) { return {x, y}; } // 等同于 function f(x, y) { return {x: x, y: y}; } f(1, 2) // Object {x: 1, y: 2}
var o = { method() { return "Hello!"; } }; // 等同于 var o = { method: function() { return "Hello!"; } };
var birth = ‘2000/01/01‘; var Person = { name: ‘张三‘, //等同于birth: birth birth, // 等同于hello: function ()... hello() { console.log(‘我的名字是‘, this.name); } };
var ms = {}; function getItem (key) { return key in ms ? ms[key] : null; } function setItem (key, value) { ms[key] = value; } function clear () { ms = {}; } module.exports = { getItem, setItem, clear }; // 等同于 module.exports = { getItem: getItem, setItem: setItem, clear: clear };
var obj = { class () {} }; // 等同于 var obj = { ‘class‘: function() {} };
属性表达式
// 方法一 obj.foo = true; // 方法二 obj[‘a‘ + ‘bc‘] = 123;
let propKey = ‘foo‘; let obj = { [propKey]: true, [‘a‘ + ‘bc‘]: 123 };
var lastWord = ‘last word‘; var a = { ‘first word‘: ‘hello‘, [lastWord]: ‘world‘ }; a[‘first word‘] // "hello" a[lastWord] // "world" a[‘last word‘] // "world"
var foo = ‘bar‘; var baz = { [foo]: ‘abc‘};
方法name的属性
(new Function()).name // "anonymous" var doSomething = function() { // ... }; doSomething.bind().name // "bound doSomething"
对象的合并 Object.assign()
Object.assign
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
var target = { a: 1 }; var source1 = { b: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
var target = { a: 1, b: 1 }; var source1 = { b: 2, c: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
var v1 = ‘abc‘; var v2 = true; var v3 = 10; var obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
注意
Object.assign
方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。\
注意,Object.assign可以用来处理数组,但是会把数组视为对象。 Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3] 上面代码中,Object.assign把数组视为属性名为0、1、2的对象,因此源数组的0号属性4覆盖了目标数组的0号属性1。
Object.keys()
ES5 引入了Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
var obj = { foo: ‘bar‘, baz: 42 }; Object.keys(obj) // ["foo", "baz"]
let {keys, values, entries} = Object; let obj = { a: 1, b: 2, c: 3 }; for (let key of keys(obj)) { console.log(key); // ‘a‘, ‘b‘, ‘c‘ } for (let value of values(obj)) { console.log(value); // 1, 2, 3 } for (let [key, value] of entries(obj)) { console.log([key, value]); // [‘a‘, 1], [‘b‘, 2], [‘c‘, 3] }
Object.values()
Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
var obj = { foo: ‘bar‘, baz: 42 }; Object.values(obj) // ["bar", 42]
var obj = { 100: ‘a‘, 2: ‘b‘, 7: ‘c‘ }; Object.values(obj) // ["b", "c", "a"]
上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b
、c
、a
。
Object.values
只返回对象自身的可遍历属性。
var obj = Object.create({}, {p: {value: 42}}); Object.values(obj) // []
上面代码中,Object.create
方法的第二个参数添加的对象属性(属性p
),如果不显式声明,默认是不可遍历的,因为p
的属性描述对象的enumerable
默认是false
,Object.values
不会返回这个属性。只要把enumerable
改成true
,Object.values
就会返回属性p
的值。
var obj = Object.create({}, {p: { value: 42, enumerable: true } }); Object.values(obj) // [42]
Object.values
会过滤属性名为 Symbol 值的属性。
Object.values({ [Symbol()]: 123, foo: ‘abc‘ }); // [‘abc‘]
如果Object.values
方法的参数是一个字符串,会返回各个字符组成的一个数组
Object.values(‘foo‘) // [‘f‘, ‘o‘, ‘o‘]
如果参数不是对象,Object.values
会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values
会返回空数组。
Object.values(42) // [] Object.values(true) // []
let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
var o = Object.create({ x: 1, y: 2 }); o.z = 3; let { x, ...{ y, z } } = o; x // 1 y // undefined z // 3
上面代码中,变量x
是单纯的解构赋值,所以可以读取对象o
继承的属性;变量y
和z
是双重解构赋值,只能读取对象o
自身的属性,所以只有变量z
可以赋值成功。
解构赋值的一个用处,是扩展某个函数的参数,引入其他操作。
Set和Map
Set 结构不会添加重复的值。
Set 函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。
const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for (let i of s) { console.log(i); } // 2 3 5 4
上面代码通过add
方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。
Set 函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。
const set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4]
Set 结构的实例有四个遍历方法,可以用于遍历成员。 keys():返回键名的遍历器 values():返回键值的遍历器 entries():返回键值对的遍历器 forEach():使用回调函数遍历每个成员 需要特别指出的是,Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用Set保存一个回调函数列表,调用时就能保证按照添加顺序调用。 (1)keys(),values(),entries() keys方法、values方法、entries方法返回的都是遍历器对象(详见《Iterator 对象》一章)。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
let set = new Set([‘red‘, ‘green‘, ‘blue‘]); for (let item of set.keys()) { console.log(item); } // red // green // blue for (let item of set.values()) { console.log(item); } // red // green // blue for (let item of set.entries()) { console.log(item); } // ["red", "red"] // ["green", "green"] // ["blue", "blue"]
Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values
方法。
Set.prototype[Symbol.iterator] === Set.prototype.values
let set = new Set([‘red‘, ‘green‘, ‘blue‘]); for (let x of set) { console.log(x); } // red // green // blue