JavaScript高级程序设计(引用类型)

对象是引用类型的一个实例。
创建Object实例的两种方法。第一种是使用new

var person= new Object();
person.name="Nicholas";
person.age=29;

另一种是使用对象字面量表示法。
var person={
name:”Nicholas”,
age:29
};

两种方式访问对象属性:
person[“name”],person.name

**5.2 Array类var person1={
toLocaleString:function(){
return “Nikolaos”;
},
toString:function(){
return “Nikolaos”;
}
};
var person2={
toLocaleString:function(){
return “Grigorios”;
},
toString:function(){
return “Greg”;
}
}
var people=[person1,person2];
alert(people);//Nicholas,Greg
alert(people.toString());//Nicholas,Greg
alert(people.toLocaleString());//Nicholas,Grigorios
toString(),toLocaleString(),join()

5.2.3 栈方法
栈是后进先出的数据结构,插入和移除发生在一个位置-栈的顶部。

var colors=new Array();
    var count=colors.push("red","green");
    alert(count);//2
    count=colors.push("black");
    alert(count);//3
    var item=colors.pop();
    alert(item);//"black"
    alert(colors.length);//2

push()返回的是修改数组的长度。
pop()方法则是返回移除的项。

5.2.4队列方法
后进先出,队列在列表的末端添加项,从列表的前端移除项。
一个从数组前端取得项的方法,shift().
它能够去除数组中的第一个项并返回该项,同时将数组长度减1.
结合使用shift()和push()方法,可以像队列一样使用数组。

var colors=new Array();
    var count=colors.push("red","green");
    alert(count);//2
    count=colors.push("black");
    alert(count);//3
    var item=colors.shift();
    alert(item);//"red"
    alert(colors.length);//2

unshift():可以在数组前端添加任意个项并返回新数组的长度。
因此,同时使用Unshift()和pop()方法可以从相反的方向来模拟队列。即,从数组前端添加项,数组末端移除项。

5.2.5重排序方法
数组中已经存在两个可以直接用来重排序的方法:reverse()和sort()。反转和排序。

var value=[0,1,5,10,15];
    value.sort();
    alert(value);//0,1,10,15,5

sort()方法会调用每个数组项中的toString()转型方法,然后比较得到字符创。
sort()方法也可以比较函数作为参数,第一个参数位于第二个参数之前则返回负数,位置相同则返回0,第一个位于位于第二个之后,则返回正数。

function compare(value1,value2) {
      if(value1<value2){
        return 1;
      }else if(value1>value2){
        return -1;
      }else{
        return 0;
      }
    }
    var value=[0,1,5,10,15];
    values.sort(compare);
    alert(values);//15,10,5,1,0
    //改变产生降序的结果则可以从大到小返回

或者使用更简单的语句

function compare(value1,value2){
    return value2-value1;
}

5.2.6操作方法

concat:

var colors=["red","green","blue"];
    var colors2=colors.concat("black","brown");
    alert(colors);//red,green,blue
    alert(colors2);//red,green,blue,black,brown

slice:

var colors=["red","green","blue","black","brown"];
    var colors2=colors.slice(1);
    var colors3=colors.slice(1,4);
    alert(colors2);//green,blue,black,brown
    alert(colors3);//green,blue,black

这里写图片描述

splice():数组方法,可以删除,插入,替换
删除参数(要删除第一项的位置,要删除的项数)
插入参数(起始位置,要删除的项数,要插入的项(可以有多项))
替换参数(起始位置,要删除的项数,要插入任意数量的项)
splice()方法始终都会返回一个数组。
var colors=[“red”,”green”,”blue”];
var removed=colors.splice(0,1);
alert(colors);//green,blue
alert(removed);//red返回的数组只包含一项

 removed=colors.splice(1,0,"yellow","orange");
    alert(colors);//green,yellow,orange,blue,
    alert(removed);//返回一个空数组

    removed=colors.splice(1,1,"yellow","orange");
    alert(colors);//green,yellow,orange,blue,
    alert(removed);//yellow返回的数组只包含一项

5.2.7位置方法
Indexof()和lastIndexof()
接收参数:要查找的项和(可选的)表示查找起点位置的索引
一个从前查找,一个从后查找
这两个方法都返回要查找的项在数组中的位置,或者在没有找到的情况下,返回值-1

var number=[1,2,3,4,5,4,3,2,1];
    alert(number.indexOf(4));//3
    alert(number.lastIndexOf(4));//5
    alert(number.indexOf(4,4));//5
    alert(number.lastIndexOf(4,4));//3
    var person={name:"Nicholas"};
    var people=[{name:"Nicholas"}];
    var morePeople=[person];
    alert(people.indexOf(person));//-1
    alert(morePeople.indexOf(person));//0

5.2.8迭代方法看书重点!
ECMAScript为数组定义了5个迭代方法,每个方法都接收两个参数:要在每一项运行的函数和(可选的)运行该函数的作用域对象–影响this值。

传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。
every(),some(),filtere(),map(),foreach()

5.2.9缩小方法
reduce()以及reduceRight()

5.3Date类型

5.4RegExp

5.5Function类型

function sum(num1,num2){
      return num1+num2;
    }
    alert(sum(10,10));//20
    var anotherSum=sum;
    alert(anotherSum(10,10));//20
    sum=null;
    alert(anotherSum(10,10))//20

使用不带圆括号的函数名是访问函数指针,而并非调用函数。此时sum与anotherSum就指向同一个函数。anotherSum()也可以被调用并返回结果。即使将sum设置为Null,但仍然可以正常调用anotherSum().

5.5.1没有重载
将函数名想象为指针。

function addSomeNumber(num){
      return num+100;
    }
    function addSomeNumber(num){
      return num+200;
    }
    var result=addSomeNumber(100)//300

5.5.2函数声明与函数表达式
解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可以访问;至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

alert(sum(10,10));
    function sum(num1,num2){
      return num1+num2;
    }

以上代码完全可以正常运行,因为在代码执行之前,解析器就已经通过一个名为函数声明提升的过程。读取并将函数声明添加到执行环境中。

alert(sum(10,10));
    sum=function sum(num1,num2){
      return num1+num2;
    }

函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。错误原因在于函数位于一个初始化语句中,而不是一个函数声明。

5.5.3作为值的函数
函数本身也是变量,所以函数也可以作为值来使用。不仅可以像传递参数一样把一个函数传递给另一个函数,而且也可以将一个函数作为另一个函数的结果返回。

function callSomeFunction(someFunction,someArgument){
      return someFunction(someArgument);
    }

这里的函数接受两个参数。第一个参数应该是一个函数,第二个参数应该是要传递给该函数的一个值。例子:

这里写图片描述

这里的callSomeFunction()函数是通用的,即无论第一个参数中传递进来的是什么函数,它都会返回执行第一个参数后的结果。

要返回函数的指针而不执行函数的话,必须去掉函数名后面的那对括号。因此上面例子中传递给callSomeFunction()的是add10和getGreeting,而不是执行他们之后的结果。

当然从一个函数中返回另一个函数,这也是极为有用的。
假设有一个数组,我们想要根据某个属性对数组进行排序。而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值。可是我们需要一种方式开指明按照哪个属性来排序。要解决这个问题可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数,下面就是这个函数的定义。

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;
        }
      }
    }

这个函数内部嵌套了另一个函数,而且内部函数前面添加可一个return操作符。在内部函数接收到propertyName参数后,它会使用方括号表示法来取得给定属性的值。取得想要的属性值后,定义比较函数就简单额。上面这个函数可以像下面例子中这样使用。

var data=[{name:"Zachary",age:28},{name:"Nicholas",age:29}];
    data.sort(createCompareionFunction("name"));
    alert(data[0].name);//Nicholas
    data.sort(createCompareionFunction("age"));
    alert(data[0].name);//Zachary

这里写图片描述

5.5.4函数内部属性
在函数内部,有两个特殊的对象:arguments和this.其中,arguments是一个类数组对象,包含传入函数的所有参数。

arguments主要用途是保存函数参数,对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
如下面的递归算法:

function factorial(num){
    if(num<1){
    return 1;
    }else{
    returnn num*factorial(num-1);
}
}

如上面所示,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名factorial紧紧耦合在一起,为了消除这种耦合紧密的现象,可以像下面这样使用arguments.callee.

function factorial(num){
      if(num<=1){
        return 1;
      }else{
        return num*arguments.callee(num-1);
      }
    }

5.5.5函数的属性和方法
函数也是对象,因此函数也有属性和方法。每个函数都包含两个属性:Length和prototype。其中,length表示函数希望接收的命名参数的个数。

function sayName(name){
    alert(name);
  }
  function sum(num1,num2){
    return num1+num2;
  }
  function sayHi(name){
    alert("Hi");
  }
  alert(sayName.length);//1
  alert(sum.length);//2
  alert(sayHi.length);//0

对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。换句话说,例如toString()和valueOf()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。

在创建自定义引用类型以及实现继承时,Prototype属性是极为重要的。

在ECMAScript中,ptototype属性是不可枚举的,因此用for-in无法发现。

每个函数包含两个非继承来的方法:apply()与call()。这两个方法的用途都是在特定的作用域中调用函数,实际等于设置函数体内this对象的值。

首先,apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中第二个参数可以是Array的实例,也可以是arguments对象。例如:

function sum(num1,num2){
    return num1+num2;
  }
  function callSum1(num1,num2){
    return sum.apply(this,arguments);//传入arguments对象
  }
  function callSum2(num1,num2){
    return sum.apply(this,[num1,num2]);、、传入数组
  }
  alert(callSum1(10,10));//20
  alert(callSum2(10,10));//20

在上面这个例子中,callSum1()在执行sum()函数时传入了this作为this值(因为是在全局作用域中调用,所以传入的就是window对象)和arguments对象。而callSum2同样也调用sum()函数。但它传入的则是this和一个参数数组。这个函数都会正常执行并返回为正确的结果。

call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于call()方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用call()方法时,传递给函数的参数必须逐个列举出来。

function sum(num1,num2){
    return num1+num2;
  }
  function callSum(num1,num2){
    return sum.call(this,sum1,sum2);
  }
  alert(callSum(10,10));//20

在使用call()方法的情况下,callSum()必须明确地传入每一个参数。结果与使用apply()没有什么不同,至于是使用apply()还是call(),完全取决于你采取那种给函数传递参数的方式最方便。
如果直接传入arguments对象,或者包含函数中先接收到的也是一个数组,那么使用apply更好,否则选择call。不给函数传递参数,使用哪一个都无所谓。

事实上,传递参数并非apply()和call()的用物之地:它们真正强大的地方是能够扩充函数赖以运行的作用域。

window.color="red";
  var o={color:"blue"};
  function sayColor(){
    alert(this.color);
  }
  sayColor();//red
  sayColor.call(this);//red
  sayColor.call(window);//red
  sayColor.call(o)//blue

this.color也是作为全局函数定义的,而且对this.color的求值会转换为window.color的求值。
当sayColor.call(o)时,函数的执行环境就不一样了,因为此时函数体内的this对象指向了O,。
使用call与apply来扩充作用域的好处,就是对象不需要和方法有任何耦合关系。

ECMAScript5还定义了一个方法:Bind(),这个方法会创建一个函数的实例,其this值会被绑定到传给Bind()函数的值,例如:

window.color="red";
  var o={color:"blue"};
  function sayColor(){
    alert(this.color);
  }
  var objectSayColor=sayColor.bind(o);
  objectSayColor();//blue

在这里,sayColor()调用bind()并传入对象o,创建了objectSayColor()函数。objectSayCorlor()函数的this的值等于o。

每个函数都继承toLocaleString和toString()方法都始终返回函数的代码。

5.6基本包装类型
ECMAScript还提供了3个特殊的引用类型:bolean,number和string.实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装l类型的对象,从而让我们能够调用一些方法来操作这些数据。

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

会执行以下步骤:
(1)创建String类型的一个实例;
(2)在实例上调用指定的方法;
(3)销毁这个实例
将返回结果保存在s2中。
可以将以上三个步骤想象成是执行了下列ECMAScript代码:

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

引用类型与基本包装类型的主要区别就是对象的生存期,使用new操作符创建的引用类型的实例在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型添加属性和方法。

var s1="some text";
s1.color="red";
alert(s1.color);//undefined

5.6.1Boolean类型

var booleanObject =new Boolean(true);

调用Boolean构造函数并传入true或者false值。
valueOf(),toLocalString(),toString()方法被重写

var falseObject=new Boolean(false);
  var result=falseObject&&true;
  alert(result);//true

  var falseValue=false;
  result=falseValue&&true;
  alert(result);//false

布尔值中所有对象都会转换为true,因此falseObject对象在布尔表达式中代表的是true.

理解基本类型的布尔值和boolean对象之间的区别非常重要,建议是永远不要使用boolean对象。

5.6.2Number对象

var num=10;
alert(num.toFixed(2));//"10.00"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值