引用类型的值(对象)是引用类型的一个实例。引用类型是一种数据结构,用于将数据和功能组织在一起。
对象是某个特定引用类型的实例。新对象是使用 new 操作符后跟一个构造函数来创建的。
构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。
一、Object 类型
Object是一个基础类型,其他的所有类型都从 Object继承了基本的行为;
// **创建 Object 实例的方式有两种**
//第一种是使用 new操作符后跟 Object 构造函数;
var obj = new Object();
obj.name="chuqiao";
obj.age=18;
//第二种是使用对象字面量表示法;
var person = {
name:"chuqiao",
age:18
};
函数的参数传递选择
对那些必需值使用命名参数,而使用对象字面量来封装多个可选参数。
//访问对象的属性
person.name//点表示法
person["name"]//方括号表示法
//在使用方括号语法时,应该将要访问的属性以字符串的形式放在括号中;
//方括号语法的主要优点就是可以通过变量来访问属性
var propertyName="name";//注意这变量必须是 string 类型
console.log(person[propertyName])
二、Array 类型
是一组值的有序列表,同时还提供了操作和转换这些值的功能;
ECMAScript 数组的每一项可以保存任何类型的数据。
//创建数组的基本方式
//第一种使用 Array 构造函数
var colors = new Array();//也可以省略 new
//第二种使用数组字面量表示法
var name=[];
利用数组的 length 属性可以方便的在数组末尾添加新项;
检测数组
对于一个网页或者一个全局作用域而言,使用 instanceof 可以判断某个对象是不是数组
if(value instanceof Array){
...
}
Array.isArray()方法的目的是最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境创建的;
if(Array.isArray(value)){
...
}
转换方法
所有对象都具有 toLocalString()、toString()和 valueof()方法。
调用数组的 toString()方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串;
调用 valueOf()返回的还是数组;
var colors = ["red","blue","green"];
alert(colors.toString()); //red, blue, green
alert(colors.valueOf()); //red, blue, green 因为 alert()要接收字符串参数,所以它在后台调用了 toString()方法
console.log(colors.valueOf()); //["red", "blue", "green"]
console.log(colors.toString()); //red, blue, green
数组继承的 toLocalString()、toString()和 valueof()方法,在默认情况下都会以逗号分隔的字符串的形式返回数组项。
而使用 join()方法,则可以使用不同的分隔符来构建这个字符串。如果不给 join()方法传入任何值,或者给它传入 undefined,则使用逗号作为分隔符。
栈方法
栈是一种 LIFO(last-in-First-out,后进先出)的数据结构,也就是最新添加的项最早被移除。
// push()方法可以接受任意数量的参数,把他们添加到数组的末尾;
//并返回修改后的数组长度
var colors=new Array();
var count = colors.push("red","green");
console.log(count);//2
count=colors.push("black");
console.log(count);//3
//pop()方法则从数组的末尾移除最后一项,减少数组的 length 值;
//然后返回移除的项
var item = colors.pop();
console.log(item);//black
console.log(colors.length);//2
队列方法
队列数据结构的访问规则是 FIFO(First-In-First-out,先进先出)。队列在列表的末端添加项,在列表的前端移出项。
//shift()方法移除数组中的第一个项,并返回该项,同时将数组的长度减1。
var colors=new Array();
var count = colors.push("red","green");
console.log(count);//2
count = colors.push("black");
console.log(count);//3
var item = colors.shift();
console.log(item);//"red"
console.log(colors.length);//2
//unshift()方法在数组的前端添加任意项,并返回数组的长度。
var colors = new Array();
var count = colors.unshift("red","green");
console.log(count);//2
count = colors.unshift("black");
console.log(count)//3
var item = colors.pop();
console.log(item);//"green"
console.log(colors.length);//2
重排序方法
数组中已经存在两个可以直接用来重排序的方法:reverse()和 sort().
//reverse()翻转数组的顺序
var values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values)//[5, 4, 3, 2, 1]
//sort()方法按升序排列数组项,即最小的排最前面,最大的排最后面。
//sort()方法会调用每个数组项的 toString()转型方法,然后比较得到的字符串,以确定如何排序
var values = [0, 1, 5, 10, 15];
values.sort();
console.log(values);//[0, 1, 10, 15, 5]
//在进行字符串比较时,"10"位于"5"的前面
//sort()方法可以接受一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面
//升序
function compare(value1,value2){
if(value1<value2){//如果第一个参数位于第二个参数的前面,返回负数
return -1;
}else if(value1>value2){//如果第一个参数位于第二个参数的后面,返回正数
return 1;
}else{//如果两个参数相等
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values);//[0, 1, 5, 10, 15]
//降序
function compare(value1,value2){
if(value1<value2){//如果第一个参数位于第二个参数的前面,返回正数
return 1;
}else if(value1>value2){//如果第一个参数位于第二个参数的后面,返回负数
return -1;
}else{//如果两个参数相等
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values);//[15, 10, 5, 1, 0]
//对于数值类型或者 values()方法会返回数值类型的对象类型,可以使用更简单的比较函数;
//即比较函数返回两个参数的差值,如果返回第一个参数减去第二个参数则是升序;
//如果返回第二个参数减去第一个参数则是降序
function compare(value1,value2){
return value1-value2;//升序
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values);//[0, 1, 5, 10, 15]
function compare(value1,value2){
return value2-value1;//降序
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values);//[15, 10, 5, 1, 0]
操作方法
concat()方法可以基于当前数组中的所有项创建一个新数组;
这个方法会先创建当前数组一个副本,然后将接受到的参数添加到这个副本的末尾,最后返回新构建的数组。
var colors = ["red", "green", "blue"];
var colors1 = colors.concat();
var colors2 = colors.concat("yellow", ["black", "brown"]);
//在没给 concat()传参数的情况下,它只是复制当前数组并返回副本;
console.log(colors1);//["red", "green", "blue"]
//如果传递给 concat()方法的是一或多个数组,则该方法会将这些数组中的每一项添加到结果数组中;
//如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。
console.log(colors2);//["red", "green", "blue", "yellow", "black", "brown"]
//原数组不会被改变
console.log(colors);//["red", "green", "blue"]
<br/>
slice()方法可以基于当前数组中的一或多个项创建一个新数组。可以接受一或两个参数,即返回项的起始和结束位置。
var colors = ["red", "green", "blue" , "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(3,4);
var colors4 = colors.slice(-2,-1);
var colors5 = colors.slice(3,2);
//只有一个参数的情况下,返回从该参数指定位置开始到当前数组末尾的所有项;
console.log(colors2);//["green", "blue", "yellow", "purple"]
//如果有两个参数,该方法返回起始和结束位置之间的项,但不包括结束位置的项
console.log(colors3);//["yellow"]
//如果参数中有负数,则用数组长度加上该数来确定相应位置;在数组长度为5的情况,slice(-2,-1)与slice(3,4)得到的结果相同
console.log(colors4);//["yellow"]
//如果结束位置小于起始位置,则返回空数组
console.log(colors5);//[]
//slice()不会影响原始数组
console.log(colors);//["red", "green", "blue", "yellow", "purple"]
<br/>
splice()向数组的中部插入项,splice()会改变原始数组;
splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项;
如果没有删除任何项则返回一个空数组。
//删除:可以删除任意数量的项,只需要指定2个参数,需要删除的第一项的位置和要删除的项数。
var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1);//从第0项开始,删除一项
console.log(colors);//["green", "blue"] 原始数组被删除一项
console.log(removed);//["red"] 返回被删除的项
//插入:可以向指定位置插入任意数量的项;
//只需要提供3个参数,起始位置、0(要删除的项数)和要插入的项;
//如果要插入多个项,可以再传入第四个,第五,以及任意多个项;
removed = colors.splice(1, 0, "yellow", "orange");//从位置1开始插入两项 删除零项
console.log(colors);//["green", "yellow", "orange", "blue"] 原数组被插入两项
console.log(removed)//[] 返回的是一个空数组 因为被删除的是零项
//替换:可以像指定位置插入任意数量的项,且同时删除任意数量的项;
//只需要指定3个参数,起始位置、要删除的项数、和要插入的任意数量的项;
//插入的项数不必与删除的项数相等
removed = colors.splice(1,1,"red","purple");//插入两项,删除一项
console.log(colors);// ["green", "red", "purple", "orange", "blue"]
console.log(removed);//["yellow"] 返回被删除的那项
位置方法
indexOf()从数组的开头(位置0)开始查找;
lastIndexOf()从数组的末尾开始向前查找;
两个方法都返回要查找的项在数组中的位置,没找到的情况返回-1;
两个参数:第一个参数是要查找的项目;第二个参数可选,表示查找起点位置的索引;
在比较第一个参数与数组中的每一项时,使用的全等操作符;
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
console.log(numbers.indexOf(4)); //3 从头部开始查询4,返回其所在的数组中的位置
console.log(numbers.lastIndexOf(4));//5 从尾部开始查询4,返回其所在数组中的位置
console.log(numbers.indexOf(4,4));//5 从数组的位置4开始查询4,返回其所在数组中的位置
console.log(numbers.lastIndexOf(4,4));//3 从数组的位置4开始反向查询4,返回其所在数组中的位置
var person = {name:"chuqiao"};
var people = [{name:"chuqiao"}];
var morePeople = [person];
console.log(people[0]===person)//false
console.log(morePeople[0]===person)//true
console.log(people.indexOf(person))// -1 没找到 不全等
console.log(morePeople.indexOf(person))// 0 找到
迭代方法
数组定义了5种迭代方法,每个方法都接受两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象——影响 this 的值。
传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置、数组对象本身。
//every():对数组中的每一项运行给定函数,如果该函数每一项都返回 true,则返回 true;
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var everyResult = numbers.every(function(item, index, array){
return (item > 2);
});
console.log(everyResult);//false
//some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true;
var someResult = numbers.some(function(item,index,array){
return (item > 2);
});
console.log(someResult);//true
//filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组;
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});
console.log(filterResult);//[3, 4, 5, 4, 3]
//map():对数组中的每一项运行给定函数,返回函数每次调用的结果组成的数组;
var mapResult = numbers.map(function(item,index,array){
return item*2;
});
console.log(mapResult);//[2, 4, 6, 8, 10, 8, 6, 4, 2]
//forEach():对数组中的每一项运行给定函数,没有返回值;
numbers.forEach(function(item,index,array){
//执行某些操作
});
归并方法
reduce()和 reduceRight() 会迭代数组的所有项,然后构建一个最终返回的值;
接收两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值;
函数接收4个参数:前一个值,当前值,项的索引和数组对象;
//reduce():从数组的第一项开始,逐个遍历到最后;
var values = [1, 2, 3, 4, 5];
var reduceSum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
console.log(reduceSum);//15
//第一次执行回调函数,prev 是1,cur2;第二次执行 prev 是3(1+2的结果),cur 是3(数组的第三项)... 这个过程把数组的每一项都访问一遍后,最后返回结果
//reduceRight():从数组的最后一项开始,向前遍历到第一项;
var reduceRightSum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
console.log(reduceRightSum);//15
//作用与 reduce()相似,方向相反而已
<br/>
三、Date类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
(略)
<br/>
阅读:http://imweb.io/topic/56e804ef1a5f05dc50643106
<br/>
五、Function 类型函数实际上是 Function 类型的实例,因此函数也是对象;
// 函数名实际上是指向函数对象的指针;
function sum(num1, num2){
return num1+num2;
}
console.log(sum(10, 10));//20
var anotherSum = sum;
console.log(anotherSum(10, 10));//20
sum = null;
console.log(anotherSum(10, 10));//20
没有函数重载;同名的函数后面覆盖前面;
定义函数的两种方式:函数声明、函数表达式;
关于函数声明的提升问题可参见 [js学习笔记 2-03][2]
作为值的函数
函数名本身就是变量,所以函数也可以作为值来使用;也就是说不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回;
//eg1
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10);
console.log(result1);//20
function getGreeting(name){
return "Hello, " + name;
}
var result2 = callSomeFunction(getGreeting, "chuqiao");
console.log(result2);//Hello, chuqiao
//要访问函数的指针而不执行函数的话,必须去掉函数名后的那对括号;
//因此上面例子传递给 callSomeFunction()的是 add10和getGreeting,而不是执行他们之后的结果
//eg2 假设有一个对象组,想要根据某个对象属性对数组进行排序
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;
}
};
}
var data = [{name: "chuqiao", age: 28},{name: "ayue", age: 29}];
data.sort(createComparisonFunction("name"));//按照 name 属性的值升序
console.log(data[0].name)//ayue
data.sort(createComparisonFunction("age"));//按照 age 属性的值升序
console.log(data[0].name);//chuqiao
函数内部属性
arguments 和 this;
arguments:是一个类数组对象,包含着传入函数中的所有参数;它还有一个 callee的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。
//阶乘函数 递归
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
var trueFactorial = factorial;
factorial = function(){
return 0;
}
console.log(trueFactorial(5));//0
console.log(factorial(5))//0
//上面函数的执行与函数名 factorial紧紧耦合在一起了
//采用arguments.callee
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
//上面factorial()函数的体内没有再引用函数名factorial,这样无论引用函数时使用的是什么名字,都可以保证正常的完成递归调用;
var trueFactorial = factorial;
//变量trueFactorial获得了factorial的值,实际上是在另一个位置上保存了一个函数的指针
factorial = function(){
return 0;
}
console.log(trueFactorial(5));//120
console.log(factorial(5))//0
函数内部的另一个特殊对象是 this,即 this 引用的是函数据以执行的环境对象,或者说是 this 值(当网页的全局作用域中调用调用函数时,this 对象引用的就是 window)
window.color = "red";
var o = {color: "blue"};
function sayColor(){
console.log(this.color)
}
sayColor();//red 当全局作用域调用 sayColor()时,this引用的是全局对象window
o.sayColor = sayColor;
o.sayColor()//blue 当把函数sayColor赋值给 o.sayColor,并调用 o.sayColor(),this 引用的是 o对象
//另一个函数对象的属性:caller ;这个属性中保存着调用当前函数的函数引用,如果是全局作用域中调用当前函数,它的值是 null;
function outer(){
inner();
}
function inner(){
console.log(inner.caller)
}
outer(); //function outer(){ inner();}
函数的属性和方法
每个函数都包含两个属性:length 和 prototype;
函数的 length属性:表示函数希望接收的命名参数的个数;
函数的 prototype属性:是保存它们所有实例方法的真正所在,换句话说,诸如 toString()和 valueOf()等方法实际上都保存在 prototype名下,只不过是通过各自对象的实例访问罢了。(后续笔记详解)
每个函数都包含两个非继承而来的方法:apply() 和 call();
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]);//传入数组
}
console.log(callSum1(10,10));//20
console.log(callSum2(10,10));//20
call()方法接收的参数:第一个参数是 this 值,其余参数都是直接传递给函数(即传递给函数的参数必须逐个列举出来)
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2)
}
console.log(callSum(10,10))
apply()和 call()真正的用武之地:能够扩充函数赖以运行的作用域;使用他们来扩大作用域的最大好处就是对象不需要与方法有任何耦合关系;
window.color = "red";
var o = {color: "blue"};
function sayColor(){
console.log(this.color)
}
sayColor(); //red
sayColor.call(this);// red
sayColor.call(window);//red
sayColor.call(o);//blue
bind()方法:会创建一个函数的实例,其 this值会被绑定到传给 bind()函数的值。(后续笔记详解其技巧)
window.color = "red";
var o = {color:"blue"};
function sayColor(){
console.log(this.color)
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue