今天,2017.3.17开始利用课余时间仔细学习《JavaScript高级程序设计》,将需要掌握的知识点记录下来,争取把书里的所有代码敲一遍并掌握。
1、标识符命名最好是第一个字母小写,剩下每个单词的首字母大写,如:firstSecond、myCar
2、var定义的变量是作用域里的局部变量,若在函数中定义,函数退出后就会被销毁
function test(){ var message = "hi"; } test(); alert(message);//错误
若在函数里定义是省略var,则会成为全局变量,但不推荐这样做,不利于维护,在严格模式下会报错
function test(){ message = "hi";//全局变量 } test(); alert(message);//"hi"
3、null值表示一个空对象指针,如果用typeof操作符检测null值时会返回object。
var car = null; alert(typeof car); //"object"
4、ECMAscript中所有函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
function setName(obj){ obj.name = "Demon"; var obj = new Object(); obj.name = "Kalus"; } var person = new Object(); setName(person); alert(person.name);//Demon } //因为参数对象是按值传递的,即使在函数内部修改了参数的值,但原始的引用仍然保持不变。 //当在这个函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。
5、为了优化内存占用,一旦数据不再使用时,最好将其值设为null来释放引用(解除引用),适用于大多数全局变量和全局变量的属性,局部变量会在它们离开执行环境时自动解除引用。
function createPerson(name){ var localPerson = new Object(); localPerson.name = name; return localPerson; } var globalPerson = createPerson("Kalus"); alert(globalPerson.name); globalPerson = null;//不需要它时手动解除,解除值的引用并不意味着自动回收该值所占用的内存,真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其收回。
6、数组中的栈方法push()和pop()
push()方法可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
pop()方法是从数组末尾移除最后一项,减小数组的length值,然后返回移除的项。
var arr = [];
var count = arr.push("red","green");
alert(count);//2
var count = arr.pop(); //取得最后一项并移除了
alert(count);//green
7、数组队列方法shift()
能够移除数组中的第一个项并返回该项,同时将数组长度减1。结合使用shift()和push()方法,可以像使用队列一样使用数组。
var arr = new Array(); var count = arr.push("red","black","green"); alert(count); var item = arr.shift(); alert(item);//red alert(arr.length); //移除了第一项后,black变为第一项,green变为第二项,长度变为2
8、数组队列方法unshift()
能在数组前端添加任意个项并返回新数组的长度。同时使用unshift()和pop()方法可以从相反方向来模拟队列。
var arr = new Array(); var count = arr.unshift("red","black"); alert(count); count = arr.unshift("orange"); alert(arr);//orange,red,black var item = arr.pop(); //取得最后一项 alert(item);//black alert(arr.length);
9、重排序方法reverse()反转数组项顺序
var values = [1,0,13,4,5]; values.reverse(); alert(values);//5,4,13,0,1
10、重排序方法sort()默认按升序排序数组项,按字符串排序,即使数组每一项都是数值。
var values = [1,0,13,4,5]; values.sort(); alert(values);//0,1,13,4,5
sort()方法可以接收一个比较函数作为参数,以便指定哪个值位于哪个值前面
一个简单的升序比较函数:
var values = [1,0,13,4,5]; values.sort(compare); alert(values);//0,1,4,5,13 function compare(value1,value2){ if(value1 < value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } }
若要产生降序的排序结果,只要交换比较函数返回值即可。
对于数值类型或者valueOf()方法会返回数值类型的对象类型,可以使用一个更简单的比较函数:
function compare(value1,value2){ return value1 - value2; }
11、操作方法concat()基于当前数组中所有项创建一个新数组。该方法会创建一个数组副本,将接收到的参数添加到数组的末尾,最后返回新构成的数组,
没有传参数时直接复制当前数组并返回副本。
var colors = ["red","black","orange"]; var colors1 = colors.concat("yellow",["brown","blue"]); alert(colors1);//red,black,orange,yellow,brown,blue
12、push()和concat()区别
push 的定义是:向数组的末尾添加一个或更多元素,并返回新的长度。该方法会改变数组的长度。
concat 的定义是:连接两个或更多的数组,并返回结果。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
var a = [1,2]; var b = [3,4,5]; var c = a.concat(b); alert(c);//1,2,3,4,5
13、操作方法slice()
接收一或两个参数,即要返回项的起始和结束位置,不影响原数组。
var colors = ["red","orange","blue","black","green"]; var colors1 = colors.slice(2); alert(colors1);//blue,black,green var colors2 = colors.slice(2,4); alert(colors2);//blue,black (不包括最后一项)
var colors3 = colors.slice(-2,-1);//black
alert(colors3);
14、操作方法splice()
1.删除:可以删除数组中任意数量的项,两个参数
如:splice(0,2)会删除数组中前两项
2.插入:向指定位置插入任意数量的项,三个参数:起始位置、0(要删除的项数)、要插入的项,如要插入多个项,可在传入任意多个项。
如:splice(2,0,"red","blue")会从当前数组的位置2开始插入两个字符串。
3.替换:向指定位置插入任意数量的项,且同时删除任意数量的项,三个参数:起始位置、要删除的项数、要插入的项 ,插入的项不必与删除的项数相等
如:splice(2,1,"red","blue")会删除当前数组位置2的项,再从位置2开始插入两个字符串
splice()方法始终都会返回一个数组,该数组包含从原数组中删除的项,没有删除返回空数组
var colors = ["red","orange","blue"]; var removed = colors.splice(0,1);// 删除一项,第一项 alert(colors);//orange,blue alert(removed);//red removed = colors.splice(1,0,"black","white"); alert(colors);//orange,black,white,blue alert(removed);//返回空数组 removed = colors.splice(1,1,"green","yellow"); alert(colors);//orange,green,yellow,white,blue alert(removed);//black
15、位置方法indexOf()和lastindexOf()
两个参数:要查找的项、查找起点位置的索引(可选)
返回要查找的项在数组中的位置,未找到返回-1,要查找的项使用全等操作符(===)
var number = [1,2,3,4,5,4,3,2,1]; alert(number.indexOf(4)); alert(number.lastIndexOf(4)); alert(number.indexOf(4,4)); alert(number.lastIndexOf(4,4)); var person = {name:"Kalus"}; var people = [{name:"Kalus"}]; var morePeople = [person]; alert(people.indexOf(person));//-1 alert(morePeople.indexOf(person));
16、迭代方法
every():对数组中每一项运行给定函数,如果该函数对每一项都返回true,则返回true
filter():对数组中每一项运行给定函数,返回该函数会返回true的数组
forEach():对数组中每一项运行给定函数,这个方法无返回值
map():对数组中每一项运行给定函数,返回每次函数调用的结果组成的数组
some():对数组中每一项运行给定函数,如果该函数对任意一项返回true,则返回true
以上方法不会修改数组中包含的值。
每个方法都接收两个参数:要在每一项上运行的函数、运行该函数的作用域对象---影响this的值(可选)
传入这些方法中的函数接收三个参数:数组项的值、该项在数组中的位置、数组对象本身
var numbers = [1,2,3,4,5,4,3,2,1]; var everyResult = numbers.every(function(item,index,array){ return (item > 2); }); alert(everyResult);//false var someResult = numbers.some(function(item,index,array){ return (item > 2); }); alert(someResult);//true var filterResult = numbers.filter(function(item,index,array){ return (item > 2); }); alert(filterResult);//3,4,5 var mapResult = numbers.map(function(item,index,array){ return (item * 2); }); alert(mapResult);//2,4,6,8,10,8,6,4,2 numbers.forEach(function(item,index,array){ //执行某些操作,没有返回值,本质上与for循环迭代数组一样 });
17、归并方法reduce()和reduceRight()
都会迭代数组的所有项,然后构建一个最终返回的值,reduce()方法从数组第一项开始,reduceRight()方法从数组最后一项开始
两个参数:在每一项上调用的函数、作为归并基础的初始值(可选)
传给reduce()和reduceRight()的函数接收4个参数:前一个值、当前值、项的索引、数组对象,
这个函数返回的任何值都会作为第一个参数自动传给下一项。
第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项(prev),第二个参数就是数组的第二项(curent)
使用reduce()方法可以执行求数值中所有值之和的操作,如:
var values = [1,2,3,4,5]; var sum = values.reduce(function(prev,cur,index,array){ return prev + cur; }); alert(sum);
第一次执行上面回调函数时,prev是1,cur是2。第二次prev是3(1加2的结果),cur是3(数组第三项)。
这个过程持续到把数组中每一项都访问一遍,最后返回结果。
reduceRight()作用类似,只不过方向相反。
18、Function类型
函数是对象,函数名实际上就是一个指向函数对象的指针。
由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没什么不同,换句话说,
一个函数可能会有多个名字。如:
function sum(num1,num2){ return num1 + num2; } alert(sum(10,10)); var anotherSum = sum;//将sum的值赋给anotherSum,注意不带圆括号的函数名是访问函数指针,而非调用函数 alert(anotherSum(10,10));//20 anotherSum和sum指向了同一函数 sum = null; alert(anotherSum(10,10));//20 即使将sum设置为null,让它与函数断绝关系,但仍然可以正常调用anotherSum()
19、ECMAScript中的函数名本身就是变量,所以函数也可以作为值来使用。
不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
function callSomeFunction(someFunction,someArgument){//第一个参数应该是一个函数,第二个参数应该是要传递给函数的值 return someFunction(someArgument); } function add(num){ return num + 10; } var result1 = callSomeFunction(add,10); alert(result1); function getGreeting(name){ return "Hello," + name; } var result2 = callSomeFunction(getGreeting,"Kalus"); alert(result2);//Hello,Kalus
从一个函数中返回另一个函数 例:
假设有一个对象数组,要根据某个对象属性对数组进行排序,而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值。
可是又需要一种方法来指明按照哪个属性进行排序,要解决这个问题就可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数。
//一个函数接受一个属性名的参数,再根据这个属性名来创建一个比较函数 function createComparisonFunction(propertyName){ return function(object1,object2){ var value1 = object1[propertyName];//内部函数接收到propretyName参数后,使用方括号表示法来取得给定属性的值 var value2 = object2[propertyName];//(用点的时候,后面需要是一个指定的属性名称,用中括号的时候 ,括号里面可以是变量或者字符串) if(value1 < value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } }; } var data = [{name: "Kalus", age: 28}, {name: "Demon", age: 29}];//定义了一个对象数组 data.sort(createComparisonFunction("name")); alert(data[0].name);//Demon data.sort(createComparisonFunction("age")); alert(data[0].name);//Kalus函数属性和方法
20、函数属性和方法
每个函数都包含两个非继承而来的方法:apply()和call(),用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
apply()方法接收两个参数:在其中运行函数的作用域、参数数组(也可以是Array的实例或arguments对象)
call()方法和apply()方法作用相同,区别在于接收参数的方式不同,对于call()方法第一个参数仍是this,变化的是其余参数都直接传递给函数
即使用call(),传递给函数的参数必须逐个列举出来。
例:
function sum(num1,num2){ return num1 + num2; } function callSum1(num1,num2){ return sum.apply(this,arguments); //传入了this作为this值(因为是在全局作用域中调用的,所以传入的就是window对象)argument对象 } function callSum2(num1,num2){ return sum.apply(this,[num1,num2]);//传入的是this和一个参数数组 } function callSum3(num1,num2){ return sum.call(this,num1,num2);//call()方法传递给函数的参数必须逐个列举出来 } alert(callSum1(10,10)); alert(callSum2(10,10)); alert(callSum3(10,10));
在使用call()方法的情况下,callSum3()必须明确地传入每一个参数,结果与apply()相同
如果参数打算传入arguments对象或者包含函数中先接收到的是一个数组,那么使用apply()更方便,否则使用call()更合适,不给函数传参的情况下两者相同。
apply()和call()方法真正强大的地方是能够扩充函数赖以运行的作用域,如:
window.color = "red"; var o = {color: "blue"}; function sayColor(){ alert(this.color); } sayColor();//red sayColor()作为全局函数定义的,在全局作用域中调用它时会显示red sayColor.call(this);//red 显示地在全局作用域中调用函数的方式 sayColor.call(window);//red 显示地在全局作用域中调用函数的方式 sayColor.call(o);//blue 函数的执行环境发生改变,此时函数体内的this对象指向了o
如果不使用call()方法,则需要先将sayColor()函数放到对象o中,然后再通过o来调用:
window.color = "red"; var o = {color: "blue"}; function sayColor(){ alert(this.color); } sayColor();//red o.sayColor = sayColor; o.sayColor();//blue
函数另一个方法: bind() 这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值,如:
window.color = "red"; var o = {color: "blue"}; function sayColor(){ alert(this.color); } var objectSayColor = sayColor.bind(o); objectSayColor();//blue objectSayColor()函数的this值等于了o
21、字符串创建新字符串的方法(相当于截取字符串):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()方法会将传入的负值与字符串的长度相加
substring()方法会把所有的负值参数都转换为0
substr()方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为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 [0,3) alert(stringValue.substr(3,-4));//"" (空字符串,因为长度变为了0)
22、字符串位置方法indexOf()和lastindexOf()
查找给定字符串,然后返回子字符串的位置索引,lastindexOf()从末尾向前查找。
都可以传递第二个参数,表示从字符串中哪个位置开始查找。
可以通过循环调用indexOf()或lastindexOf()来找到所有匹配的字符串,如:
var stringValue = "A new version of WebStorm is available!"; var positions = new Array(); var posIndex = stringValue.indexOf("e"); while(posIndex != -1){ positions.push(posIndex); posIndex = stringValue.indexOf("e",posIndex + 1); } alert(positions);//3,7,18,37
23、字符串trim()方法
会创建一个字符串副本,删除前置及后缀的所有空格,然后返回结果,原字符串不变。
此外Firefox、Safari、Chrome还支持非标准的trimLeft()和trimRight(),分别用于删除字符串开头和末尾的空格。
var stringValue = " hello world "; var trimmedStringValue = stringValue.trim(); alert(stringValue);// hello world alert(trimmedStringValue);//hello world
24、字符串localeCompare()方法
用于比较两个字符串,并返回下列值的一个:
1)如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多情况下是-1,具体的值要视实现而定)
2)如果字符串等于字符串参数,则返回0
3)如果字符串在字母表中应该排在字符串参数之前,则返回一个正数(大多情况下是1)
var stringValue = "yellow"; alert(stringValue.localeCompare("brick")); alert(stringValue.localeCompare("yellow")); alert(stringValue.localeCompare("zoo"));//-1
使用这个方法的例子:
var stringValue = "yellow"; function determineOrder(value){ var result = stringValue.localeCompare(value); if(result < 0){ alert("The string 'yellow' comes before the string '"+ value +"'."); }else if(result > 0){ alert("The string 'yellow' comes after the string '"+ value +"'."); }else{ alert("The string 'yellow' is equal to the string '"+ value +"'."); } } determineOrder("brick"); determineOrder("yellow"); determineOrder("zoo");
25、min()和max()方法
要找到数组中的最大值或最小值,可以像下面这样使用apply()方法:
把Matn对象作为apply()的第一个参数,从而正确地设置this的值,然后可以将任何数组作为第二个参数。
var values = [1,2,3,4,5,6,7,8]; var max = Math.max.apply(Math,values); alert(max);
26、random()方法
套用下面的公式,可以利用Math.random()从某个整数范围内随机选择一个值:
随机值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
如想随机选择2到10之间的数值:(2到10之间有9个数,第一个可能值为2)
var num = Math.floor(Math.random() * 9 + 2); alert(num);
多数情况下,可以通过一个函数来计算可能值的总数和第一个可能值:
selectForm()接受两个参数:应该返回的最小值和最大值,用最大值减最小值再加1得到可能值的总数。
function selectFrom(lowerValue,upperValue){ var choices = upperValue - lowerValue + 1; return Math.floor(Math.random() * choices + lowerValue); } var num = selectFrom(2,10); alert(num);//介于2和10之间(包括2和10)的一个数值
利用这个函数,可以方便地从数组中随机取出一项:
function selectFrom(lowerValue,upperValue){ var choices = upperValue - lowerValue + 1; return Math.floor(Math.random() * choices + lowerValue); } var colors = ["red","green","yellow","black","orange","purple"]; var color = colors[selectFrom(0,colors.length - 1)]; alert(color);//随机产生数组中包含的任一字符串