一、js 判断对象是否为空
1、将 json 对象转化为 json 字符串,再判断该字符串是否为 "{}"
var data = {};var b = (JSON.stringify(data) == "{}");alert(b); // true复制代码
注意: 忽略转换 undefined、function、Symbol 属性
JSON.stringify({[Symbol("key")]: "foo"}); // {}复制代码
2、for in 循环判断
var obj = {};var b = function() {for(var key in obj) {return false;}return true;}alert(b()); // true复制代码
3、jquery 的 isEmptyObject()
此方法是 jquery 将 2 方法 (for in) 进行封装,使用时需要依赖 jquery
var data = {};var b = $.isEmptyObject(data);alert(b); // true复制代码
4、Object.getOwnPropertyNames()
获取到对象中的属性名,存到一个数组中,返回数组对象,我们可以通过判断数组的 length 来判断此对象是否为空
var data = {};var arr = Object.getOwnPropertyNames(data);alert(arr.length === 0); // true复制代码
注意:此方法不兼容 IE8
5、使用 ES6 的 Object.keys()
与 4 方法类似,是 ES6 的新方法, 返回值也是对象中属性名组成的数组
var data = {};var arr = Object.keys(data);alert(arr.length === 0); // true复制代码
二、js 遍历对象
1、for in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
var obj = {'0': 'a', '1': 'b', '2': 'c'};for (var i in obj) {console.log(i, obj[i]);}复制代码
2、Object.getOwnPropertyNames()
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性).
var obj = {'0': 'a', '1': 'b', '2': 'c'};Object.getOwnPropertyNames(obj).forEach((key) => {console.log(key, obj[key]);});复制代码
3、Object.keys()
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)
var obj = {'0': 'a', '1': 'b', '2': 'c'};Object.keys(obj).forEach((key) => {console.log(key, obj[key]);});复制代码
4、Reflect.ownKeys()
返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举
var obj = {'0': 'a', '1': 'b', '2': 'c'};Reflect.ownKeys(obj).forEach(function(key) {console.log(key, obj[key]);});复制代码
三、js 数组遍历
1、for
var arr = [1, 2, 3];for (var i = 0; i < arr.length; i ++) {console.log(i, arr[i]);}复制代码
2、forEach
var arr = [1, 2, 3];arr.forEach(function(val, index) {console.log(val, index);});复制代码
3、for in
var arr = [1, 2, 3];for (var i in arr) {console.log(i, arr[i]);}复制代码
4、for of
不仅支持数组,还支持大多数类数组对象
也支持字符串遍历,它将字符串视为一系列的 Unicode 字符来进行遍历
var arr = [1, 2, 3];for (var value of arr) {console.log(value);}复制代码
5、数组/对象数组中获取 id
let arr = [{id: 0,text: 'a'}, {id: 1,text: 'b'}];let str = arr.map( (item) => {return [item.id]; // 字符串、数组、对象});复制代码
四、数据类型
1、原始数据类型
null 空值undefined 变量未初始化Number 数字类型String 字符串boolean 布尔型Object 对象复制代码
2、ES6 Symbol
概述
Symbol 数据类型是一个原始数据类型
Symbol 是一种特殊的、不可变的数据类型,可以作为对象属性的标识符使用
Symbol 对象是一个 symbol primitive data type 的隐式对象包装器
语法格式
Symbol([description]) // description 是可选的 字符串
Symbol 的描述,可用于调试(便于区分 Symbol 值)但不能访问 Symbol 本身
Number
const b = Number(10); // 10 const b = 10; // 简写
Symbol
const name = Symbol(); const name1 = Symbol('sym1'); console.log(name, name1) // Symbol() Symbol(sym1)
Symbol 转码 需要 babel 及 babel-polyfill
babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。如果想让这个方法运行,必须使用 babel-polyfill,为当前环境提供一个垫片。
Symbol 特点
1、Symbol 不能使用 new
const name = new Symbol();
2、每个从 Symbol() 返回的 symbol 值都是唯一的
一个 symbol 值能作为对象属性的标识符
Symbol("foo") 不会强制字符串 “foo” 成为一个 symbol类型
它每次都会创建一个新的 symbol类型:
Symbol("foo") === Symbol("foo"); // falseSymbol.for('foo') === Symbol.for('foo'); // true复制代码
Symbol.for() 与 Symbol() 这两种写法,都会生成新的 Symbol
它们的区别是,前者会被登记在全局环境中供搜索,后者不会
Symbol.for() 不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的 key 是否已经存在,如果不存在才会新建一个值,比如,如果你调用 Symbol.for("cat") 30 次,每次都会返回同一个 Symbol 值,但是调用 Symbol("cat")30 次,会返回 30 个不同的 Symbol 值
3、可以使用Object.defineProperty()
和Object.defineProperties()
方法
在一个对象上定义新的属性
// 设置对象属性只读。Object.defineProperty(obj, name, {writable: false});Object.defineProperty(props, 'key', {get: warnAboutAccessingKey,configurable: true});复制代码
4、全局共享
Symbol 在 js 文件中定义的 Symbol,并不能在其他文件直接共享
要创建跨文件可用的 symbol,甚至跨域(每个都有它自己的全局作用域), 使用 Symbol.for() 方法和 Symbol.keyFor() 方法从全局的 symbol 注册表中设置和取得。
Symbol.for() // 只有一个参数
Symbol.keyFor() // 只有一个参数,返回的是key
let name = Symbol.for('000');let name1 = Symbol.for('111');let name2 = Symbol.for('222');console.log(Symbol.keyFor(name)); // 000console.log(Symbol.keyFor(name1)); // 111console.log(Symbol.keyFor(name2)); // 222复制代码
5、Symbol 不支持类型强制转换
let a = 1;console.log(typeof a); // numberconsole.log(a + ' haha') // '1haha'Symbol 不支持强制转换let a = Symbol('a');console.log(typeof a);console.log(a + ' haha'); // Cannot convert a Symbol value to a string复制代码
6、Symbol 检索
Symbol 作为属性名,该属性不会出现在for...in
、for...of
循环中
也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回
但是,它也不是私有属性,有一个 ES6 新增的方法Object.getOwnPropertySymbols
方法
可以获取指定对象的所有 Symbol 属性名
let a = Symbol('a');let b = Symbol('b');let obj = { [a]: '123', [b]: 45 }for (let value of Object.getOwnPropertySymbols(obj)) {console.log(obj[value]); // "123" 45}复制代码
7、Object.getOwnPropertySymbols
使用 Object.getOwnPropertyNames 方法得不到Symbol属性名,需要使用Object.getOwnPropertySymbols
方法
const obj = {};let foo = Symbol("foo");Object.defineProperty(obj, foo, {value: "foobar",});for (let i in obj) {console.log(i); // 无输出}Object.getOwnPropertyNames(obj); // []Object.getOwnPropertySymbols(obj); // [Symbol(foo)]复制代码
8、Reflect.ownKeys
还有一个上面提到的 Reflect.ownKeys 方法可以返回所有类型的键名,包括常规键名和 Symbol 键名
let obj = { [Symbol('my_key')]: 1, enum: 2, nonEnum: 3 };Reflect.ownKeys(obj); // ["enum", "nonEnum", Symbol(my_key)]复制代码
9、typeof 运算符
typeof Symbol('foo') === 'symbol'复制代码
10、在所有使用可计算属性名的地方,都能使用 Symbol 类型。比如在对象中的key
const name = Symbol('name');const obj = { [name]: "haha" }console.log(obj[name]); // haha复制代码
11、Symbol 包装器对象作为属性的键
var sym = Symbol('foo');var obj = {[sym]: 1};obj[sym]; // 1obj[Object(sym)]; // still 1复制代码
实例: 消除魔术字符串
消除魔术字符串,消除强耦合
function getArea(shape, options) {let area = 0;switch (shape) {case 'Triangle': // 魔术字符串area = .5 * options.width * options.height;break;/* ... more code ... */}return area;}getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串复制代码
定义一个变量
const shapeType = {triangle: 'Triangle'};function getArea(shape, options) {let area = 0;switch (shape) {case shapeType.triangle:area = .5 * options.width * options.height;break;}return area;}getArea(shapeType.triangle, { width: 100, height: 100 });复制代码
Symbol 值
如果仔细分析,可以发现 shapeType.triangle 等于哪个值并不重要
只要确保不会跟其他 shapeType 属性的值冲突即可
因此,这里就很适合改用 Symbol 值
const shapeType = {triangle: Symbol()};复制代码