前言笔者最近整理了一些前端技术文章。有兴趣的可以参考这里:muwooblogs。接下来我们输入正:js数据类型六种基本数据类型:Boolean。布尔值,true和false.null。指示null值的特殊关键字。JavaScript区分大小写,因此null与Null、NULL或其他变量完全不同。不明确的。变量未定义时的属性。数字。代表一个数字,例如:42或3.14159。细绳。表示一个字符串,例如:“Howdy”符号(ECMAScript6中新添加的类型)。实例唯一且不可变的数据类型。并且在大多数情况下,Object的对象引用数据类型可以通过typeof属性来判断。但是也有一些例外,比如:varfn=newFunction('a','b','returna+b')typeoffn//function还有相关讨论function是js的数据类型还是不是JavaScriptFunction也算基本类型吗?基本类型和引用数据类型的相关区别基本数据类型我们来看看MDN中对基本数据类型的一些定义:除了Object之外的所有类型都是不可变的(值本身不能改变)。例如,与C不同,JavaScript中的字符串是不可变的。我们将这些类型的值称为“原始值”。vara='string'a[0]='a'console.log(a)//string我们通常会重新分配一个变量,而不是改变基本数据类型的值。js中没有可以改变boolean值和数字的方法。有很多操作字符串的方法,但这些方法都返回一个新的字符串而不改变原始数据。例如:通过选择单个字母或使用String.substr()获取字符串的子字符串。使用连接运算符(+)或String.concat()连接两个字符串。引用数据类型引用类型(object)是存放在堆内存中的,而变量实际上是存放在栈内存中的指针,指向堆内存中的地址。每个空间的大小不一样,要根据情况具体分配,比如。varperson1={name:'jo??zo'};varperson2={name:'xiaom'};varperson3={name:'xiaoq'};引用类型的值是变量:person1['name']='muwoo'console.log(person1)//{name:'muwoo'}按值传递和按引用传递在理解了基本数据类型和引用类型,我们应该能理解按值传递和按引用传递的区别。当我们进行赋值操作时,基本数据类型的赋值(=)就是在内存中开辟一段新的栈内存,然后将值赋值给新的栈。例如:vara=10;varb=a;a++;console.log(a);//11console.log(b);//10所以,基本类型赋值的两个变量是两个相互独立的变量,互不影响。但是引用类型的赋值是按引用传递的。只是改变指针的指向,例如,也就是说,引用类型的赋值是对栈中存储的对象的地址的赋值,使两个变量指向同一个对象,所以操作两者之间相互影响。例如:vara={};//a持有一个空对象的实例varb=a;//a和b都指向这个空对象a.name='jozo';console.log(a.name);//'jozo'console.log(b.name);//'jozo'b.age=22;console.log(b.age);//22console.log(a.age);//22console.log(a==b);//trueshallowcopy先来看一段代码的执行情况:varobj={a:1,b:{c:2}}varobj1=objvarobj2=shallowCopy(obj);functionshallowCopy(src){vardst={};for(varpropinsrc){if(src.hasOwnProperty(prop)){dst[prop]=src[prop];}}returndst;}varobj3=Object.assign({},obj)obj.a=2obj.b.c=3console.log(obj)//{a:2,b:{c:3}}console.log(obj1)//{a:2,b:{c:3}}console.log(obj2)//{a:1,b:{c:3}}console.log(obj3)//{a:1、b:{c:3}}这段代码可以看出,赋值得到的对象obj1只是改变了指针,依然指向同一个对象,而浅拷贝得到的obj2是重新创建的一个新对象。但是,如果原对象obj中有另一个对象,则不会再对该对象进行复制,而只会复制其变量对象的地址。这是因为浅拷贝只复制了一层对象的属性,并没有包含对象中引用类型的数据。对于数组,比较常见的浅拷贝方式是slice(0)和concat()ES6比较常见的浅拷贝方式是Object.assign深拷贝通过上面的说明,相信大家对深拷贝有了一个大概的了解还有一点:深拷贝就是拷贝对象和对象的所有子对象。那么如何实现这样的深拷贝呢?1.JSON.parse(JSON.stringify(obj))对于常规对象,我们可以使用JSON.stringify将对象转为字符串,然后使用JSON.parse为其分配另外一个存储地址,这样就可以解决问题该内存地址指向同一个:varobj={a:{b:1}}varcopy=JSON.parse(JSON.stringify(obj))obj.a.b=2console.log(obj)//{a:{b:2}}console.log(copy)//{a:{b:1}}但是JSON.parse()和JSON.stringify也有问题,JSON.parse()和JSON.stringify()可以正确处理的对象只有Number、String、Array等可以用json表示的数据结构,所以不能用json表示的函数将不会被正确处理。vartarget={a:1,b:2,hello:function(){控制台。日志(“你好,世界!”);}};变种复制=JSON。解析(JSON.stringify(目标));安慰。日志(副本);//{a:1,b:2}console.log(JSON.stringify(target));//"{"a":1,"b":2}"2。遍历实现属性Copy由于浅拷贝只能实现非对象一级属性的拷贝,那么当遇到对象时,只需要递归实现其内部属性的浅拷贝即可:functionextend(source){vartargetif(typeofsource==='object'){target=Array.isArray(source)?[]:{}for(varkeyinsource){if(source.hasOwnProperty(key)){if(typeofsource[key]!=='object'){target[key]=source[key]}else{target[key]=extend(source[key])}}}}else{target=source}returntarget}varobj1={a:{b:1}}varcpObj1=extend(obj1)obj1.a.b=2console。log(cpObj1)//{a:{b:1}}varobj2=[[1]]varcpObj2=extend(obj2)obj2[0][0]=2console.log(cpObj2)//[[1]]我们再看看Zepto中深拷贝的代码://内部方法:用户将一个或多个对象合并到第一个对象中//参数://target目标对象对象合并到target//source合并对象//deep是否进行深度合并函数extend(target,source,deep){for(keyinsource)if(deep&&(isPlainObject(source[key])||isArray(source[key]))){//source[key]是对象,target[key]不是对象,则target[key]={}进行初始化,否则递归会出错if(isPlainObject(source[key])&&!isPlainObject(target[key]))target[key]={}//source[key]是数组,target[key]不是数组,然后target[key]=[]初始化,否则递归会出错if(isArray(source[key])&&!isArray(target[key]))target[key]=[]//执行递归extend(target[key],source[key],deep)}//不满足以上条件,说明source[key]是一般值类型,直接赋值给target即可elseif(source[key]!==undefined)target[key]=source[key]}内部实现其实和参考jsdepthcopyvsshallowcopy类似
