5.5Function 类型
函数实际上是对象,而函数名实际上是一个指向函数(对象)的指针,所以一个函数其实可以有多个函数名
函数定义
函数定义一般使用函数声明语法定义
function sum(num1,num2){
return num1 + num2;
}
console.log(sum(10,10)); //20
也可使用函数表达式定义函数,但要记得加;
var sum = function(num1 + num2){
return num1 + num2;
}; //相当于定义一个变量并赋值,所以要加;
不推荐使用Function构造函数(这种语法会导致解析两次代码,一次解析常规的ECMAScript代码,一次解析传入的字符串)
函数名相当于一个指向函数(对象)的指针,函数名改变不影响函数
function sum(num1,num2){
return num1 + num2;
}
var sum1 = sum;
console.log(sum1(10,10)); //20
sum = null; //改变sum的值,使其为空值
console.log(sum1(10,10)); //20,sum的改变不会影响函数,此时他与函数已无关联
console.log(sum(10,10)); //会报错,因为sum此时已经不是函数了
5.51 没有重载(深入理解)
ECMAScript中的函数没有重载概念
先后声明两个同名函数,后面的函数会覆盖先前的函数
function addNum(num){
return num + 10;
}
function addNum(num){
return num + 20;
}
console.log(addNum(10)); //30
5.52函数声明与函数表达式
在代码被编译时,函数声明的函数有一个函数声明提升的过程,函数表达式没有
函数声明提升:对代码求值时,js引擎在第一遍会声明函数并将它们放到源代码树的顶部,所以即使声明函数在使用函数代码的后面,也可以吧声明函数提升到前面
console.log(addNum(10)); //30
function addNum(num){
return num + 10;
}
函数表达式定义的函数只能将函数声明放在函数使用前面
console.log(addNum(10)); //报错:addNum is not a function
var addNum = function(num){
return num + 10;
};
5.53作为值的函数
可像传递参数一样将一个函数传递给另一个函数,也可将一个函数作为另一个函数的结果返回
传递函数的指针
function callSomeFunction(someFunction,someArgument){
return someFunction(someArgument);
}
function addTen(num){
return num + 10;
}
var result1 = callSomeFunction(addTen,10);
console.log(result1); //20
函数callFunction的第一个参数其实只是someFunction的函数名,并不是函数,若是函数的话那也不能将someFunction的参数改为someArgument了,也就失去了意义
5.54 函数内部属性
arguments对象
它是个类数组对象,包含着传入函数的所有参数。
它还有个名叫callee的属性,该属性是个指针,指向拥有arguments这个对象的函数。
function factorial(num){
if(num <= 1){
return num;
}else{
return num * factorial(num - 1);
}
}
这是个阶乘函数,若函数有函数名且函数名不变那倒没有问题,但是如果没有函数或者函数名改变就会出问题了,所以改为第5行代码改为以下形式即可解决
return num * arguments.callee(num - 1);
arguments对象的callee属性指向拥有对象的函数,即以上的factorial函数
this对象
函数总是指向调用函数的那个对象(自己写的)
caller函数对象属性
ES5规范的。
这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null
function outer(){
inner();
}
function inner(){
console.log(inner.caller); //function outer(){
} // inner();
outer(); //}
console.log()出了outer函数的源代码
为使得更松散的耦合,可以使用前面提到的arguments.callee代替函数名
console.log(arguments.callee.caller);
5.55函数属性和方法
length属性
函数希望接收的命名参数的个数,例如sum(num1,num2)的length就是2
prototype属性
非常重要,第六章详细介绍
apply()方法
apply()接收两个参数:作用域(this),参数数组(arguments)
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
相当于就是把另一个对象的属性拿来自己用
可以这样说
方法.apply(作用域,数组); //就是把一个方法在某个作用域下拿来作用到数组上
function Person(name,age){
this.name=name;
this.age=age;
}
/*定义一个学生类*/
function Student(name,age,grade) {
Person.apply(this,arguments);
this.grade=grade;
}
//创建一个学生类
var student=new Student("zhangsan",21,"一年级"); //使用函数给变量赋值时要使用new关键字
//测试
alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
上述例子就是用 Person.apply(this,arguments); 将Person里的name,age属性拿来给Student用
call()方法
用途大致一样,只是接受参数改了,第一个还是this,其余参数全部传给调用的函数,
借鉴连接
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
前三个无论是直接运行函数,还是用call()方法取this,window,都是在全局作用域上,而最后一个引用对象o,将作用域扩充到了对象o上。
用apply(),call()扩充作用域的好处是对象不需要与方法有任何耦合关系
bind()方法
这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值
window.color = "red";
var o = {color:"blue"};
function sayColor(){
console.log(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
相当于创建了个新函数,等号左边是函数名,右边是原函数调用bind()方法,方法里的参数决定了原函数this指向哪个对象,决定了this的值
第六行代码等价于
var objectSayColor = function(){
console.log(o.color);
}
每个函数继承的toLocaleString()和toString()方法始终都返回函数的代码。另外一个继承的valueof()方法同样也只返回函数代码
5.6基本包装类型
5.6.1 Boolean类型(建议永远不要使用)
5.6.2 Number类型(不建议使用)
用到了再回来看这两种类型
5.6.3 String类型
String类型是字符串的对象包装类型,可用String构造函数来创建
var stringObject = new String("hello world"); //好像是在后台这样创建包装对象
String对象的方法可在所有基本的字符串值中访问到,继承的valueof()、toLocalString()和toString()方法,都返回对象所表示的基本字符串值
String类型的每个实例都有一个length属性,表示字符串中包含多少个字符。
var stringValue = "hello world";
console.log(stringValue.length); //11
a.字符方法
charAt()
接受一个参数,字符位置,返回特定字符
charCodeAt()
接受一个参数,字符位置,返回特定字符的字符编码
var stringValue = "hello world";
console.log(stringValue.charAt(1)); //e
console.log(stringValue.charCodeAt(1)); //101
ES5定义了另一个识别个别字符的方法,有点类似数组用位置调用数组内的元素
var stringValue = "hello world";
console.log(stringValue[1]); //e
b.字符串操作方法
concat()
将一个或多个字符串拼接起来,对原字符串无影响
var stringValue = "hello";
var result = stringValue.concat(" world");
var result1 = stringValue.concat(" world"," !");
console.log(result); //hello world
console.log(result1); //hello world !
其实和 + 差不多,不过实际操作中 + 用的更多些
slice(),substring(),substr()
都是由原字符串创建新的子字符串,三个方法都会接收一或两个参数,对原字符串无影响
三个方法的第一个参数都是子字符串的起始位置
slice(),substring()第二个参数都是最后一个字符后面的位置,substr()的第二个参数是返回的字符个数
var stringValue = "hello world";
console.log(stringValue.slice(2)); //llo world
console.log(stringValue.substring(2)); //llo world
console.log(stringValue.substr(2)); //llo world
console.log(stringValue.slice(2,7)); //ll0 w
console.log(stringValue.substring(2,7)); //llo w
console.log(stringValue.substr(2,7)); //llo wor
若传递给这些方法的参数是负值,slice()方法将传入的负值与字符串长度相加,substring()方法将所有负值转化为零,substr()方法将第一个负值参数与字符串长度相加,将第二个参数转化为零
var stringValue = "hello world";
console.log(stringValue.slice(-3)); //rld
console.log(stringValue.substring(-3)); //hello world
console.log(stringValue.substr(-3)); //rld
console.log(stringValue.slice(-3,-2)); //r
console.log(stringValue.substring(-3,-2)); // (空字符串)
console.log(stringValue.substr(-3,-4)); // (空字符串)
c.字符串位置方法
indexOf()从前往后查找,lastIndexOf()从后往前查找
都可接收两个参数,第一个参数是要查找的字符,第二个参数是查找的起始位置
找到了返回该字符位置,没找到则返回-1
var stringValue = "hello world";
console.log(stringValue.indexOf("o")); //4
console.log(stringValue.lastIndexOf("o")); //7
console.log(stringValue.indexOf("o",6)); //7
console.log(stringValue.lastIndexOf("o",6)); //4
可以运用循环加上这两种方法遍历将特定字符的位置全弄出来
var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
var positions = new Array();
var pos = stringValue.indexOf("e");
while(pos > -1){
positions.push(pos); //将新得到的pos从数组尾部添加进数组
pos = stringValue.indexOf("e",pos + 1);
}
console.log(positions); //[3,24,32,35,52]
不能用for,用for将每个位置当作起始位置查找效率太低,也不能用do{}while(),要考虑一开始就查找不到指定字符的情况
d.trim()方法
ES5定义的方法,创建一个字符串副本,删除前置和后缀的所有空格,然后返回结果。可用来对拥有较多无用空格字符串的改善
e.字符串大小写转换方法
toLowerCase() 将字符串中字符全转换为小写字符
toUpperCase() 将字符串中字符全转换为大写字符
toLocalLowerCase() 针对部分少数语言,将字符串中字符全转换为小写字符
toLocalUpperCase() 针对部分少数语言,将字符串中字符全转换为大写字符
在不知道代码将在哪种语言环境中运行的情况下,使用针对地区的方法更稳妥一些
f.字符串的模式匹配方法
match()方法
match()方法本质上与调用RegExp的exec()方法相同,返回匹配项的数组
只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象
var text = "cat,hat,fat";
var pattern1 = /.at/;
var pattern2 = /.at/g;
var result1 = text.match(pattern1);
var result2 = text.match(pattern2);
console.log(result1); //["cat"]
console.log(result2); //["cat","hat","fat"]
console.log(result1.index); //0 匹配项在数组中的位置
console.log(result2.index); //undefined
search()方法
接收一个参数,要么是一个正则表达式,要么是一个RegExp对象
返回第一个匹配项的位置,没找到匹配项则返回-1
var text = "cat,bat,sat";
var pos = text.serch(/at/);
console.log(pos); //1
replace()方法
接受两个参数,第一个是要被替换的字符串或者正则表达式,第二个参数是要替换上去的字符串或者是一个函数
var text = "cat,hat,fat";
var result1 = text.replace("at","xx");
var result2 = text.replace(/at/g,"xx");
console.log(result1); //cxx,hat,fat
console.log(result2); //cxx,hxx,fxx
第一个参数是字符串则只能替代第一个匹配项,若需要替代所有匹配项,则需要用正则表达式,且是g模式,注意正则表达式不需要加引号
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
如果第二个参数是字符串,那么还可以使用一些特殊的字符序列,将正则表达式得到的值插入到结果字符串中
字符序列 | 替换文本 |
---|---|
$$ | $ |
$& | 匹配整个模式的字符串 |
$’ | 匹配的字符串之前的子字符串 |
$` | 匹配的字符串之后的子字符串 |
$n | 匹配第n(0~9)个捕获组的子字符串,若正则表达式未定义捕获组,则使用空字符串($n) |
$nn | 匹配第nn(0~99)个捕获组的字符串 |
var text = "cat,hat,fat";
var result1 = text.replace(/(.at)/g,"world($1)");
var result2 = text.replace(/.at/g,"world($1)");
console.log(result1); //world(cat),world(hat),world(fat)
console.log(result2); //world($1),world($1),world($1)
split()方法
基于指定的分割符将一个字符串分割成多个字符串,并将结果放在一个数组中
接受的第一个参数是分隔符,可接受第二个参数,用于指定数组的大小
var text = "cat,hat,fat,nat";
var text1 = text.split(",");
var text2 = text.split(",",2);
console.log(text1); //["cat","hat","fat","nat"]
console.log(text2); //["cat","hat"]
g. localeCompare()方法
比较两个字符串,并返回一个值
字符串和字符串参数的比较 | 返回的值 |
---|---|
字符串首字母在字符串参数首字母之前 | 负数(大多数是-1) |
字符串等于字符串参数 | 0 |
字符串首字母在字符串参数首字母之后 | 正数(大多数是1) |
var text = "lili";
var text1 = "zizi";
var text2 = "lili";
var text3 = "aiai";
console.log(text.localeCompare(text1)); //-1
console.log(text.localeCompare(text2)); //0
console.log(text.localeCompare(text3)); //1
可以创建一个比较两字符串的函数
var stringValue = "yellow";
function determinOrderValue(value){
var result = stringValue.localeCompare(value);
if(result < 0){
console.log(stringValue + " is before than " + value);
}else if(result > 0){
console.log(stringValue + " is after than " + value);
}else{
console.log(stringValue + " is equal than " + value);
}
}
determinOrderValue("aaaa"); //yellow is after than aaaa
determinOrderValue("yellow"); //yellow is equal than yellow
determinOrderValue("zzzzz"); //yellow is before than zzzzz
h. fromCharCode()方法
接受一或多个字符编码,将其转化为一个字符串
console.log(String.fromCharCode(104,101,108,108.111)); //hello
5.7单体内置对象
由ECMAScript实现提供的,不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了
开发人员不需要实例化内置对象,因为他们已经实例化了
Object,Array,String就是内置对象,还有两个单体内置对象:Global和Math
5.7.1 Global对象
不属于任何其他对象的属性和方法,最终都是Global对象的属性和方法
所有在全局作用域中定义的属性和函数,都是Global对象的属性
1.URI编码方法(没看懂,回来再看)
什么是URI
encodeURI()和encodeURIComponent()可以对URI进行编码,以便发送给浏览器
encodeURI()不会对本身属于URI的特殊字符进行编码
2. eval()方法
只接受一个参数,要执行的ECMAScript或js字符串
调用eval()方法时,会将传入的参数当作实际的ECMAScript语句来解析,然后把执行结果放到原位置
eval()执行的代码可以引用在包含环境中定义的变量,函数
var msg = "hello world";
eval("console.log(msg);");
但是在eval()中创建的任何变量或函数都不会被提升,只有先定义再引用才可以
eval("console.log(msg);"); //报错
var msg = "hello world";
console.log(msg); //undefined
var msg = "hello world";
在严格模式下为eval赋值也会导致错误
5.7.2 Math对象
保存数学公式和信息的公共位置
1.Math对象的属性
部分常用属性
属性 | 说明 |
---|---|
Math.E | 自然对数的底数,常量e的值 |
Math.LN10 | ln10,(其他对数都可这样推) |
Math.LOG2E | 以2为底e的对数 |
Math.PI | Π的值 |
Math.SQRT1_2 | 1/2的平方根 |
Math.SQRT2 | 2的平方根 |
2.min()和max()方法
确定一组数的最小值和最大值
var max = Math.max(3,8,7,6);
var min = Math.min(3,8,7,6);
console.log(max,min); //8 3
确定一个数组的中数字的最大值
var values = [1,2,3,4,5,6];
var max = Math.max.apply(Math,values);
console.log(max); //6
用了apply()方法,忘了apply()方法就点这里,Math.max()方法是确定一组数的最大值,Math是总的作用域,values是要执行方法的数组,所以就是在Math作用域内将Math.max()方法作用到values这个数组上
(未完待续)
3.舍入方法
Math.ceil() 总是将小数向上舍入为最接近的整数
Math.floor() 总是将小数向下舍入为最接近的整数
Math.round() 对小数四舍五入
console.log(Math.ceil(25.1),Math.ceil(25.5),Math.ceil(25.9)); //26,26,26
console.log(Math.floor(25.1),Math.floor(25.5),Math.floor(25.9)); //25,25,25
console.log(Math.round(25.1),Math.round(25.5),Math.round(25.9)); //25,26,26
4.random方法
Math.random()方法返回大于0,小于1的一个随机数
从某个整数范围内随机选取一个值
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值);
随机取1到50中任意整数,取50个这样的整数
for(var i = 1;i <= 50;i++){
var num = Math.floor(Math.random() * 50 + 1);
console.log(num);
}
创建一个随机从某数到某数之间取整数的函数,并且用这个函数来随机取一个数组的一项
function selectNum(lowerNum,upperNum){
var num = upperNum - lowerNum + 1; //计算可能取到的值的个数
return Math.floor(Math.random() * num + lowerNum);
}
var colors = ["red","black","white","green","pink","yellow"];
var selectColor = colors[selectNum(0,colors.length - 1)]; //调用selectNum函数确定随机取得selectColor的位置
console.log(selectColor);
5.其他方法
方法 | 说明 | 方法 | 说明 |
---|---|---|---|
Math.abs(num) | num的绝对值 | Math.asin(x) | x的反正弦值 |
Math.exp(num) | Math.E的num次幂 | Math.atan(x) | x的反正切值 |
Math.log(num) | num的自然对数 | Math.asin2(y,x) | y/x的反正切值 |
Math.pow(num,power) | num的power次幂 | Math.cos(x) | x的弦值 |
Math.sqrt(num) | num的平方根 | Math.sin(x) | x的正弦值 |
Math.acos(x) | num的反余弦值 | Math.tan(x) | x的正切值 |