JavaScript 学习笔记:引用类型

Object类型

创建引用类型(如 Object)实例的方式有 2 种,第一种是使用 new 操作符后跟 Object 构造函数:

JAVASCRIPT
var person = new Object(); person.name = "Sky"; person.age = 26;

另一种是使用对象字面量表示法,对象字面量是对象定义的一种简写形式。

JAVASCRIPT
var person = { name : "Sky", "age" : 26 // 属性名的双引号可省略 };
JAVASCRIPT
var person = {}; // 等价于:var person = new Object(); person.name = "Sky";

对象字面量还可以用来向函数传递大量可选参数。

JAVASCRIPT
function displayInfo(args){ var output = ""; if(typeof args.name == "string"){ output += "name: " + args.name + "\n"; } if(typeof args.age == "number"){ output += "age: " + args.age + "\n"; } console.log(output); } displayInfo({ name: "Sky", age: 26 }); displayInfo({ name: "Sky" });
输出
name: Sky age: 26 name: Sky

访问对象的属性可以使用点表示法或者方括号表示法。

方括号表示法的主要优点是:可以通过变量来访问属性,或者属性名可能引发语法错误时使用。

JAVASCRIPT
console.log(person.name); console.log(person["name"]); var attrName = "first name"; console.log(person[attrName]); //若使用person.first name显然会报错

Array类型

创建数组

创建数组的方法:

JAVASCRIPT
var colors = new Array(); var colors = new Array(3); //创建一个长度为3的数组 var colors = new Array("red", "blue", "green"); //创建数组并传递应该包含的项 var colors = Array(); //new可以省略

也可以使用数组字面量表示法:

JAVASCRIPT
var colors = []; //创建空数组 var colors = ["red", "blue", "green"]; //创建包含3个项的数组

访问数组

使用数字索引来访问或设置数组的值。

JAVASCRIPT
var colors = ["red", "blue", "green"]; console.log(colors[0]); colors[4] = "yellow"; //索引不存在则新建项 colors[colors.length] = "brown"; //利用length属性可以方便地在数组末尾添加项 console.log(colors);
输出
red ["red", "blue", "green", undefined, "yellow", "brown"]
数组的length属性不是只读的!
JAVASCRIPT
var colors = ["red", "blue", "green"]; colors.length = 2; //最后一项被删除了 console.log(colors);
输出
["red", "blue"]

检测数组

检测一个值是否是数组:

JAVASCRIPT
colors instanceof Array

在 IE9+ 浏览器上,还可以使用更准确的方法——Array.isArray函数:

JAVASCRIPT
Array.isArray(colors)

输出数组

使用toStringvalueOfjoin方法可以将数组直接输出出来,默认以逗号分隔每项。

JAVASCRIPT
alert(colors.toString()); alert(colors.valueOf()); alert(colors); alert(colors.join()); alert(colors.join("|"));
输出
red,blue red,blue red,blue red,blue red|blue

push与pop

栈是一种 LIFO(Last-In-First-Out,后进先出)的数据结构,ECMAScript 为数组提供了push-推入和pop-弹出的方法实现栈的行为。

push接收任意数量参数,逐个添加到数组末尾,返回修改后数组长度;

pop移除末尾项并返回该项。

JAVASCRIPT
var colors = new Array(); colors.push("red", "blue"); colors.pop();

shift与unshift

队列的访问规则是 FIFO(First-In-First-Out,先进先出),在末尾添加项,在前端移除项。

shift能移除数组的第一项并返回该项,unshift能够从前端添加任意多项,并返回修改后数组长度。

JAVASCRIPT
var colors = new Array(); colors.push("red", "blue"); colors.shift(); colors.unshift("green", "yellow");

数组排序

reverse函数可以反转数组中的项,sort会转换数组中的项为字符串后,再按升序进行排列。

JAVASCRIPT
var nums = [0,1,5,10,15]; nums.reverse(); console.log(nums); nums.sort(); console.log(nums);
输出
[15, 10, 5, 1, 0] [0, 1, 10, 15, 5]

由于sort比较的是字符串,上例的排序并非我们想要的。但sort支持接收一个比较函数作为参数,让我们指定比较规则。

JAVASCRIPT
var nums = [0,1,5,10,15]; nums.sort(compare); console.log(nums); //升序比较规则函数 function compare(value1,value2){ return value1 - value2; }
输出
[0, 1, 5, 10, 15]

合并数组

concat会返回当前数组的副本,如果传入参数,则会将参数添加到数组末尾后再返回新的数组。

JAVASCRIPT
var colors = ["red","blue"]; var colors2 = colors.concat("green",["white","brown"]); console.log(colors.toString()); console.log(colors2.toString());
输出
red,blue red,blue,green,white,brown

截取子数组

slice会基于原数组返回一个子数组,原数组不会改变。第一个参数是起始位置,第二个参数(可选)是结束位置。

JAVASCRIPT
var colors = ["red","blue","green", "white"]; var colors2 = colors.slice(1); var colors3 = colors.slice(1,3); //含1但不含3 console.log(colors.toString()); console.log(colors2.toString()); console.log(colors3.toString());
输出
red,blue,green,white blue,green,white blue,green
类似的方法,一般都是仅包含起始位置项,但不包含结束位置项!

splice方法

splice算是最强大的数组方法了,主要的用法:

删除splice(0,2)删除第 0 位置开始的 2 项;

插入splice(1,0,"a","b")删除位置 1 开始的 0 项(即不删除项),并在位置1处插入"a","b"两项;

替换splice(1,1,"a","b")删除位置 1 开始的 1 项,并在位置 1 处插入"a","b"两项。

JAVASCRIPT
var colors = ["red","blue","green", "white"]; var removed = colors.splice(0,1); console.log(colors.toString()); console.log(removed.toString()); removed = colors.splice(1,0,"yellow"); console.log(colors.toString()); console.log(removed.toString()); removed = colors.splice(1,2,"black","gray"); console.log(colors.toString()); console.log(removed.toString());
输出
blue,green,white red blue,yellow,green,white (空字符串) blue,black,gray,white yellow,green
splice 方法会直接修改原数组,返回值是被删除的数组集合。

获取位置

indexOf从位置 0 开始查找项,lastIndexOf从数组末尾开始查找。可选的第 2 个参数:开始查找的起点位置。

JAVASCRIPT
var colors = ["red","blue","green","red", "white"]; console.log(colors.indexOf("red")); console.log(colors.indexOf("red",1)); console.log(colors.lastIndexOf("red"));
输出
0 3 3
比较项是否相等,内部采用的是全等操作符(===),即类型和值都必须一致。

数组迭代

几个常用的迭代函数:

every:对数组中每一项运行指定函数,全部为 true 则返回 true;

some:只要有一项为 true 则返回 true;

filter:返回运行函数返回为 true 的所有项组成的数组;

map:返回运行函数返回值组成的数组;

forEach:对数组中每一项运行指定函数,无返回值。

JAVASCRIPT
var nums = [1,2,3,4,5]; var everyResult = nums.every(function(item,index,array){ if(item > 2){ return true; } }); console.log(everyResult.toString()); var someResult = nums.some(function(item,index,array){ if(item > 2){ return true; } }); console.log(someResult.toString()); var filterResult = nums.filter(function(item,index,array){ if(item > 2){ return true; } }); console.log(filterResult.toString()); var mapResult = nums.map(function(item,index,array){ return item+1; }); console.log(mapResult.toString()); var sum = 0; nums.forEach(function(item,index,array){ sum += item; }); console.log(sum); console.log(nums.toString()); //上面的操作不会修改原数组
输出
false true 3,4,5 2,3,4,5,6 15 1,2,3,4,5

Date类型

使用new Date()创建一个日期对象。

Date.parseDate.UTC都返回表示日期的毫秒数,Date.parse传递一个表示日期的字符串,而Date.UTC传入年、月、日、时、分、秒,其中年、月必填,月是从 0 开始,小时是 24 小时制的。

JAVASCRIPT
var now = new Date(); //当前时间 var date1 = new Date("8/19/2015"); var date2 = new Date(Date.parse("8/19/2015")); //与上面等价 var date3 = new Date(2015,10,17,22,18,56); //注意10代表11月,因为月份是从0开始的 var date4 = new Date(Date.UTC(2015,10,17,22,18,56)); //与上面等价

关于Date类型的常用方法:

JAVASCRIPT
var now = new Date(); console.log(now.getFullYear()); console.log(now.getMonth()); //从0开始的月份 console.log(now.getDate()); console.log(now.getDay()); //星期几,0代表星期日 console.log(now.getHours()); console.log(now.getMinutes()); console.log(now.getSeconds()); console.log(now.getMilliseconds()); console.log(now.getTimezoneOffset()); //本地时间与UTC时间相差的分钟数
输出
2015 7 19 3 22 15 22 239 -480

RegExp类型

创建正则表达式:/pattern/flags ;

其中,模式(pattern)部分是正则表达式,flags代表1个或多个标志,可能的标志包括:

g:全局模式,模式被应用于所有字符串,而非发现第一个匹配后就立即停止;

i:忽略大小写;

m:多行模式。

模式中用到的所有元字符必须在前面加""转义,元字符包括:

( ) [ ] { } \ ^ $ | ? * + .

JAVASCRIPT
// 匹配所有的以"at"结尾的3个字符的组合,忽略大小写 var pattern1 = /.at/gi; // 匹配所有的".at",忽略大小写 var pattern2 = /\.at/gi;

也可以使用RegExp构造函数创建正则表达式:

JAVASCRIPT
var pattern1 = new RegExp(".at","gi"); // 注意2个参数都是字符串形式的!

使用test函数检测字符串与模式是否匹配:

JAVASCRIPT
var text="000-00-0000"; var pattern = /\d{3}-\d{2}-\d{4}/gi; pattern.test(text);
输出
true

Function类型

定义函数

定义函数的 3 种方式:

JAVASCRIPT
// 方式1:函数声明定义函数 function sum(num1, num2){ return num1 + num2; } // 方式2:函数表达式定义函数 var sum = function(num1, num2){ return num1 + num2; } // 方式3:构造函数定义函数(不推荐) var sum = new Function("num1", "num2", "return num1 + num2"); //前面的参数作为函数参数,最后一个参数视作函数体

函数其实是Function类型的实例,因此函数也是对象,函数名实际上是一个指向函数对象的指针。

JAVASCRIPT
function sum(num1, num2){ return num1 + num2; } console.log(sum(1,2)); var anotherSum = sum; console.log(anotherSum(3,4)); sum = null; console.log(anotherSum(3,4)); //sum指针变为null,并不会影响anotherSum这个指针
输出
3 7 7

没有重载

由于没有函数签名,所以 ECMAScript 中没有重载的概念。同名函数后面的函数会覆盖前面的。

JAVASCRIPT
function sum(num1, num2){ return num1 + num2; } function sum(num1, num2, num3){ return num1 + num2 + num3; } console.log(sum(1,2,3));
输出
6

其实上面的代码等价于:

JAVASCRIPT
var sum = function(num1, num2){ return num1 + num2; }; sum = function(num1, num2, num3){ return num1 + num2 + num3; }; console.log(sum(1,2,3));

这样可以更直观的看出,后面的sum覆盖了前面的。

在代码开始执行之前,解析器会通过一个名为函数声明提升(function declaration hoisting)的过程读取全部函数声明并添加到相应的执行环境中。所以,可以先调用函数,再去用函数声明的方式定义该函数。

JAVASCRIPT
console.log(sum(1,2)); function sum(num1, num2){ return num1 + num2; }
输出
3

而如果函数是利用函数表达式定义的,则必须等到解析器执行到它所在的代码行,才会被解析执行。

JAVASCRIPT
console.log(sum(1,2)); var sum = function(num1, num2){ return num1 + num2; };
输出
TypeError: sum is not a function

作为值的函数

因为函数名本身就是变量,所以函数也可以作为值来使用。

现在假设有一个数组对象,需要按照对象的某个属性来进行排序,可以这样写:

JAVASCRIPT
function createComparisonFunction(propertyName){ //该函数返回一个比较函数 return function(obj1, obj2){ var val1 = obj1[propertyName]; //因为这里属性值是变量,只能使用方括号表示法 var val2 = obj2[propertyName]; if(val1 < val2){ return -1; }else if(val1 > val2){ return 1; }else{ return 0; } } } var data = [{name: "Zhang", age:20},{name: "Li", age:30}]; //按name属性排序 data.sort(createComparisonFunction("name")); console.log(data); //按age属性排序 data.sort(createComparisonFunction("age")); console.log(data);
输出
[Object { name="Li", age=30}, Object { name="Zhang", age=20}] [Object { name="Zhang", age=20}, Object { name="Li", age=30}]

函数内部有 2 个特殊对象:argumentsthis

arguments对象

arguments包含传入函数的参数数组,它还有 1 个名为callee的属性,指向函数本身。

JAVASCRIPT
//递归函数 function factorial(num){ if(num <= 1){ return 1; }else{ return num * arguments.callee(num - 1); //使用arguments.callee调用函数本身,能够不依赖函数名 } } var newFactorial = factorial; factorial = function(){ return 0; } console.log(newFactorial(5)); console.log(factorial(5));
输出
120 0

this对象

函数内部的另一个特殊对象就是thisthis指向函数所在的执行环境,当在全局作用域中调用函数时,this对象引用的就是window

JAVASCRIPT
var color = "red"; function showColor(){ console.log(this.color); } var obj = { color : "blue", showColor : showColor }; showColor(); //获取的是window.color obj.showColor(); //获取的是obj.color
输出
red blue

函数属性

ECMAScript 中的函数也是对象,因此也有属性和方法。每个函数都包含 2 个属性:lengthprototype

length属性表示函数的参数个数:

JAVASCRIPT
function sum(num1, num2){ return num1 + num2; } console.log(sum.length);
输出
2

apply和call方法

每个函数都包含applycall方法,用来在特定的作用域中调用函数。

apply方法接收 2 个参数:一是作用域,二是传入的参数(Array 实例或者 arguments 对象);

call方法接收 1 个以上不确定参数:第一个参数依旧是作用域,其余参数全部传入函数。

JAVASCRIPT
function sum(num1, num2){ return num1 + num2; } function callSum1(num1, num2){ return sum.apply(this,[num1, num2]); } function callSum2(num1, num2){ return sum.apply(this,arguments); } function callSum3(num1, num2){ return sum.call(this,num1,num2); } console.log(callSum1(10,10)); console.log(callSum2(10,10)); console.log(callSum3(10,10));
输出
20 20 20

applycall常用来扩充函数的作用域:

JAVASCRIPT
var color = "red"; function showColor(){ console.log(this.color); } var obj = { color : "blue", }; showColor.call(this); showColor.call(window); showColor.call(obj); //showColor()中的this指向了obj
输出
red red blue
上述代码的好处是:obj对象上不用创建showColor方法,对象不需要与方法有任何耦合关系。

bind方法

此外,函数还有一个方法bind,它会创建一个函数的实例,this值会被绑定到传给bind的参数值。

JAVASCRIPT
var color = "red"; function showColor(){ console.log(this.color); } var obj = { color : "blue", }; var showColorObj = showColor.bind(obj); showColorObj();
输出
blue

基本包装类型

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

3个基本包装类型:BooleanNumberString

因为有了基本包装类型,所以 JavaScript 中的基本类型可以当做对象来访问。

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

相当于后台作了下列处理:

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

Number类型的toFixed方法,会按照指定的小数位数返回四舍五入后的值。

JAVASCRIPT
var num1 = 10; console.log(num1.toFixed(2)); var num2 = 10.005; console.log(num2.toFixed(2));
输出
10.00 10.01

String的几个常用方法:

1. 字符方法

JAVASCRIPT
var str = "hello world"; //返回给定位置的单字符的字符串 console.log(str.charAt(1)); //返回给定位置的字符编码 console.log(str.charCodeAt(1)); //返回方括号内索引位置的单字符的字符串 console.log(str[1]);
输出
e 101 e

2. 操作方法

JAVASCRIPT
var str1 = "hello"; //concat可以接收一个或多个参数来拼接返回字符串 var str = str1.concat(" ","world"); console.log(str); //截取从位置3开始到最后的字符串 console.log(str.slice(3)); //截取从位置3开始到位置7结束的字符串,注意不包含位置7 console.log(str.slice(3,7)); //同slice() console.log(str.substring(3)); //同slice() console.log(str.substring(3,7)); //截取从位置3开始到最后的字符串 console.log(str.substr(3)); //截取从位置3开始的长度为7的字符串 console.log(str.substr(3,7));
输出
hello world lo world lo w lo world lo w lo world lo worl

3. 位置方法

JAVASCRIPT
var str = "hello world"; //搜索不到的子字符串,则返回-1 console.log(str.indexOf("a")); //从左往右查找的第一个子字符串位置 console.log(str.indexOf("o")); //从右往左查找的第一个子字符串位置 console.log(str.lastIndexOf("o")); //从指定位置开始往右查找的第一个子字符串位置 console.log(str.indexOf("o",5)); //从指定位置开始往左查找的第一个子字符串位置 console.log(str.lastIndexOf("o",5));
输出
-1 4 7 7 4

在使用第二个参数的情况下,可以通过循环调用indexOflastIndexOf来找到所有匹配的子字符串。

JAVASCRIPT
var str = "hello world"; var positions = new Array(); var pos = str.indexOf("o"); while(pos > -1){ positions.push(pos); pos = str.indexOf("o", pos + 1); //从找到的子字符串的下一个位置开始,再次寻找 } console.log(positions.toString());
输出
4,7

4. trim()方法

JAVASCRIPT
var str1 = " hello world "; var str = str1.trim(); //会删除前面和后面的全部空格 console.log(str);
输出
hello world

5. 大小写转换方法

JAVASCRIPT
var str = "hello world"; console.log(str.toUpperCase()); //转为大写 console.log(str.toLocaleUpperCase()); //针对特殊地区作了处理的大写转换 console.log(str.toLowerCase()); //转为小写 console.log(str.toLocaleLowerCase()); //针对特殊地区作了处理的小写转换
输出
HELLO WORLD HELLO WORLD hello world hello world

单体内置对象

Global对象

内置对象是指由 ECMAScript 提供的、不依赖于宿主环境的对象,不必显式地实例化它们。ObjectArrayStringGlobalMath等都是内置对象。

在全局作用域中定义的所有属性和函数,其实都是Global对象的属性和函数。

Global对象的encodeURIencodeURIComponent方法可以对 URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以使浏览器能够理解。

其中encodeURI不会对诸如":"、"/"、"?"、"#"等本身属于URI 的特殊字符编码,而encodeURIComponent会对所有字符进行编码。

JAVASCRIPT
var uri = "http://www.abc.com/illegal value.html#start"; console.log(encodeURI(uri)); console.log(encodeURIComponent(uri));
输出
http://www.abc.com/illegal%20value.html#start http%3A%2F%2Fwww.abc.com%2Fillegal%20value.html%23start

对应的2个解码方法是decodeURIdecodeURIComponent,其中decodeURI只能对使用encodeURI替换的字符进行解码,而decodeURIComponent能够解码任意特殊字符。

JAVASCRIPT
var uri = "http%3A%2F%2Fwww.abc.com%2Fillegal%20value.html%23start "; console.log(decodeURI(uri)); console.log(decodeURIComponent(uri));
输出
http%3A%2F%2Fwww.abc.com%2Fillegal value.html%23start http://www.abc.com/illegal value.html#start

eval函数可以接收一个字符串参数,并把它当做实际的ECMAScript 语句来解析。

JAVASCRIPT
eval("function Hi(){console.log(\"Hi!\");}"); Hi();
输出
Hi!

获取Global对象的 2 种方式:

  1. web 浏览器将Global对象作为window对象的一部分加以实现,可以用window来访问全局作用域中声明的变量和函数。
JAVASCRIPT
var color = "red"; function sayColor(){ console.log(window.color); } window.sayColor();
输出
red
  1. 返回全局this对象。
JAVASCRIPT
//定义global对象,注意最后的括号,有括号代表函数的执行 var global = function(){ return this; }(); var color = "red"; function sayColor(){ console.log(global.color); } global.sayColor();

Math对象

Math对象的一些常用方法:

minmax可以接收任意多个参数,并返回最小和最大的值。如果要对用于数组,可以使用函数的apply方法。

JAVASCRIPT
var nums = [1,2,3,4,5]; console.log(Math.max(1,2,3,4,5)); //console.log(Math.max(nums)); //错误!不可以直接传递数组作为参数 console.log(Math.max.apply(Math,nums)); //Math对象作为作用域,数组作为第二个参数
输出
5 5

几个舍入方法:Math.ceil向上舍入,Math.floor向下舍入,Math.round四舍五入。

JAVASCRIPT
console.log(Math.ceil(25.1)); console.log(Math.ceil(25.9)); console.log(Math.floor(25.1)); console.log(Math.floor(25.9)); console.log(Math.round(25.1)); console.log(Math.round(25.9));
输出
26 26 25 25 25 26

Math.random会返回一个介于 0 和 1 之间的随机小数,不包括 0 和 1。下面的公式可以从某个整数范围内随机选择一个值:

值 = Math.floor(Math.random() * 一共多少个可能值 + 第1个可能值)

一个通用的返回一定范围内随机整数的函数:

JAVASCRIPT
//返回2个值之间的随机数 function randomFrom(lowerValue,upperValue){ var choices = upperValue - lowerValue + 1; return Math.floor(Math.random() * choices + lowerValue); } console.log(randomFrom(2,10));

使用场景示例——返回数组中的随机对象:

JAVASCRIPT
var colors = ["red","yellow","blue","green","white"]; var color = colors[randomFrom(0,colors.length - 1)]; console.log(color);
【END】

本文链接:

版权声明:本博客所有文章除声明转载外,均采用 BY-NC-SA 3.0 许可协议。转载请注明来自 iBlog

阅读 949 | 发布于 2015-09-13
暂无评论