JavaScript 引用类型实例详解【数组、对象、严格模式等】
本文实例讲述了JavaScript引用类型。分享给大家供大家参考,具体如下:
数组
在ECMAScript中数组是非常常用的引用类型
ECMAScript所定义的数组和其他语言中的数组有着很大的区别
数组也是一种对象
创建数组
//方法一 vararr=newArray(); //方法二 vararr1=[];
特点
-
数组即一组数据的集合
-
js数组更加类似java的map容器。长度可变,元素类型任意
-
数组长度随时可变!随时可以修改!(length属性)
vararr1=[123,324,true,'abc',1,4,5,newDate()]; arr1.length=5; console.log(arr1); //log里面是传递的字符串,JS引擎默认会调用.toString();隐式的调用.
常用方法
push、pop
shift、unshift
splice、slice
concat、join、sort、reverse(逆序)
影响原数组 splice() arr.splice(开始项,[控制几位数,值]);//statr,count, vararr=[1,2,3,4,5,6,7]; varzf=arr.splice(3);//控制几位数,默认值:arr.length-1//包括3原来项数 console.log(arr);//[1,2,3] console.log(zf);//[4,5,6,7]//返回值--取出的内容 vararr=[1,2,3,4,5,6,7]; varzf=arr.splice(3,2);//截取 console.log(arr);//[1,2,3,6,7] console.log(zf);//[4,5] vararr=[1,2,3,4,5,6,7]; vart=arr.splice(3,2,'zf','dd');//替换 console.log(arr);//[1,2,'zf','dd',6,7] console.log(t);//[4,5] vararr=[1,2,3,4,5,6,7]; vart=arr.splice(3,0,'zf','dd');//插入 console.log(arr);//[1,2,3,'zf','dd',4,5,6,7] console.log(t);//[]//如果为0,去除空数组 vararr=[1,2,3,4,5,6,7]; var12=arr.splice(-4);//截取 console.log(arr);//[1,2,3] console.log(zf);//[4,5,6,7]
// slice(stat,end)//去出了end-stat项。不包括end项。
varzf=arr.sort(function(a,b){//传递匿名函数,通过匿名函数参数判断大小。 if(a>b){ return1; }elseif(aES5数组新特性
位置方法:indexOflastIndexOf
迭代方法:everyfilterforEachsomemap
缩小方法:reducereduceRight//indexOf();//查找位置 vararr=[234,23,45,46,45,645,56]; //1个参数的时候,表示传值返回索引位置 varidxVal=arr.indexOf(45); //2个参数的时候,第一个表示查询的值,第二个参数是传值,表示起始开始查询的起始位置 varidxVal=arr.indexOf(2,3); //查找数组比较的时候是"===" //找不到返回-1
//迭代方法 //every:对于数组每一个元素进行一个函数的运行如果函数都返回true,最后则返回true。如果有一个返回false最后结果则返回false。 //测试数组的所有元素是否都通过了指定函数的测试 vararr=[1,2,3,4,3,2,4,6]; varreslut=arr.every(function(item,index,array){ returnitem>0; }); console.log(reslut);//true //filter:对于数组的每一个元素进行一个函数的运行给定的函数执行,把过滤后的结果返回。 vararr=[1,2,3,4,3,2,4,6]; varreslut=arr.filter(function(item,index,array){ returnitem>2;//所有大于2的过滤出来 }) console.log(reslut);//[3,4,3,4,6] //forEach:循环数组每一项,并执行一个方法 //方法中的参数:数组成员的值,数组成员的索引,原数组(修改原数组会影响原来遍历的数组) vararr=[1,2,3,4,3,2,4,6]; arr.forEach(function(item,index,array){ console.log(item); }); vararr1=['tan','cyan','pink','red']; arr1.forEach(function(val,idx,arrs){ return1;//返回返回并不会影响原数组 }); console.log(arr); //map:对于数组的每一个元素进行一个函数的运行可以经过函数执行完毕把新的结果返回,原数组不变。 vararr=[1,2,3,4,3,2,4,6]; varreslut=arr.map(function(item,index,array){ returnitem*3; }); console.log(reslut);//[3,6,9,12,9,6,12,18] //some:对于数组每一个元素进行一个函数的运行如果有一项返回true最后则返回true如果每一项都返回false,最后才返回false。 vararr=[1,2,3,4,3,2,4,6]; varreslut=arr.some(function(item,index,array){ returnitem>5;//有一个返回true,就返回true }); console.log(reslut);//true
//模拟filter方法 Array.prototype.filter=function(cb){ varreslut=[]; try{ if(cb&&cb.constructor===Function){ for(vari=0;i2; }); console.log(a); //模拟some Array.prototype.some=function(fn){ try{ if(fn&&fn.constructor===Function){ for(vari=0;i
vararr=[1,2,3,4,3,2,4,6]; //reducereduceRight //前一个值,当前值,索引位置,array //数组中的每个值(从左到右)开始合并,最终为一个值。 //接收一个函数作为累加器,数组中的每一个值(从左到右)开始合并,最终为一个值。 varreslut=arr.reduce(function(prev,cur,index,array){ returnprev+cur; }); console.log(reslut);//25 //reduceRight从右开始遍历 varreslut1=arr.reduceRight(function(prev,cur,index,array){ returnprev+cur; }); console.log(reslut);//25
//得到接口的对象 varo=(function(){ varperson={ name:'xixi', age:22, } return{ sayName:function(k){ returnperson[k]; }, } }()); varperson=['name','age'].reduce(function(obj,k){ //console.log(obj,k,'--'); obj[k]=o.sayName(k); returnobj; },{}); console.log(person);数组判断方法:
Array.isArray();
判断是否为数组,如果是,则返回true,否则返回false。vararr=[]; console.log(Array.isArray(arr));填充方法:
fill();
实现对数组的填充
参数:接受值,直接填充,如果是函数,也是直接填充//arr.fill(1); //arr.fill(function(){ //return2; //}); //arr.fill([1,2,3]); arr.fill({x:1}); console.log(arr);Object
引用类型都是Object类型的实例,Object也是ECMAScript中使用最多的一种类型(就像java.lang.Object一样,Object类型是所有它的实例的基础)//所有类的基础类。
Object类型的创建方式、使用
对于Object类型应用forin枚举循环
Obj每个实例都具有属性和方法
Constructor:保存着用于创建当前对象的函数。(构造函数)
hasOwnProperty(propertyName):用于检测给定的属性在当前对象实例中(而不是原型中)是否存在。
isPrototypeOf(Object):用于检查传入的对象是否是另外一个对象的原型。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
toLocaleString():返回对象的字符串表示。该字符串与执行环境的地区对应.
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔表示。
OBject.prototype.toString()
Object.prototype.toString
作用:根据内部的this返回一个类似于这样的字符串[objectconstructorName]
这个方法有个缺点,不能获取用户自定义对象的具体类型.
只能获取内置对象的类型.
自定义对象类型都返回:[objectObject]console.log(Object.prototype.toString.call([]));//[objectArray] console.log(Object.prototype.toString.call(Array));//[objectFcuntion] console.log(Object.prototype.toString.call(newDate()));//[objectDate] //简写方式 console.log(({}).toString.call([]));//[objectArray]toString();
//字符串==>String.prototype.toString(); vara='t'; console.log(a.toString());//t vara=newString(); console.log(a.toString());//空字符串 vara=newString('string'); console.log(a.toString());//string //数组==>Array.prototype.toString(); varb=[1,2,3,4]; console.log(b.toString());//1,2,3,4 varb=[]; console.log(b.toString());//空字符串 varb=newArray(); console.log(b.toString());//空字符串 varb=newArray(3,5); console.log(b.toString());//3,5 //对象==>Object.prototype.toString(); varc={}; console.log(c.toString());//[objectObject] //函数 console.log(Function.toString());//functionFunction(){[nativecode]} console.log(Array.toString());//functionArray(){[nativecode]} console.log(RegExp.toString());//functionRegExp(){[navtivecode]}关于JSON函数
JSON.parse()
作用:将JSON字符串解析成JavaScirpt值。在解析过程中,可以选择性的修改某些属性的原始解析值。
参数1:JSON字符串
参数2:reviver函数,用来转换解析出的属性值。(可选参数)
返回值:解析出的一个Objectconsole.log(JSON.parse(10));//10 console.log(JSON.parse(true));//true console.log(JSON.parse('"xixi"'));//xixi console.log(JSON.parse(null));//null console.log(JSON.parse('"undefined"'));//undefined console.log(JSON.parse("[]"));//[]如果指定了reviver函数,解析的出的Object,解析值本身以及它所包含的所有属性,会按照一定的顺序(从最最里层的属性开始,一级级往外,最终到达顶层)分别去调用指定的reviver函数。
在调用过程中,当前属性所属的对象会作为this值,当前属性名和属性值会分别作为第一个参数和第二个参数传入reviver函数中,如果reviver函数返回undefeind,则当前属性会从属性对象中删除,如果返回了其它值,则返回的值会成为当前属性新的属性值。
当遍历到最顶层的值(解析值)时,传入reviver函数的参数会是空字符串''(因为此时已经没有真正的属性)和当前的解析值(有可能已经被修改过),当前的this值会是{"":修改过的解析值},JSON.parse('{"p":5}',function(key,val){ if(key==='')returnval;//如果到了最顶层,则直接返回属性值 returnval*2; });JSON.stringify();
stringify(value[,replacer,[space]]);
将任意的JavaScript值序列化成JSON字符
参数1:value:将序列化成JSON字符串的值
参数2:replacer:可选,如果是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理。如果是一个数组,则暴行在这数组中的属性名才会被序列化到最终的JSON字符串中。
参数3:space,指定缩进可通的空白字符串,用于美化输出。控制结果字符串里的间距。注意:
不可枚举的属性会被忽略
非数组对象的属性不能保证以特定的顺序出现的序列化后的字符串中。
布尔值,数字,字符串的包装对象在序列化过程中会自动装换成对应的原始值。
undefeind,任意的函数,以及symbol值,在徐泪花过程横纵挥别忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)
所有以symbol为属性键的属性值都会被完全忽略掉,即便replacer参数中强制指定包含了它们
console.log(JSON.stringify([undefined,Object,Symbol()]));//null,null,null console.log(JSON.stringify({x:undefined,y:Object,z:Symbol()}));//{}Object.create
ES5为对象提供了一个Object.create();
作用:创建一个类,是一种寄生式继承。
返回一个类,这个类的原型指向传递进来的对象。创建的实例化对象,构造函数指向的是继承的对象的类的构造函数。本身没有原型,可以通过原型链找到继承的对象类中的原型。具有继承对象上的属性以及方法。
因此,创建的实例化对象可以使用继承对象上的属性和方法。varBook=function(title,price){ this.title=title; this.price=price; } Book.prototype.sayTitle=function(){ returnthis.price; } varbook=newBook('one',10); //创建一个继承类 varNewBook=Object.create(book); console.log(NewBook.constructor); varprice=NewBook.sayTitle(); console.log(price);
//模拟Object.create(); //寄生式继承 Object.prototype.create=function(obj){ try{ if(obj&&obj.constructor===Object){ functionF(){} F.prototype=obj; returnF; } }catch(e){ //TODOhandletheexception } } //创建一个继承类 varNewBook=Object.create(book); console.log(NewBook.constructor); varprice=NewBook.sayTitle(); console.log(price);Object.defineProperty
Object.defineProperty();
直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回这个对象。
参数1:需要被设置的对象
参数2:设置的属性名
参数3:配置项,添加属性的特性属性特性属性:
value:该属性值,默认值:undefeind
writable:可否被修改,默认值:false(不能被修改)
configuarable:能否通过delete删除属性从而重新定义属性,能够修改属性的特性,或者能否把属性修改为访问属性。默认值:false;(不可以重新定义或删除)
enumerable:是否可以被for-in枚举。默认值:falsevarobj={}; Object.defineProperty(obj,'title',{ value:'tan', //writable:true, configurable:false, //enumerable:true }); deleteobj.title; //obj.title='pink'; //for(variinobj){ // //console.log(obj[i]); // //} console.log(obj);特性方法:
set:给属性提供setter的方法,如果没有setter则为undefined。默认值undefiend。
参数:该参数的新值分配给该属性。默认:undefinedObject.defineProperty(obj,'title',{ get:function(){ console.log('get'); returnthis._title; }, set:function(val){ this._title=val; } }); obj.title='pink'; vart=obj.title;defineProperties
在一个对象上添加或修改一个或多个自有属性,并返回该对象。
参数1:表示要被处理的对象
参数2:定义多个属性特性对象varobj={} Object.defineProperties(obj,{ color:{ value:'tan' }, names:{ value:'zf' } }); console.log(obj);getOwnPropertyNames
Object.getOwnPropertyNames();
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组。
参数:需要获取的对象。getOwnPropertyDescriptor
Object.getOwnPropertyDescriptor();
指定对象上一个自由属性对应的属性描述符。(自由属性指的直接赋予该对象的属性,不需要从原型链上进行查找的属性)
参数1:获取的对象。
参数2:获取的属性值模拟map
模拟java中的Map
//简单实现map functionMap(){ //priveate的对象来保存key和val varobj={}; //put方法 this.put=function(key,val){ obj[key]=val;//把键值对绑定到object上. } //获得map容器的个数 this.size=function(){ varcount=0; for(variinobj){ count++; } returncount; } //根据key得到val this.get=function(key){ returnobj[key]||(obj[key]===0)||(obj[key]===false)?obj[key]:null; } //remove删除方法 this.remove=function(key){ if(obj[key]||obj[key]===0||obj[key]===false)deleteobj[key]; } //eachMap遍历map容器的方法 this.eachMap=function(cb){ if(cb&&cb.constructor===Function){ for(variinobj){ cb.call(this,i,obj[i]); } } } } varm=newMap(); m.put('01',120); m.put('02','tan'); //console.log(m.size()); // //console.log(m.get('0')); //m.remove('01'); //console.log(m.get('01'),'--'); m.eachMap(function(key,val){ console.log(key,val,'---'); });去掉数组的重复项
vararr=[1,2,4,2,3,4,5,546,57,6,5,4,31,57]; //js对象特性,数组去重 //在js对象中key是永远不会重复的. //1,把数组转成一个js的对象 //2,把数组中的值,变成js对象当中的key //3,把对象再还原成数组 //数组转对象 vartoObject=function(arr){ varreslutObj={}; for(vari=0;i其他引用类型
单体对象(不需要实例化对象,就可以使用的方法):
Global对象(全局)这个对象不存在,无形的对象(特别的,特殊的存在)
其内部定义了一些方法和属性:encodeURI、encodeURIComponent、decodeURI、decodeURIComponent、eval、parseInt、parseFloat、isNaN(在js里面只有NaN自己不等于自己本身的)、Escape、unescape//encodeURI、encodeURIComponent、 varuri='http://www.baidu.comcn'; varstr1=encodeURI(uri);//http://www.baidu.com%20cn//(url://不会进行编码) varstr2=encodeURIComponent(uri);//http%3A%2F%2Fwww.baidu.com%20cn//任何不标准的文字都会进行编码 console.log(str1); console.log(str2); //decodeURI、decodeURIComponent、 console.log(decodeURI(str1));//http://www.baidu.comcn console.log(decodeURIComponent(str2));//http://www.baidu.comcn
//eval(string)方法无形的javascript解析器 varstr1='vara=10;varb=20;'; eval(str1); console.log(a+b); //数组字符串直接使用:eval(strArr); vararr='[10,203,345,45,6]'; varevalArr=eval(arr); console.log(evalArr); //对象字符串 varobj='{name:"123",age:20}'; varevalObj=eval('('+obj+')'); console.log(evalObj);//Object{name:"123",age:20}
//escapeunescapeURI转码 varstr='八百米'; varstr2=escape(str);//%u516B%u767E%u7C73 console.log(str2);Math对象
内置的Math对象可以用来处理各种数学运算
可以直接调用的方法:Math.数学函数(参数)
求随机数方法:Math.random(),产生[0,1)范围一个任意数Date对象
获取当前时间的一系列详细方法vardate=newDate(); console.log(date.getTime());//当前时间的毫秒数基本包装类型:Boolean、String、Number
Function类型、RegExp类型
简单单体和闭包单体
单体(singleton)模式是js中最基本但又最有用的模式之一,它可能比其他任何模式都常用。
这种模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一的变量进行访问。通过确保单体对象只存在一份实例,就可以确信自己的所有代码使用的都是同样的全局资源。简单单体
//简单单体模式(只能创建一个实例)//无法通过new关键字来实例化. varSingleton={//当成模板类 attr1:true, attr2:10, method1:function(){ console.log(this.attr1); } } Singleton.method1(); //划分命名空间(区分代码)闭包单体
//利用闭包来创建单体,闭包主要的目的,保护数据 varalogy={}; alogy.singleton=(function(){ //添加私有成员 vara=100; varfn1=function(){ console.log(a); } //块级作用域里的执行结果赋值单体对象 return{ attr1:10, attr2:20, method:function(){ console.log(this.attr1); }, fn1:fn1 } })(); alogy.singleton.method(); alogy.singleton.fn1();惰性单体
//惰性单体(和闭包单体类似)
//通过一个私有变量来控制是否实例化对象,初始化一个init。 varExt={}; Ext.Base=(function(){ //私有变量控制返回的单体对象 varuniqInstance; //需要一个构造器init初始化单体对象的方法 functionInit(){ //私有成员 vara1=10; vara2=true; varfun1=function(){ console.log(a1); } return{ attr1:a1, attr2:a2, fun1:fun1 } } return{ getInstance:function(){ if(!uniqInstance){//不存在,创建单体实例 uniqInstance=newInit(); } returnuniqInstance; } } })() varinit=Ext.Base.getInstance(); init.fun1();//10分支单体
//分支单体(判断程序的分支-浏览器差异的检测) //简单判断 varExt={}; vardef=true; Ext.More=(function(){ varff={ attr1:'ff' }; varie={ attr1:'ie' } returndef?ff:ie; })() console.log(Ext.More.attr1);//ff简单链式编程实现
简单链式调用。returnthis;
//简单函数链式调用 functionDog(){ this.run=function(){ console.log('dogisrun...'); returnthis; } this.eat=function(){ console.log('dogiseat...'); returnthis; } this.slepp=function(){ console.log('dogissleep'); returnthis; } } vard1=newDog(); d1.run().eat().slepp();模拟jquery底层代码
//模拟jquery底层链式编程 //函数自执行特点: //1:程序启动时候里面代码自动执行 //2:内部的成员变量外部无法访问(除了不加var修饰的变量) //块级作用域 (function(window,undefined){ //$最常用的对象返回给外界//大型程序开发一般使用'_'作为私有的对象 function_$(args){ //匹配id选择器 varidSelect=/^\#[\w+]?/; this.dom;//接收所得到的元素 if(idSelect.test(args)){//匹配成功接收元素//#div this.dom=document.getElementById(arguments[0].substr(1)); }else{ thrownewError('选择器不正确!'); } } //在Function类上扩展一个可以实现链式编程的方法 Function.prototype.method=function(methodName,fn){//实现链式编程,方法的名字和进行调用的函数是什么 this.prototype[methodName]=fn; returnthis;//链式编程 } //在_$原型对象上加一些公共的方法 _$.prototype={ constructor:_$, addEvent:function(type,cb){ //ffchrome if(window.addEventListener){ this.dom.addEventListener(type,cb,false); //ie }elseif(window.attachEvent){ this.dom.attachEvent('on'+type,cb); } returnthis; }, setStyle:function(key,val){ this.dom.style[key]=val; returnthis; } } //window上注册一个全局变量 window.$=_$; //准备方法 _$.onReady=function(cb){ //1,实例化_$对象,注册到window上 window.$=function(args){ returnnew_$(args); } //2:执行传入的代码 cb.call(window); //3:实现链式编程 _$.method('addEvent',function(){}).method('setStyle',function(){}); } })(window)//程序的入口window传入作用域中 $.onReady(function(){ $('#div') .addEvent('click',function(){ console.log('点击了'); }) .setStyle('background','pink') });严格模式
严格模式是JavaScript中的一种限制性更强的变种方式。
严格模式与非严格模式可以共存,可以逐渐的选择性加入严格模式。全局作用域
定义变量必须通过var。
严格模式禁止删除声明变量。delete关键字
使用delete删除一个变量名(而不是属性名):deletemyVariable
'usestrict'; deleteObject.prototype;//error. //删除一个不可配置的属性函数参数
定义相同名称的参数
要求参数名唯一。
在正常模式下,最后一个重名参数名讳覆盖之前的重名参数,之前的参数仍然可以通过arguments[i]来访问,还不是完全无法访问。关键字,保留字
使用eval或arguments作为变量名或函数名
严格模式下:
访问arguments.callee,arguments.caller,anyFunction.caller以及anyFunction.arguments都会抛出异常禁止使用八进制
浏览器都支持以零(0)开头的八进制语法:0644==420还有'\045==='%''
认为数字的前导零没有语法意义,但是会改变数字的意义。eval
严格模式下不能向全局作用域下添加变量
在正常模式下,代码eval('varx;')会给上层函数或全局引入一个新的变量x
严格模式下,eval为被运行的代码创建变量,eval不会影响到名称映射到外部变量或其它局部变量。varx=22; varevalX=eval("varx=42;x"); console.log(x===22); console.log(evalX===42);函数内部this
在正常模式下函数调用,this的值会指向全局对象,在严格模式中,this的值会指向undefiend。
当函数通过call和apply调用时,如果传入的是thisvalue参数是一个null和undefiend除外的原始值(字符串,数字,布尔值),则this的值会成为那个原始值的对应的包装对象。如果thisavlue参数的值是undefeind或null,则this的值会指向全局变量。在严格模式中,this值就是thisvalue参数的值,没有任何类型转换。
this:仅在this指向自己创建的对象时使用它
arguments
arguments对象属性不语对应的形参变量同步更新。
非严格模式下,修改arugmetns对象中的某个索引属性的值,和这个属性对应的形参变量的值也会同时变化。
严格模式下,arguments对象会以形参变量的拷贝的形式被创建和初始化。因此arguments对象的改变不会影响形参。arguments:总是通过形参的名字获取函数参数,或者在函数的第一行拷贝arguments
varargs=Array.prototype.slice.call(arguments)with
严格模式禁用with。
with问题:块内的任何变量都可以映射到with传进来的对象的属性,也可以映射到包围这个块的作用域内的变量(甚至是全局变量),在运行时才能够决定:在代码运行之前无法得到。
严格模式下,使用with会引起语法错误。varx=7; with(obj){//语法错误 //如果没有开启严格模式,with中的这个x会指向with上面的那个x,还是obj.x? //如果不运行代码,我们无法知道,因此,这种代码让引擎无法进行优化,速度也就会变慢。 x; }感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。