学习axios源码中实用的工具函数
var toString = Object.prototype.toString; // 通过Object.prototype.toString来获取每个对象的类型 function isArray(val) { return toString.call(val) === '[object Array]'; }
// 如果要判断是否是null,使用Object.prototype.toString function isUndefined(val) { return typeof val === 'undefined'; }
// a.判断val不是null和undefined // b.因为Buffer本身是一个类,所以要判断它是否存在构造函数 // c.通过自身的isBuffer判断 // 在node中使用,Buffer.from('a') function isBuffer(val) { return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val); }
var toString = Object.prototype.toString; function isArrayBuffer(val) { return toString.call(val) === '[object ArrayBuffer]'; }
// 先判断typeof FormData !== 'undefined',猜测原因是为了兼容IE,相关链接:https://stackoverflow.com/questions/19486597/formdata-is-undefined-in-ie-only function isFormData(val) { return (typeof FormData !== 'undefined') && (val instanceof FormData); }
function isArrayBufferView(val) { var result; // 此处主要是为了兼容IE9及以下 if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) { result = ArrayBuffer.isView(val); } else { result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer); } return result; }
function isString(val) { return typeof val === 'string'; }
function isNumber(val) { return typeof val === 'number'; }
// 看了下测试用例,数组也算对象,如果真实只检测object的话,还建议使用 Object.prototype.toString function isObject(val) { return val !== null && typeof val === 'object'; }
// plainObject翻译为中文即为纯对象,所谓的纯对象,就是该对象是通过{}或new Object()创建的。 // 判断是否为“纯对象”,是为了和其他对象区分开比如说null、数组以及宿主对象(所有的DOM和BOM都是数组对象)等。 // 其实就是判断目标对象的原型是不是`null` 或 `Object.prototype // jQuery中的isPlainObject() 函数用于判断指定参数是否是一个纯粹的对象,返回值为Boolean类型。 //“纯粹的对象”,就是通过 { }、new Object()、Object.create(null) 创建的对象。 //这个方法的作用是为了跟其他的 JavaScript对象如 null,数组,宿主对象(documents),DOM 等作区分,因为这些用 typeof 都会返回object。 var toString = Object.prototype.toString; function isPlainObject(val) { if (toString.call(val) !== '[object Object]') { return false; } // Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值) // Object.getPrototypeOf:实际上其实是获取当前对象的__proto__ // Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 var prototype = Object.getPrototypeOf(val); // Object.getPrototypeOf({}.__proto__) // Object.create(null) return prototype === null || prototype === Object.prototype; } // 测试用例 // expect(utils.isPlainObject({})).toEqual(true); // expect(utils.isPlainObject([])).toEqual(false); // expect(utils.isPlainObject(null)).toEqual(false); // expect(utils.isPlainObject(Object.create({}))).toEqual(false); // let b = {} // expect(utils.isPlainObject(b).toEqual(true);
function isDate(val) { return toString.call(val) === '[object Date]'; }
function isFile(val) { return toString.call(val) === '[object File]'; }
function isBlob(val) { return toString.call(val) === '[object Blob]'; }
function isFunction(val) { return toString.call(val) === '[object Function]'; }
function isStream(val) { // pipe是stream的一个方法,fs.createReadStream源码会使用到, return isObject(val) && isFunction(val.pipe); }
// URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串 // var paramsString = "q=URLUtils.searchParams&topic=api" //var searchParams = new URLSearchParams(paramsString); //searchParams.has("topic") === true; // true //searchParams.get("topic") === "api"; // true //searchParams.getAll("topic"); // ["api"] //searchParams.get("foo") === null; // true //searchParams.append("topic", "webdev"); //searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev" //searchParams.set("topic", "More webdev"); //searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev" //searchParams.delete("topic"); //searchParams.toString(); // "q=URLUtils.searchParams" function isURLSearchParams(val) { return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams; }
function trim(str) { return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); }
/** * Determine if we're running in a standard browser environment * * This allows axios to run in a web worker, and react-native. * Both environments support XMLHttpRequest, but not fully standard globals. * * web workers: * typeof window -> undefined * typeof document -> undefined * * react-native: * navigator.product -> 'ReactNative' * nativescript * nativescript介绍 https://zhuanlan.zhihu.com/p/29452684 * navigator.product -> 'NativeScript' or 'NS' */ function isStandardBrowserEnv() { if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' || navigator.product === 'NativeScript' || navigator.product === 'NS')) { return false; } return ( typeof window !== 'undefined' && typeof document !== 'undefined' ); }
/** * Iterate over an Array or an Object invoking a function for each item. * * If `obj` is an Array callback will be called passing * the value, index, and complete array for each item. * * If 'obj' is an Object callback will be called passing * the value, key, and complete object for each property. * // 在迭代数组和对象的每一项时,执行传入的自定义方法 // 如果obj是数组,callback执行参数为value, index, and complete array // 如果obj是对象,callback执行参数为value, key, and complete object // 此覆盖方法貌似只是比forEach能多处理下对象类型,没太想到其他用途 function forEach(obj, fn) { // Don't bother if no value provided if (obj === null || typeof obj === 'undefined') { return; } // Force an array if not already something iterable if (typeof obj !== 'object') { /*eslint no-param-reassign:0*/ obj = [obj]; } if (isArray(obj)) { // Iterate over array values for (var i = 0, l = obj.length; i < l; i++) { fn.call(null, obj[i], i, obj); } } else { // Iterate over object keys for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { fn.call(null, obj[key], key, obj); } } } }
/** * Accepts varargs expecting each argument to be an object, then * immutably merges the properties of each object and returns result. * * When multiple objects contain the same key the later object in * the arguments list will take precedence. * * Example: * * ```js * var result = merge({foo: 123}, {foo: 456}); * console.log(result.foo); // outputs 456 * ``` * * @param {Object} obj1 Object to merge * @returns {Object} Result of all merge properties */ function merge(/* obj1, obj2, obj3, ... */) { var result = {}; function assignValue(val, key) { if (isPlainObject(result[key]) && isPlainObject(val)) { result[key] = merge(result[key], val); } else if (isPlainObject(val)) { result[key] = merge({}, val); } else if (isArray(val)) { result[key] = val.slice(); } else { result[key] = val; } } for (var i = 0, l = arguments.length; i < l; i++) { forEach(arguments[i], assignValue); } return result; }
/** * Extends object a by mutably adding to it the properties of object b. */ function extend(a, b, thisArg) { forEach(b, function assignValue(val, key) { if (thisArg && typeof val === 'function') { a[key] = bind(val, thisArg); } else { a[key] = val; } }); return a; }
/** * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) */ // 确定json文件是UTF-8 无BOM编码的的。如果有BOM,会在读取第一行的时候出现乱码。 // 所谓 BOM,全称是Byte Order Mark,它是一个Unicode字符,通常出现在文本的开头,用来标识字节序。UTF-8主要的优点是可以兼容ASCII,但如果使用BOM的话,这个好处就荡然无存了。 // 删除UTF-8编码中BOM function stripBOM(content) { if (content.charCodeAt(0) === 0xFEFF) { content = content.slice(1); } return content; }
// 数组最好使用typeof判断,这样定义()=> {}的方法,会被Object.prototype.toString识别为Object 1.typeof:仅能判断基础数据类型,如:“number”,”string”,”undefined”,”boolean”,“symbol” (ES6新增)六种,”object”类型建议使用Object.prototype.toString判断 2.instanceof 用于判断一个变量是否某个对象的实例,如:Object Array Function // 所有的均可使用下边方法判断 3.Object.prototype.toString:对于数组、null、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串。所以用此方法来判断
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。
但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。
在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。