JavaScript高级程序设计---学习笔记(一)

时间:2023-01-26 11:05:32

今天,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 的定义是:连接两个或更多的数组,并返回结果。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
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);//随机产生数组中包含的任一字符串