跳到主要内容

数据类型

字符串

  • str.toString('进制')
  • str.charAt(index)str[index]:返回索引对应的字符
  • str.concat(str1,str2,str3...)
  • str.indexOf()str.lastIndexOf(); // 返回索引或-1
  • str.trim(): 去除字符串两边的空格
  • str.toUpperCase():转换大写
  • str.toLowerCase():转换小写
  • str.replace(oldStr,newStr):字符串替换
  • str.split('...'): 把一个字符串分割成字符串数组
  • for···of···: 字符串的遍历器接口
  • includes() startsWith() endsWith()
  • padStart() padEnd(): 字符串补全
  • repeat(num): 将源字符串复制 num 遍,返回新的字符串
// 字符串.slice(start, end); // 前包后不包
// slice() substring() substr() 第一个参数是开始位置,
// slice() substring() 第二个参数是结束位置
// substr() 第二个参数是 返回的长度
let str = abcdefg;
console.log(str.slice(2, 4)); // cd
console.log(str.substring(2, 4)); // cd
console.log(str.substr(2, 4)); // cdef

数组

ES5 数组方法

// 检测数组
Array.isArray(arr);
arr instanceof Array;

// 转换方法
arr.toLocaleString();
arr.toString();
arr.valueOf();

// 栈方法(后进先出)
arr.push(item1,item2,....,itemx); // 添加元素,返回值为数组的长度,并且原数组会发生变化
arr.pop(item1,item2,....,itemx); // 删除并返回数组的最后一个元素,原数组会发生变化

// 队列方法(先进先出)
arr.unshift(newelement1,newelement2,....,newelementX); // 向数组的开头添加一个或更多元素,并返回新的长度。【原数组会发生变化】
arr.shift(); // 删除并返回数组的第一个元素 【原数组会发生变化】

// 颠倒数组中元素的顺序。返回颠倒后的数组 【原数组会发生变化】
arr.reverse();

// 对数组的元素进行排序
arr.sort(); // 默认排序顺序是根据字符串 Unicode 编码

arr.sort(function (a, b) {
return a - b; // 升序(从小到大)
});
arr.sort(function (a, b) {
return b - a; // 降序(从大到小)
});

// 数组拼接
arr.concat(arr01,arr02,...) // 返回新的数组

// 数组拼接
arr.join(separator);

// 从已有的数组中返回选定的元素。【截取后,不会改变原数组,而是返回新的数组】
arr.slice(start,end); // 只有 start,将会截取到数组末尾
// 如果 start 的值为负数,假如数组长度为 length,则表示从 length+start 的位置开始复制,
// 此时参数 end 如果有值,只能是比 start 大的负数,否则将返回空数组。
[1,2,3].slice(-1); // [3]

// 向/从数组中添加/替换项目,然后返回被替换出来的项目。【原数组会发生变化】
arr.splice(index, howmany, item1, ..., itemX)
// 参数:
// index 从哪个索引位置开始删 数字
// howmany 替换几个 数字
// item1,.....,itemX 替换的数据(可以是多个) 可选

// 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1
arr.indexOf(searchElement);
// 返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找
arr.lastIndexOf(searchElement);

ES6 数组方法

// 数组遍历
array.forEach(function (value, index, currentArray) {});

// 过滤出符合筛选条件的元素,返回一个新的数组
array.filter(function (value, index, currentArray) {
return 条件;
});

// 验证数组中的每一个元素是否都符合指定的条件,返回布尔值
array.every(function (value, index, currentArray) {
return 条件;
});

// 验证数组中的元素,是否有符合指定条件的,返回布尔值
array.some(function (value, index, currentArray) {
return 条件;
});

// 遍历数组中的每一个元素,更改后存入一个新的数组中,返回一个新的数组
array.map(function (value, index, currentArray) {
return 操作;
});

array.reduce(callback(previousValue, currentValue, index, array)[, initialValue])

copyWithin() 复制数组项

// 数组实例的copyWithin()方法会在当前数组内部将指定位置的成员复制到其他位置(会覆盖原成员),返回新数组
// Array.prototype.copyWithin(target, start = 0, end = this.length)
// target 可选,从该位置替换数据
// start 可选,从该位置读取数据,默认是0
// end 可选,到该位置前停止读取数据,默认等于数组长度。如果是负值,表示倒数

find() 和 findIndex()

// .find() 找出第一个符合条件的数组成员,参数是一个回调函数
// 所有数组成员一次执行该回调函数,直到找到第一个返回为true的成员,然后返回该成员
// 如果么有符合从条件的成员,则返回undefined。 findIndex() 返回 索引
  • fill() 给定值填充到一个数组中,返回值为新数组
  • entries() keys() values() -- 用于遍历数组
  • includes() 方法返回的是一个布尔值,表示数组是否包含给定的值
  • Array.from() 将类数组对象转化为真正的数组
  • Array.of() 将一组值转化为数组

数组的空位

// 空位不是 `undefined`
console.log(Array(3)); // [empty × 3]
  • forEach()filter()every()some() 都会跳过空位
  • map() 会跳过空位,但是会保留这个值
  • join()toString() 会将空位视为 undefined
  • undefinednull 会被处理成空字符串
  • ES6 明确将空位转化为 undefined

对象

  1. Object.assign(target, ...sources):将一个或多个源对象的所有可枚举属性复制到目标对象,并返回目标对象。
  2. Object.create(proto, [propertiesObject]):使用指定的原型对象和可选的属性对象创建一个新对象。
  3. Object.defineProperty(obj, prop, descriptor):将一个属性添加到对象或修改现有属性的特性。
  4. Object.defineProperties(obj, props):将多个属性添加到对象或修改现有属性的特性。
  5. Object.entries(obj):返回一个给定对象自身可枚举属性的键值对数组。
  6. Object.freeze(obj):冻结一个对象,使其不可修改,包括属性和原型。
  7. Object.fromEntries(iterable):将一个键值对数组转换为一个对象。
  8. Object.getOwnPropertyDescriptor(obj, prop):返回指定对象上一个自有属性对应的属性描述符。
  9. Object.getOwnPropertyDescriptors(obj):返回指定对象上所有自有属性对应的属性描述符。
  10. Object.getOwnPropertyNames(obj):返回一个数组,包含指定对象所有自有属性的名称。
  11. Object.getOwnPropertySymbols(obj):返回一个数组,包含指定对象所有自有 Symbol 类型属性的 Symbol 值。
  12. Object.getPrototypeOf(obj):返回指定对象的原型。
  13. Object.is(value1, value2):比较两个值是否相等,与 === 运算符不同,Object.is() 方法认为 NaN-0 是不同的。
  14. Object.keys(obj):返回一个数组,包含指定对象所有自有可枚举属性的名称。
  15. Object.preventExtensions(obj):阻止一个对象扩展,使其不能添加新属性。
  16. Object.seal(obj):封闭一个对象,使其不能添加新属性,同时将所有现有属性设置为不可配置。
  17. Object.setPrototypeOf(obj, proto):设置一个对象的原型为另一个对象或 null
  18. Object.values(obj):返回一个数组,包含指定对象所有自有可枚举属性的值。
  19. Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性),返回值:表示给定对象是否可扩展的一个 Boolean。

属性描述符

JavaScript 中的属性描述符(Property Descriptor)是一个包含对象属性相关信息的数据结构,它可以用来定义和控制属性的行为和特性。每个对象属性都有一个相关的属性描述符,可以通过 Object.getOwnPropertyDescriptor() 方法来获取该属性的描述符。

Object.defineProperty()

Object.defineProperty()` 是 JavaScript 中一个非常重要的方法,它可以用来定义对象属性的行为和特性。具体来说,它可以用来实现以下功能:

  1. 定义新的对象属性或修改已有属性的特性:通过 Object.defineProperty() 方法,我们可以重新定义一个对象的已有属性或者创建一个新的属性,并指定该属性的特性(例如是否可读写、是否可枚举、是否可删除等)。
  2. 实现数据绑定或拦截器:通过在属性描述符中定义 getset 访问器方法,我们可以实现数据绑定或拦截器,即在属性值被获取或设置时执行一些自定义逻辑。
  3. 禁止对象扩展或密封:通过属性描述符的 configurable 属性,我们可以禁止对象的扩展或密封,从而防止新属性的添加、已有属性的删除或属性特性的修改。

需要注意的是,Object.defineProperty() 方法只能对对象的直接属性进行操作,而不能对对象的原型链属性进行操作。如果想要对整个对象或对象的原型链进行操作,可以使用其他方法,例如 Object.defineProperties()Object.create()Object.setPrototypeOf() 等。

如何判断对象上是否包含某个属性

  1. in 操作符:in 操作符会检查属性是否在对象及其原型链中。
  2. Object.hasOwnProperty() 方法只会检查属性是否在对象上,不会检查原型链。
  3. Object.getPrototypeOf() 方法可以用来获取一个对象的原型对象。如果一个属性不在对象自身的属性列表中,可以使用该方法来判断该属性是否在原型链上。
  4. Object.prototype.hasOwnProperty.call() 方法

Object.prototype.hasOwnProperty.call() 方法可以用来判断一个属性是否在对象的原型链上。具体做法是使用 call() 方法将 Object.prototype.hasOwnProperty() 方法绑定到对象上,并将属性名作为参数传入该方法。

const obj = {};
console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); // false

遍历对象属性的方法

  1. for...in 循环:使用 for...in 循环可以遍历对象自身及其原型链上的所有可枚举属性,因此需要使用 Object.hasOwnProperty() 方法来判断属性是否是对象自身的属性。
  2. Object.keys() 方法:Object.keys() 方法可以返回一个数组,该数组包含对象自身的所有可枚举属性的属性名。因此,可以使用该方法来遍历对象自身的属性。
  3. Object.getOwnPropertyNames() 方法:该方法可以返回一个数组,该数组包含对象自身的所有属性的属性名,无论它们是否可枚举。因此,可以使用该方法来遍历对象自身的所有属性。

Symbol

概述

为了减少对象的属性名冲突,ES6 引入新的原始数据类型 Symbol,JS 的第七种数据类型。

Symbol 能够保证每个属性的名字都是独一无二,这样就能从根本上防止属性名冲突。

Symbol 值能够通过Symbol函数生成,也就是说,对象的属性名现在可以有 2 种类型,一种就是原来的字符串,另一种就是新增的Symbol 类型。

  • Symbol 函数前不使用 new 命令,因为生成的 Symbol 是一个原始类型的值,不是对象,那么,也就不能添加属性(类似于字符串的数据类型)
  • Symbol 函数乐意接受一个字符串作为参数,表示 Symbol 实例的描述,主要是为了在控制台显示,或者转化为字符串为了区分(注意,相同参数返回值是不相同的!)
let s1 = Symbol('s1');
let s2 = Symbol('s2');
let s3 = Symbol('s2');
console.log(s1, s2); // Symbol(s1) Symbol(s2)
console.log(s1.toString(), s2.toString()); // Symbol(s1) Symbol(s2)
console.log(s2 == s3); // false
console.log(s2 === s3); // false

作为属性名的 Symbol

Symbol 值可以作为标识符用于对象的属性名,保证不会出现同名的属性。这对于一个对象有多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

let mySymbol = Symbol();
/` 第一种写法 */;
let a1 = {};
a1[mySymbol] = 'holle!';
/` 第二种写法 */;
let a2 = {
[mySymbol]: 'holle!'
};
/` 第三种写法 */;
let a3 = {};
Object.defineProperty(a3, mySymbol, { value: 'holle!' });

console.log(a1[mySymbol]); // holle!
console.log(a2[mySymbol]); // holle!
console.log(a3[mySymbol]); // holle!

注意:Symbol 值作为对象的属性名不能使用点运算符,点后面是字符串,不是 Symbol 类型!

Symbol 定义常量

常量使用 Symbol 值的最大的好处就是,其他任何值都不可能有相同的值了。

let log = {};
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
};

消除魔术字符串

魔术字符串是指,在代码中多次出现、与代码形成强耦合的某一个具体字符串或数值。风格良好的代码,应该尽量消除魔术字符串,而又含义清晰的变量代替。

/* 字符串Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。 */
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔术字符串
area = 0.5 * options.width * options.height;
break; /* ... more code ... */
}
return area;
}

getArea('Triangle', {
width: 100,
height: 100
}); // 魔术字符串

常用的消除魔术字符串的方法,就是把它写成一个变量。

我们把 Triangle 写成 shapeType 对象的 triangle 属性,这样就消除了强耦合。

可以发现 shapeType.triangle 等于哪个值并不重要,只要确保不会跟其他 shapeType 属性的值冲突即可。

const shapeType = {
triangle: Symbol('Triangle')
};

function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = 0.5 * options.width * options.height;
break;
}
return area;
}

getArea(shapeType.triangle, {
width: 100,
height: 100
});

属性名的遍历

Symbol 属性遍历:Object.getOwnPropertySymbols 方法获取指定对象的所有 Symbol 属性。

let keySymbolName = Symbol('name');
let keySymbolAge = Symbol('age');
var a = {
[keySymbolName]: 'houfee',
[keySymbolAge]: 24
};
let arr = Object.getOwnPropertySymbols(a);
console.log(arr); // [Symbol(name), Symbol(age)]

Set 和 Map

Set

Set 本身是一个构造函数,用来生成 Set 数据结构。Set 数据结构类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();

console.log(typeof s); // object

// 通过add方法向 Set 结构加入成员
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

console.log(s); // Set { 2, 3, 5, 4 }

for (let i of s) {
console.log(i);
}

参数

// 接受数组作为参数
const set = new Set([1, 2, 3, 4, 4]);
console.log(set); // [1, 2, 3, 4]
console.log(set.size); // 4

// 接受类似数组的对象作为参数
const set1 = new Set(...document.querySelectorAll('div'));

// 数组去重简单方法:
Array.from(new Set(set));
let arr = [...new Set(set)];

Set 的方法

  • add(value):添加某个值,返回 Set 结构本身。

  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功

  • has(value):返回一个布尔值,表示该值是否为 Set 的成员

  • clear():清除所有成员,没有返回值

使用 Set 实现并集(Union)、交集(Intersect)和差集(Difference):

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}

WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。

  1. WeakSet 的成员只能是对象和 Symbol 值,而不能是其他类型的值。
  2. WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

WeakSet 结构有以下三个方法。

  • WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员,返回 WeakSet 结构本身。
  • WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员,清除成功返回 true,如果在 WeakSet 中找不到该成员或该成员不是对象,返回 false。
  • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

Map

ES6 提供了 Map 数据结构,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。

// 使用对象作为键
const m = new Map();
const o = {
p: 'Hello World'
};

m.set(o, 'holle world!');
m.get(o); // "holle world!"

m.has(o);
m.delete(o);
m.has(o);

Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

const map = new Map([
['name', '张三'],
['title', 'Author']
]);

map.size; // 2
map.has('name'); // true
map.get('name'); // "张三"
map.has('title'); // true
map.get('title'); // "Author"

Map 的方法

  • map.size
  • map.set(key, value)
  • map.get(key): 读取 key 对应的键值,如果找不到 key,返回 undefined
  • map.has(key): 返回一个布尔值,表示某个键是否在当前 Map 对象之中
  • map.delete(key): 删除某个键,返回 true,如果删除失败,返回 false
  • map.clear(): clear 方法清除所有成员,没有返回值

WeakMap

WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。

WeakMap 与 Map 的区别有两点。

首先,WeakMap 只接受对象(null 除外)和 Symbol 值作为键名,不接受其他类型的值作为键名。其次,WeakMap 的键名所指向的对象,不计入垃圾回收机制。