咱们先说一下JS的数据类型,咱们通常说JS有六大数据类型(ES6之前)分别是:前端
基本数据类型数组
引用数据类型post
在ES6中新增了Symbol数据类型。学习
有时咱们须要知道数据的类型其判断一些事情,咱们常常会用typeof去判断数据类型。大数据
那么typeof能判断什么类型呢?this
就这几个数据类型,但这些咱们够用吗?或者说准确吗?spa
咱们没有看到null那么他是什么类型呢?咱们用typeof null
发现它是object
,是否是很奇怪,其实这是一个bug,可是这个bug是能修复的可是不能修复,由于null通常是用来表示一个对象是空的,有时咱们用null来取消事件,我理解的它好像是一个占位符,表示这个对象是空的。那为何不能修复呢?由于修复它好说,可是修复了它会带来许多麻烦。prototype
咱们来看一下typeof判断的状况。3d
console.log(typeof(1)); //number console.log(typeof("1")); // string console.log(typeof(true)); // boolean console.log(typeof({})); // object console.log(typeof(function (){})); // function console.log(typeof(null)); // object console.log(typeof(undefined)); // undefined
当咱们想判断一个对象那个是否是null或者是否是Date、RegExp等类型时会怎么样呢?咱们发现都是object
,那咱们有没有办法区分他们呢?
在这以前我先介绍一下Object.prototype.toString这个方法,我相信你们不陌生吧。它也能判断数据类型,可是是这样的。code
console.log(Object.prototype.toString.call(1)); console.log(Object.prototype.toString.call("1")); console.log(Object.prototype.toString.call(true)); console.log(Object.prototype.toString.call({})); console.log(Object.prototype.toString.call(function (){})); console.log(Object.prototype.toString.call(null)); console.log(Object.prototype.toString.call(undefined)); console.log(Object.prototype.toString.call(new RegExp())); console.log(Object.prototype.toString.call(new Date())); [object Number] [object String] [object Boolean] [object Object] [object Function] [object Null] [object Undefined] [object RegExp] [object Date]
咱们发现它比typeof高级点,能分辨的更准确,可是格式好像不是咱们要的。
接下来进入主题,直接上代码。
//首先定义好数据类型。 let types = { "[object Object]": "Object", "[object RegExp]": "RegExp", "[object Date]": "Date" }; function type(regs) { let result = typeof(regs); // 先获取传过来的参数 // 若是是对象在进行判断,不是则返回。 if(result === 'object'){ if(regs === null){ return 'null'; }else{ return types[Object.prototype.toString.call(regs)]; } }else{ return result; } } console.log(type(1)); //number console.log(type("1")); // string console.log(type(true)); // boolean console.log(type({})); // object console.log(type(function (){})); // function console.log(type(null)); // null console.log(type(undefined)); // undefined console.log(type(new RegExp())); //RegExp console.log(type(new Date())); //Date
咱们常常会用到一个对象去作一些事情,可能有时候咱们不想改变原有的数据。,时候咱们就须要对象克隆了,你可能简单的觉得就是 = 就好了,那咱们来看一看。
let obj = { a: 1 } let obj2 = obj; console.log(obj); //{a: 1} console.log(obj2); //{a: 1}
咱们看到复制过来了,这样咱们就能够随便使用了。那咱们来修改一下obj看看。
obj.a = 2; console.log(obj); //{a: 2} console.log(obj2); //{a: 2}
发现都变成了{a: 2}
,是否是很奇怪。由于对象是引用类型的,他们赋值实际上是赋的地址值,就是他们指向同一个地方,那么咱们应该怎么作呢?你应该知道怎么遍历对象,咱们就把它遍历一遍再复制。看代码
let obj = { a: 1 } function clone(obj) { let a = {}; for(let o in obj){ a[o] = obj[o] } return a; } let obj2 = clone(obj); console.log(obj); //{a: 1} console.log(obj2); //{a: 1} obj.a = 2; console.log(obj); //{a: 2} console.log(obj2); //{a: 1}
没有改变,看来咱们成功了,那这篇文章就到这了。呵呵,其实远没有,咱们来看一下有没有什么问题。
let obj = { a: { b: 1 }, c: 3 } function clone(obj) { let a = {}; for(let o in obj){ a[o] = obj[o] } return a; } let obj2 = clone(obj); console.log(obj); console.log(obj2); obj.a .b = 2; console.log(obj); console.log(obj2);
咱们发现又出问题了。
hasOwnProperty
这个属性,它就是判断自身有没有这个属性,而不会去原型上找。function clone(obj) { let a = {}; for(let o in obj){ if(obj.hasOwnProperty(o)){ a[o] = obj[o]; } } return a; }
这个问题解决了,就差上一个了,咱们接着用判断数据的类型来判断是否还须要复制的方法解决上一个问题。
let obj = { a: { b: 1, d: { e:[{f: 2}], g: { h:{ l: 5 } } } }, c: 3 } function deepClone(origin, target) { let tar = target || {}, arr = "[object Array]", str = Object.prototype.toString; for(let o in origin){ if(origin.hasOwnProperty(o)){ // 若是是对象接着递归复制 if(typeof origin[o] === 'object'){ // 判断是对象仍是数组 tar[o] = str.call(origin[o]) === arr ? [] : {}; deepClone(origin[o], tar[o]); }else{ tar[o] = origin[o]; } } } return tar; } let obj2 = deepClone(obj, {}); console.log(obj); console.log(obj2); obj.a.d.g.h.l = 6; console.log(obj.a.d.g.h.l); //6 console.log(obj2.a.d.g.h.l); //5
function extend() { let origin, // 要拷贝的源 target = arguments[0], // 获取第一个参数 isDeepClone = false; // 是否深拷贝 length = arguments.length, //拷贝的个数 arr = "[object Array]", str = Object.prototype.toString, i = 0; if(typeof target === 'boolean'){ isDeepClone = target; i ++; target = arguments[i]; //获取目标元素 } //防止循环引用 if(origin === target){ return; } // 兼容function if(typeof target !== 'object' && typeof target !== 'function' ){ target = {}; } for ( ; i < length; i++) { origin = arguments[i]; for(let o in origin){ if(origin.hasOwnProperty(o)){ if(origin[o] === 'object'){ if(isDeepClone){ target[o] = str.call(origin[o]) === arr ? [] : {}; extend(true, target[o], origin[o]); } }else{ target[o] = origin[o]; } } } } return target; }
let obj = { a: { b: function (argument) { }, d: { e:[{f: 2}], g: { h:{ l: 5 } } } }, c: 3 } let r = JSON.stringify(obj); r = JSON.parse(r); obj.a.d.g.h.l = 6; console.log(r.a.d.g.h.l); // 5
也是能够的,咱们输出一下r看看。
有没有发现少了什么?对,就是function,它不只不能复制function还有undefined也不行,还有别的本身查一下吧。
3.数组克隆
有了上面的铺垫,咱们知道数组也是引用类型,就不能简单的等于来复制。
let arr = [8,5,6,6,8]; let arr2 = arr.concat(); arr2[3] = 1; console.log(arr); //[8, 5, 6, 6, 8] console.log(arr2); //[8, 5, 6, 1, 8]
能够复制成功,那么引用类型呢?
let arr = [8,{a: 1},6,6,8]; let arr2 = arr.concat(); arr2[1].a = 2; console.log(arr); console.log(arr2);
let arr = [8,{a: 1},6,6,8]; let arr2 = arr.slice(); arr2[1].a = 2; arr2[2] = 2; console.log(arr); console.log(arr2);
还有一些别的方法,我就不一一列举了,这些都是浅复制。
若是想深度克隆数组,也可使用上面介绍的使用JSON也是能够的。
let arr = [8,{a: 1},6,6,8]; let arr2 = JSON.parse( JSON.stringify(arr) ); arr2[1].a = 2; arr2[2] = 2; console.log(arr); console.log(arr2);
目前想到的就这些,总感受拉下了什么,若是我想起来了我会继续补充的。
4.闲聊
上面写的我意犹未尽,多是本身知识的局限性暂时只能想到那些,上面说到了for...in,那么咱们来简单的说一下for...of和它的区别。
那咱们直接遍历一次,看看有什么区别。
let arr = [8,{a: 1},6,6,8]; let a = { b:1, r: 8, h:{ e:6 } } console.log('for...of'); for(let i of arr){ console.log(i); } console.log('for...in'); for(let i in a){ console.log('key:' + i); }
是否是感受挺好的,咱们再来看看。
let arr = [8,{a: 1},6,6,8]; let a = { b:1, r: 8, h:{ e:6 } } console.log('for...in遍历数组'); for(let i in arr){ console.log(i); } console.log('for...of遍历对象'); for(let i of a){ console.log('key:' + i); }
for(let i in arr){ console.log(arr[i]); //[8,{a: 1},6,6,8] }
我以为你看到这里应该知道遍历什么用哪一个更合适了。
补充
__proto__
的实现
Object.defineProperty(Object.prototype, __proto__, { get: function(){ return Object.getPrototypeOf(this); }, set: function(ob){ Object.setPrototypeOf(this, ob); return ob;
}) ```
下一篇文章我想说一下数组去重好像不是最全的数组去重方法,由于内容挺多,我就不一块儿写了,喜欢的能够点一个赞,或者关注一下。鼓励一下一名自学前端的大学生。