JavaScript之引用类型(ECMAScript5)

Object类型

 1 //创建方式一
 2 var person = new Object();
 3 person.name = "jack";
 4 person.age = 12;
 5 
 6 //创建方式二
 7 var person = {
 8       name:"jack",
 9       age:12
10 }
11 //创建空对象
12 var person = {};//与new Object()相同
13 
14 //访问方式
15 person["name"];  jack
16 person.name;  jack
17 //以上两种方式区别在于使用中括号方式可以通过变量访问
18 var propertyName="name";
19 person[propertyName];  jack
20 person["first name"] = "jack";//如果属性名有空格

Array类型  

//定义
var array = new Array();
var array2 = new Array("a","b","c");
var array3 = ["a","b","c"];
//修改
array3[2] = "d";//array3:a,b,d
//新增
array3[3] = "d";//array3:a,b,c,d
array3[length] = "d";//array3:a,b,c,d第二种新增方式
//末尾删除元素
//数组的length属性不是只读的,所以通过改变length可以从数组末尾移除
array3.length=3;//array3:a,b,c
 

检测数组:确定一个值是哪种基本类型(Undefined,Null,Boolean,Number,String)使用typeof操作符,确定一个值是哪种引用类型使用instanceof操作符。

之所以Array中新增了Array.isArray()方法,是因为instanceof操作符是在只有一个全局执行环境的情况下;如果包含多个框架,那就存在两个以上不同的全局环境,就存在两个以上的不同版本的Array构造函数。 栈方法(LIFO):Array通过push(接收任意数量的参数,逐个添加到数组末尾)和pop(从数组末尾移除最后一项,并减少length值,返回移除的项)两个方法可以实现类似栈的行为。

队列方法(FIFO):Array通过shift(从数组前端取得项)和push或unshift(在数组前端添加任意个项并返回新数组的长度)和pop两种都能实现模拟队列的形式。

重排序方法:reverse(反转数组项的顺序);sort(实现排序,接收一个自定义函数,通过负数,0,正数)

操作方法:concat(基于接收的参数添加到副本数组中,并返回数组的副本);slice(返回起始和结束位置之间的项,但不包括结束位置的项);splice()方法:可以删除任意数量的项splice(0,2)会删除前两项(要删除第一项的位置和要删除的项数);可以向指定位置插入多个项;可以向指定位置插入任意数量的项 同时删除任意数量的项。

位置方法:ECMAScript 5为数组实例添加了两个位置方法:indexOf()和lastIndexOf()

迭代方法

  1. every():接收一个函数,如果对于数组每一项都返回true,结果返回true。
  2. some():接收一个函数,如果对于数组中有返回true的项,结果就返回true,注意与every区别。
  3. filter():接收一个函数,返回满足条件也就是true的项。
  4. forEach():对数组中每一项运行给定的函数。
  5. map():运行给定的函数,返回每次函数调用的 结果组成的数组。

归并方法:reduce(从数组第一项开始)和reduceRight(从数组最后一项开始)。

Function类型

函数实际上是对象,每个函数都是Function类型的实例,都与其他引用类型一样具有属性和方法。因此函数名实际上也是一个指向函数对象的指针。

 1 //使用函数声明语法定义
 2 function sum(num1,num2)
 3 {
 4      return num1+num2;          
 5 }
 6 //使用函数表达式定义,注意结尾要加分号
 7 var sum = function(num1,num2)
 8 {
 9     return num1+num2;
10 };

函数声明与函数表达式是有区别的,解析器在向执行环境加载数据时,会率先读取函数声明,并使其在执行任何代码之前可以访问;而函数表达式则需要等到解析器执行到它所在的代码行才会真正被解释执行,也就是说函数表达式要写在调用函数代码的前面。

函数可以作为值来使用,既可作为参数也可作为返回值,如下例子:

//根据属性名来创建一个比较函数,来指明按照哪个属性来排序
function createComparisonFunction(propertyName)
{
    return function(object1,object2)
     {
         var value1 = object1[propertyName];
         var value2 = object2[propertyName];
         
         if(value1<value2){
             return -1;
         }else if(value1<value2){
             return 1;
         }else{ 
             return 0;
         }
     }
}    
//利用数组data调用sort()方法
data.sort(createComparisonFunction("name"));

函数内部属性:

在函数内部,有两个特殊对象:arguments和this。arguments的主要用途是保存函数参数,其中有个callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。 

//简单的递归算法,但是函数内部的执行和函数名factorial耦合在一起
function factorial(num)
{
    if(num<=1)
    {
        return 1;
    }else{
        return num*factorial(num-1);
    }
}
//利用arguments.callee解决
function factorial(num)
{
    if(num<-1){
        return 1;
    }else{
        return num*arguments.callee(num-1);
    }
}

另外一个函数对象的属性是:caller。其保存着调用当前函数的函数的引用。也就是谁调用的函数,caller就把它的引用保存下来。

function outer()
{
   inner();
}

function inner()
{
   alert(inner.caller);//弹出outer()函数的源代码
   alert(arguments.callee.caller);//和上一句一样
}

函数属性和方法:

每个函数都包含两个属性:length(函数接收的命名参数的个数)和prototype。

每个函数都包含两个非继承而来的方法:apply()和call(),在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。apply()接收两个参数,一个在其中运行函数的作用域,拎一个是参数数组(可以是array或arguments对象)。call()第一个参数和apply一样,后面必须明确传入每个参数。除了用法不同其他的没什么不同。另外他们真正强大的地方是能够扩充函数赖以运行的作用域。

function sum(num1,num2)
{
     return num1+num2;  
}
sum.apply(this, [num1,num2] );
sum.call(this,num1, num2);

//扩充函数作用域
window.color = "red";
var o = {color:"blue"};
function showColor(){
    alert(this.color);
}

showColor();//red
showColor.call(this);//red
showColor.call(window);//red
showColor.call(o);//blue

也可以使用bind()方法。

 

基本包装类型


为了便于操作基本类型值,ECMAScript引入3个特殊的引用类型:Boolean,Number,String。所谓包装类型,就是将基本类型包装起来,放一些操作方法和属性等。

每当读取一个基本类型值的时候,后台就会创建与一个对应的基本包装类型的对象,从而能让我们可以调用某些方法操作这些数据。

var s1 = "some text";
var s2 = s1.substring(2);

//后台内部相当于如下代码
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

当第二行代码访问s1时,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值,读取模式访问字符串时,后台都会自动完成下列处理:

  1. 创建String类型的一个实例。
  2. 在实例上调用指定的方法。
  3. 销毁这个实例。

引用类型与基本包装类型的主要区别就是对象的生存期。使用new 操作符在执行流离开当前作用域之前一直保存在内存中。而自动创建的基本包装类型的对象,则只存在一行代码的执行瞬间,然后立即销毁。

单体内置对象

内置对象:

由ECMAScript实现提供的,不依赖于宿主环境的对象,程序执行之前就已经存在,比如:Object,Array和String。另外还有Global和Math。

Global对象:

  • URI编码方法:通过encodeURI()和encodeURICOMponent()方法对URI进行编码,以便发送给浏览器。区别在于第一个不会对本身属于URI的特殊字符进行编码,例如冒号,正斜杠,问号和井号。而另一个则会对它发现的任何非标准字符进行编码。与这两个方法对应的是:decodeURI(只能对使用encodeURI()替换的字符进行解码)和decodeURIComponent(针对encodeURIComponent()编码的字符)。
  • eval()方法像是一个解析器。比如eval("function say(){  alert(' Hi '); }");但是创建的任何变量或者函数都不会被提升,只有在eval执行时候才创建。
  • window对象,全局作用域中声明的所有变量和函数,都成为了window对象的属性。

Math对象:

  • 提供数学公式和信息的公共位置。
  • 比如min()和max()方法,确定一组数值中最小值和最大值,都可以接收任意多个数值参数。
  • 舍入方法,Math.ceil(向上舍入),Math.floor(向下舍入),Math.round(标准的四舍五入)
  • random()方法返回大于等于0小于1的一个随机数。
//套用如下公式,从某个整数范围随机选择一个值
var result = Math.floor(Math.random()*可能值的总数+第一个可能的值)
//如下会选择一个介于2到10之间(包括边界)的值。
//从2数到10要数9个数,所以可能值的总数是9
var num = Math.floor(Math.random()*9+2);
View Code

当然Math还有其他许多方法。

小结

  • 引用类型和传统面向对象程序设计中的类相似,但实现不同
  • Object是一个基础类型,其他所有类型都从Object继承了基本的行为
  • Array类型是一组值的有序列表,同时还提供了操作和转换这些值的功能
  • Date类型提供了有关日期和时间的信息
  • 函数实际上是Function类型的实例,因此函数也是对象;而这一点正是js最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为
  • 基本包装类型使得基本类型值可以被当做对象来访问,从而方便数据的操作,在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便数据操作。一经执行完毕,就会立即销毁新创建的包装对象
  • 在所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。Web浏览器实现了承担该角色的window对象。

 

 

posted @ 2017-07-10 09:34  贝同学  阅读(769)  评论(0编辑  收藏  举报