《JavaScript高级程序设计》学习笔记(第五章)- 下
2014-11-21 17:08
288 查看
Function类型
ECMAScript中的函数实际上也是对象。每个函数都是Function类型的实例,并且与其它引用类型一样也具有属性和方法。所以,函数名称实际上也是一个指向函数对象的指针。
这也就不难理解函数的另一种定义方法,实际就是在声明一个变量:
var sum = function(num1, num2) { return num1 + num2; }
实际上,函数也能使用构造方法来定义,不过这种方法是不推荐使用的:
// 最后一个参数会被当成函数体 var sum = new Function("num1", "num2", "return num1 + num2");
没有重载(深入理解)
将函数名想象为指针,也就可以理解为什么ECMAScript当中没有函数重载的概念。function addSomeNumber(num) { return num + 100; } function addSomeNumber(num1, num2) { return num1 + 200; } var result = addSomeNumber(100); // 300 // --> 等价于 <-- var addSomeNumber = function(num) { return num + 100; } addSomeNumber = function(num1, num2) { return num1 + 200; } var result = addSomeNumber(100); // 300
可以看到,当声明两个同名函数时,实际上是第一个函数的变量被后面的所覆盖了,也就无法构成重载。
函数声明与函数表达式
在解析器向执行环境加载数据时,对待函数声明和函数表达式是有区别的。解析器会率先读取函数声明,并使其可以在执行任何代码之前可用,而对于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被执行。// 运行正确 alert(sum(10,10)); function sum(num1, num2){ return num1 + num2; } // 运行出错 alert(sum(10,10)); var sum = function(num1, num2){ return num1 + num2; };
由于第一段代码使用了函数声明,所以解析器会在运行代码之前将其添加到执行环境中,所以可以正确运行。而第二段代码因为是函数表达式,所以在执行第一句的时候,实际上
sum函数还未被定义,导致运行出错。
作为值的函数
因为ECMAScript当中的函数名本身就是变量,所以函数也可以被当成参数来使用,也可以作为返回值从一个函数中返回。函数内部属性
在函数的内部,有两个特殊的属性:arguments和
this,这两个属性本身也都是引用类型。
arguments除了保存函数参数的作用,还有一个
callee的属性,该属性是一个指针,指向拥有这个
arguments对象的函数。
function factorial(num){ if (num <=1) { return 1; } else { return num * factorial(num-1) } } // <-- 等价于 --> function factorial(num){ if (num <=1) { return 1; } else { return num * arguments.callee(num-1) } }
this引用的是执行该函数的环境对象。
window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } sayColor(); //"red" o.sayColor = sayColor; o.sayColor(); //"blue"
当在全局作用域中调用函数时,
this引用的是全局对象
window。而使用对象调用时,则
this指向的是该对象本身。
关于
this以后还会进行详细的讨论。
ECMAScript 5中还定义了另一个函数属性的对象:
caller,这个属性保存了调用当前函数的函数的引用,如果是在全局使用域内,则它的值为
null。
函数属性和方法
因为函数也是对象,所以函数也有属性和方法。每个函数都有两个属性:length和
prototype。
length表示函数希望接收的命名参数的个数。
function sayName(name){ alert(name); } function sum(num1, num2){ return num1 + num2; } function sayHi(){ alert("hi"); } alert(sayName.length); //1 alert(sum.length); //2 alert(sayHi.length); //0
prototype是ECMAScript中面向对象一个十分重要的属性,关于这个属性之后会更加详细地讨论。
除了上面两个属性,每个函数还有两个非继承而来的方法:
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
call()方法与
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
ECMAScript 5还定义了一个
bind()方法,这个方法会创建一个函数的实例,其
this值会被绑定到传给
bind()函数的值。
window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } var objectSayColor = sayColor.bind(o); objectSayColor(); //blue
而对于
toString()、
toLocaleString()和
valueOf()方法,都会返回函数的代码。
基本包装类型
我们之前说过,只有引用类型的数据才能添加属性,但是我们却经常对字符串调用各种方法。这是怎么回事呢?实际上,每当我们读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而我们能够调用一些方法来操作这些数据。基本包装类型只存在于一行代码的执行瞬间,然后立即被销毁。这也就解释了为什么我们不能为基本类型添加属性和方法,因为对基本包装类型添加的属性,在下一行代码执行的时候就被销毁了。
我们应该避免显式地创建基本包装类型对象。
Boolean类型
Boolean类型是与布尔值对应的引用类型。
Boolean类型的实例重写了
valueOf()方法,返回基本类型值的
true或
false。重写了
toString()方法,返回字符串
true和
false。
Number类型
Number是与数字值对应的引用类型。
Number的
valueOf()方法也会返回基本类型的数值,而
toString()和
toLocaleString()方法会返回数值对应的字符串。
Number类型还提供了一些用于数值格式化为字符串的方法。
toFixed()方法会按照指定的小数返回数值的字符串表示:
var num = 10; alert(num.toFixed(2)); //"10.00"
toExponential()方法会返回以指数表示法表示的数值的字符串形式。
var num = 10; alert(num.toExponential(1)); //"1.0e+1"
对于一个数值来说,
toPrecision()方法可能会返回固定大小(fixed)格式,也可能返回指数格式(exponential),具体看哪种格式最合适。
var num = 99; alert(num.toPrecision(1)); //"1e+2" alert(num.toPrecision(2)); //"99" alert(num.toPrecision(3)); //"99.0"
String类型
String类型是字符串的对象包装类型。对于
String类型的对象,三个继承的方法都直接返回对象所表示的基本字符串值。
String类型每个实例都有一个
length属性,表示字符串中的字符个数。要注意的是,即使字符串中包含双字节字符,每个字符也仍然算一个字符。
String类型提供了很多方法,以提供字符串的操作和解析。
字符方法
charAt()和
charCodeAt()用于访问字符串中的特定字符。这两个方法都接收一个参数,即基于0的字符位置。
charAt()以字符形式返回给定位置的字符,而
charCodeAt()会以字符编码的形式返回。
var stringValue = "hello world"; alert(stringValue.charAt(1)); //"e" alert(stringValue.charCodeAt(1)); // 输出"101"
在ECMAScript 5当中,还可以使用方括号加数字索引来访问字符串,与数组的取值方法类似。
字符串操作方法
concat()方法用于将一或多个字符串拼接起来,返回拼接得到的新字符串。
var stringValue = "hello "; var result = stringValue.concat("world", "!"); alert(result); //"hello world!" alert(stringValue); //"hello"
实际上,在大多数情况下,字符串拼接使用更多的还是加号操作符(+)。
ECMAScript还提供了三个用于获取子字符串的方法:
slice()、
substr()和
substring()。这三个方法可以接受一个或两个参数,第一个参数为指定开始位置,对于
slice()和
substring(),第二个参数是指定子字符串的结束位置,而
substr()的第二个参数则是指定字符的个数。
var stringValue = "hello world"; alert(stringValue.slice(3)); //"lo world" alert(stringValue.substring(3)); //"lo world" alert(stringValue.substr(3)); //"lo world" alert(stringValue.slice(3, 7)); //"lo w" alert(stringValue.substring(3,7)); //"lo w" alert(stringValue.substr(3, 7)); //"lo worl"
在传递参数为负值的情况下,slice() 方法会将传入的负值与字符串的长度相加, substr() 方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为 0。最后, substring() 方法会把所有负值参数都转换为 0。
var stringValue = "hello world"; alert(stringValue.slice(-3)); //"rld" alert(stringValue.substring(-3)); //"hello world" alert(stringValue.substr(-3)); //"rld" alert(stringValue.slice(3, -4)); //"lo w" alert(stringValue.substring(3, -4)); //"hel" alert(stringValue.substr(3, -4)); //"" (空字符串)
字符串位置方法
indexOf()和
lastIndexOf()可以用于从字符串中查找子字符串,并返回子字符串的位置(如果没有找到,则返回-1)。两个方法区别只在于搜索的起始位置。并且两个方法都可以接受第二个参数,用于指定从哪个位置可以搜索。
trim()方法
ECMAScript 5为所有字符串字义了trim()方法。这个方法会创建一个字符串副本,删除前置和后缀的所有空格,然后返回结果。
var stringValue = " hello world "; var trimmedStringValue = stringValue.trim(); alert(stringValue); //" hello world " alert(trimmedStringValue); //"hello world"
字符串大小写转换方法
toLowerCase()、
toLocalceLowerCase()、
toUpperCase()和
toLocaleUpperCase()用于转换字符串的大小写。
字符串模式匹配方法
String类型定义了几个用于在字符串中匹配模式的方法。
match()与
RegExp的
exec()方法本质上是一样的。
match()方法接收一个参数,要么是正则字面量,或一个
RegExp对象。
var text = "cat, bat, sat, fat"; var pattern = /.at/; //与 pattern.exec(text)相同 var matches = text.match(pattern); alert(matches.index); //0 alert(matches[0]); //"cat" alert(pattern.lastIndex); //0
search()方法用于在字符串中查找符合特定模式的子字符串,并返回子字符串的位置,它接收的参数与
match()一样。
var text = "cat, bat, sat, fat"; var pos = text.search(/at/); alert(pos); //1
String类型还提供了一个用于替换子字符串。这个方法可以接收两个参数:第一个参数可以是一个RegExp对象或者一个字符串(不会被转换为正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,则只会替换第一个匹配的子字符串。
var text = "cat, bat, sat, fat"; var result = text.replace("at", "ond"); alert(result); //"cond, bat, sat, fat" result = text.replace(/at/g, "ond"); alert(result); //"cond, bond, sond, fond"
第二个参数如果指定一个函数,传递给函数的参数依次是模式的匹配项、各个捕获组的匹配项、匹配项的位置和原始字符串。
最后一个与模式匹配有关的方法是
split(),这个方法可以基本指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符可以是一个字符串(不会被转化为正则表达式),也可以是一个
RegExp对象。这个方法也可以接收第二个参数,用于指定数组的大小。
var colorText = "red,blue,green,yellow"; var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"] var colors2 = colorText.split(",", 2); //["red", "blue"] var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""]
localeCompare()方法
这个方法比较两个字符串,根据字符编码进行比较返回正数、负数或者0。fromCharCode()方法
String构造函数本身还有一个静态方法:
fromCharCode(),这个方法接收一个或多个字符编码,然后将它们转换成一个字符串。
alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
单体内置对象
除了上面介绍的内置对象,ECMA-262还定义了两个单体内置对象:Global和
Math。
Global对象
所以在全局作用域中定义的属性和函数,都是Global对象的属性。在web浏览器当中,这个对象被当作window对象的一部分来实现。Global对象还包含其他一些方法:
URI编码方法
encodeURI()和
encodeURIComponent()方法可以对URI进行编码,它们会以UTF-8编码替换掉无效的字符。其中,
encodeURI()用于整个URI,而
encodeURIComponent()只用于URI中某一段进行编码。与其对应的两个方法是
decodeURI()和
decodeURIComponent()。
eval()方法
eval()方法可以将传入的字符串当作ECMAScript语句来执行。通过
eval()执行的代码被认为是包含该次调用的执行环境的一部分,因为被执行的代码具有与该执行环境相同的作用域链。
eval("function sayHi() { alert('hi'); }"); sayHi(); eval("var msg = 'hello world'; "); alert(msg); //"hello world"
Math对象
ECMAScript对保存数学公式和信息提供了一个公共位置,即Math对象。Math对象的属性
Math对象包含的属性大都是数学中可能用到的特殊值:属性 | 说明 |
---|---|
Math.E | 自然对数的底数,即常量 e 的值 |
Math.LN10 | 10的自然对数 |
Math.LN2 | 2的自然对数 |
Math.LOG2E | 以2为底 e 的对数 |
Math.LOG10E | 以10为底 e 的对数 |
Math.PI | π的值 |
Math.SQRT1_2 | 1/2的平方根(即2的平方根的倒数) |
Math.SQRT2 | 2的平方根 |
min()和max()方法
这两个方法可以接收任意多个数值参数,并返回所有值的最大值或最小值。var max = Math.max(3, 54, 32, 16); alert(max); //54 var min = Math.min(3, 54, 32, 16); alert(min); //3
舍入方法
Math.ceil()向上取整,
Math.floor()向下取整,
Math.round()执行四舍五入方法。
alert(Math.ceil(25.9)); //26 alert(Math.ceil(25.5)); //26 alert(Math.ceil(25.1)); //26 alert(Math.round(25.9)); //26 alert(Math.round(25.5)); //26 alert(Math.round(25.1)); //25 alert(Math.floor(25.9)); //25 alert(Math.floor(25.5)); //25 alert(Math.floor(25.1)); //25
random()方法
Math.random()方法返回大于等于0小于1的一个随机数。可以利用这个方法从某个整数范围内随机选择一个值。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值) // 通用函数 function selectFrom(lowerValue, upperValue) { var choices = upperValue - lowerValue + 1; return Math.floor(Math.random() * choices + lowerValue); }
其他方法
Math对象中还包含了其他一些与计算相关的方法,在此就不详细记录,遇到的时候再查阅资料就可以了。
相关文章推荐
- 《Spring实战》学习笔记-第五章:构建Spring web应用
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(4)
- 《Java 学习笔记》 第五章阅读体验
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(5)
- 《机器学习实战》学习笔记之第五章—— Logistic回归
- 《深入理解Android内核设计思想》学习笔记:第五章 Android进程、线程管理
- 《COM原理及应用》学习笔记之第五章
- 《c++ primer》学习笔记 第五章 表达式
- 《JAVA编程思想》学习笔记——第五章 初始化与清理
- 《Python自然语言处理》学习笔记-第五章
- 《Thinking in Java》学习笔记——第五章:隐藏实施过程
- 《计算机系统要素》学习笔记:第五章计算机体系结构
- 《Mongodb权威指南》学习笔记 第五章 索引
- 《C++大学教程》学习笔记 第五章:控制语句(第二部分)
- 《JavaScript高级程序设计》学习笔记(第五章)- 上
- 学习笔记--第五章神经网络
- 《深入java虚拟机》学习笔记(第五章 java虚拟机)
- 《Mongodb权威指南》学习笔记 第五章 索引
- 《Spring实战》学习笔记-第五章:构建Spring web应用
- 《COM原理及应用》学习笔记之第五章