javascript高级程序设计-第五章(续)

没有一节一节写的很详细,就总结一些常用的,给自己或者也一起在学习的朋友一起过过眼瘾,一起理理,喜欢的朋友可以点赞关注哦。

Array类型
重排序方法

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

var values = [1, 2, 3, 4, 5]; 
values.reverse(); 
console.log(values); //5,4,3,2,1 

sort()方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。为了实现排序,sort()方法会调用每个数组项的 toString()转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()方法比较的也是字符串。

var values = [0, 1, 5, 10, 15]; 
values.sort(); 
console.log(values); //0,1,10,15,5

可以用比较函数做数据排序,升序:

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 

如果只想反转数组原来的顺序,使用 reverse()方法要更快一些。

操作方法

concat() 方法可以基于当前数组中的所有项创建一个新数组。如果传递给 concat()方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。

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

slice() 方法它能够基于当前数组中的一或多个项创建一个新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项但不包括结束位置的项。注意,slice()方法不会影响原始数组。

var colors = ["red", "green", "blue", "yellow", "purple"]; 
var colors2 = colors.slice(1); 
var colors3 = colors.slice(1,4); 
console.log(colors2); //[green,blue,yellow,purple]
console.log(colors3); //[green,blue,yellow]

splice() 方法很重要,可以做数组的删除、插入、替换操作。

  • 删除: 可以删除任意数量的项,只需指定 2 个参数:要删除的第一项的位置和要删除的项数。例如,splice(0,2)会删除数组中的前两项。
  • 插入: 可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。例如,splice(2,0,“red”,“green”)会从当前数组的位置 2 开始插入字符串"red"和"green"。
  • 替换: 可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如,splice (2,1,“red”,“green”)会删除当前数组位置 2 的项,然后再从位置 2 开始插入字符串
    “red"和"green”。
var colors = ["red", "green", "blue"]; 
var removed = colors.splice(0,1); // 删除第一项
console.log(colors); // [green,blue] 
console.log(removed); // [red],返回的数组中只包含一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
console.log(colors); // [green,yellow,orange,blue] 
console.log(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
console.log(colors); // [green,red,purple,orange,blue] 
console.log(removed); // [yellow],返回的数组中只包含一项
位置方法

indexOf()和 lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中,indexOf()方法从数组的开头(位置 0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回1。在比较第一个参数与数组中的每一项时,会使用全等操作符;也就是说,要求查找的项必须严格相等(就像使用===一样)。

var numbers = [1,2,3,4,5,4,3,2,1]; 
console.log(numbers.indexOf(4)); //3 
console.log(numbers.lastIndexOf(4)); //5 
console.log(numbers.indexOf(4, 4)); //5 
console.log(numbers.lastIndexOf(4, 4)); //3 
var person = { name: "Nicholas" }; 
var people = [{ name: "Nicholas" }]; 
var morePeople = [person]; 
console.log(people.indexOf(person)); //-1 
console.log(morePeople.indexOf(person)); //0 
迭代方法

ES5为数组定义了 5 个迭代方法。每个方法都接收两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象——影响 this 的值。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。根据使用的方法不同,这个函数执行后的返回值可能会也可能不会影响方法的返回值。

  • every(): 对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。
  • filter(): 对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
  • forEach(): 对数组中的每一项运行给定函数。这个方法没有返回值。
  • map(): 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • some(): 对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。

比较相似的是 every()和 some(),它们都用于查询数组中的项是否满足某个条件。对 every()来说,传入的函数必须对每一项都返回 true,这个方法才返回 true;否则,它就返回false。而 some()方法则是只要传入的函数对数组中的某一项返回 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 
var someResult = numbers.some(function(item, index, array){ 
 return (item > 2); 
}); 
console.log(someResult); //true 

filter() 函数,它利用指定的函数确定是否在返回的数组中包含某一项。例如,要返回一个所有数值都大于 2 的数组:

var numbers = [1,2,3,4,5,4,3,2,1]; 
var filterResult = numbers.filter(function(item, index, array){ 
 return (item > 2); 
}); 
console.log(filterResult); //[3,4,5,4,3] 

map() 也返回一个数组,而这个数组的每一项都是在原始数组中的对应项上运行传入函数的结果。例如,可以给数组中的每一项乘以 2,然后返回这些乘积组成的数组,如下所示。

var numbers = [1,2,3,4,5,4,3,2,1]; 
var mapResult = numbers.map(function(item, index, array){ 
 return item * 2; 
}); 
console.log(mapResult); //[2,4,6,8,10,8,6,4,2] 

forEach() 它只是对数组中的每一项运行传入的函数。这个方法没有返回值,本质上与使用 for 循环迭代数组一样。

var numbers = [1,2,3,4,5,4,3,2,1]; 
numbers.forEach(function(item, index, array){ 
 //执行某些操作 
}); 
归并方法

reduce()和 reduceRight()。这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。其中,reduce()方法从数组的第一项开始,逐个遍历到最后。而 reduceRight()则从数组的最后一项开始,向前遍历到第一项。
reduce() 方法可以执行求数组中所有值之和的操作

var values = [1,2,3,4,5]; 
var sum = values.reduce(function(prev, cur, index, array){ 
 return prev + cur; 
}); 
console.log(sum); //15 

reduceRight() 的作用类似,只不过方向相反而已。

var values = [1,2,3,4,5]; 
var sum = values.reduceRight(function(prev, cur, index, array){ 
 return prev + cur; 
}); 
console.log(sum); //15 
Function类型
没有重载

代码例子如下:

function addSomeNumber(num){ 
 return num + 100; 
} 
function addSomeNumber(num) { 
 return num + 200; 
} 
var result = addSomeNumber(100); //300 
// 以上代码和以下代码效果一样
var addSomeNumber = function (num){ 
 return num + 100; 
}; 
addSomeNumber = function (num) { 
 return num + 200; 
}; 
var result = addSomeNumber(100); //300

通过观察重写之后的代码,很容易看清楚到底是怎么回事儿——在创建第二个函数时,实际上覆盖
了引用第一个函数的变量 addSomeNumber。

函数声明与函数表达式

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

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

以上代码完全可以正常运行。因为在代码开始执行之前,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中。对代码求值时,JavaScript引擎在第一遍会声明函数并将它们放到源代码树的顶部。所以,即使声明函数的代码在调用它的代码后面,JavaScript 引擎也能把函数声明提升到顶部。如果像下面例子所示的,把上面的函数声明改为等价的函数表达式,就会在执行期间导致错误。

如下函数表达式的例子

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

以上代码之所以会在运行期间产生错误,原因在于函数位于一个初始化语句中,而不是一个函数声明。换句话说,在执行到函数所在的语句之前,变量 sum 中不会保存有对函数的引用;而且,由于第一行代码就会导致“unexpected identifier”(意外标识符)错误,实际上也不会执行到下一行。

作为值的函数

参考一下代码例子

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, "Nicholas"); 
console.log(result2); //"Hello, Nicholas" 

这里的 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; 
 } 
 }; 
} 
var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}]; 
data.sort(createComparisonFunction("name")); 
console.log(data[0].name); //Nicholas 
data.sort(createComparisonFunction("age")); 
console.log(data[0].name); //Zachary 
函数内部属性

在函数内部,有两个特殊的对象:arguments 和 this。虽然 arguments 的主要用途是保存函数参数,但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。请看下面这个非常经典的阶乘函数。

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

问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee。

function factorial(num){ 
 if (num <=1) { 
 return 1; 
 } else { 
 return num * arguments.callee(num-1) 
 } 
} 
函数属性和方法

每个函数都包含两个属性:length 和 prototype。其中,length 属性表示函数希望接收的命名参数的个数。

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

每个函数都包含两个非继承而来的方法: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]); // 传入数组
} 
console.log(callSum1(10,10)); //20 
console.log(callSum2(10,10)); //20 

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

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

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

使用场景: 传递参数并非 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 
单体内置对象
Global对象

isNaN()、isFinite()、parseInt()以及 parseFloat(),实际上全都是 Global对象的方法。除此之外,Global 对象还包含其他一些方法

  • URI 编码方法: Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如空格。而这两个 URI 编码方法就可以对 URI 进行编码,它们用特殊的 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。
  • eval()方法: eval()方法就像是一个完整的 ECMAScript 解析器,它只接受一个参数,即要执行的 ECMAScript(或 JavaScript)字符串。eval(“alert(‘hi’)”);等同于alert(“hi”); 正常情况下能够用eval实现的功能都可以用替代的方式实现(不是我说的,但是我同意) 比如JSON.parse(JSON对象解析),比如new Function()(执行特定代码)。弊端:1、性能不好 2、不安全 3、产生混乱的代码逻辑。
Math对象

与我们在 JavaScript 直接编写的计算功能相比,Math 对象提供的计算功能执行起来要快得多。Math 对象中还提供了辅助完成这些计算的属性和方法。

min()和 max()方法
var max = Math.max(3, 54, 32, 16); 
console.log(max); //54 
var min = Math.min(3, 54, 32, 16); 
console.log(min); //3 

要找到数组中的最大或最小值,可以像下面这样使用 apply()方法。(酷、这个应该会经常用到)

var values = [1, 2, 3, 4, 5, 6, 7, 8]; 
var max = Math.max.apply(Math, values); 

这个技巧的关键是把 Math 对象作为 apply()的第一个参数,从而正确地设置 this 值。然后,可
以将任何数组作为第二个参数。

舍入方法
  • Math.ceil() 执行向上舍入,即它总是将数值向上舍入为最接近的整数;
  • Math.floor() 执行向下舍入,即它总是将数值向下舍入为最接近的整数;
  • Math.round() 执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课上学到的舍入规则)。
console.log(Math.ceil(25.9)); //26 
console.log(Math.ceil(25.5)); //26 
console.log(Math.ceil(25.1)); //26 
console.log(Math.round(25.9)); //26 
console.log(Math.round(25.5)); //26 
console.log(Math.round(25.1)); //25 
 
console.log(Math.floor(25.9)); //25 
console.log(Math.floor(25.5)); //25 
console.log(Math.floor(25.1)); //25 
random()方法

Math.random()方法返回大于等于 0 小于 1 的一个随机数。对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件。套用下面的公式,就可以利用 Math.random()从某个整数范围内随机选择一个值。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值