《javascript高级程序设计》读书笔记(四)

发现一个问题,工作一段时间,再一次啃这本红宝书的时候,果然又会是另一种滋味。果然网友们说的没错,这是一本可以反复啃的宝典~

今日份,从date类型开始哟~~

date类型

var now = new Date(); //不传参数时,自动获取当前日期和时间
如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数。
ECMAScript提供了两个方法:Date.parse()和Date.UTC().
Date.parse()接收一个表示日期的字符串参数,然后尝试返回相应日期的毫秒数。如果传入的不能表示日期,返回NaN。
直接将表示日期的字符串传递给Date构造函数,同样也会在后台调用Date.parse()。
Date.UTC()方法同样返回表示日期的毫秒数,不同的是Date.UTC()参数分别是年份,基于0 的月份(一月是0,二月是1),月日等等。年和月两个参数是必须的。
Date.now()返回表示调用这个方法时的日期和时间的毫秒数。

var someDate=Date.parse("May 25, 2004")       //1085414400000   相应日期的毫秒数
var someDate1 = new Date(Date.parse("May 25, 2004"))    //Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
var someDate4 = new Date(Date.UTC(2004,10))    //Mon Nov 01 2004 08:00:00 GMT+0800 (中国标准时间)
var start = Date.now();     //1593680521689       相应日期的毫秒数

《javascript高级程序设计》读书笔记(四)_第1张图片

正则表达式的匹配模式支持3个标志。
g:表示全局模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;
i:表示不区分大小写模式,即在确定匹配项时忽略模式与字符串的大小写;
m:表示多行模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

var parrern1 = /[bc]at/i;            //匹配第一个"bat"或"cat",不区分大小写
var parrern2 = /.at/gi;            //匹配所有以"at"结尾的三个字符串的组合,不区分大小写
var parrern3 = new RegExp("[bc]at", "i");  //与parrern1相同,只不过是使用构造函数创建的

《javascript高级程序设计》读书笔记(四)_第2张图片
左边是这些模式的字面量形式,右边是使用RegExp构造函数定义相同模式时使用的字符串

Function 类型

函数通常使用函数声明语法和函数表达式来定义:

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

var sum = function(num1, num2) {
    return num1 + num2;
}             //两个一样的效果

注意!!!使用不带圆括号的函数名是访问函数指针,而非调用函数!!函数是对象,函数名是指针

事实上,函数申明和函数表达式是有区别的,解析器在执行环境中,会率先读取函数声明,并使其在执行任何代码之前可用;至于函数表达式,则必须等到解析器执行到它所在代码行,才会真的被解释执行。

alert(sum(10,10));
function sum(num1, num2) {
    return num1 + num2;
}
//以上代码正常运行,因为执行之前,解析器已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中。
//对代码求值时,javascript引擎在第一遍会声明函数并将它们放在源代码树的顶部
//即使声明函数的代码在调用它的代码后面,也能把函数声明提升到顶部。
alert(sum(10,10));
var sum = function(num1, num2) {
    return num1 + num2;
}
//会产生错误,在执行到函数所在的语句之前,变量sum中不会保存有对函数的引用。
//unexpected identifier

在ECMAScript中函数本身就是变量,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。

function callSomeFunction(someFunction, someArgument) {
    return someFunction(someArgument);
}    //接受两个参数,第一个是函数,第二个是一个值
function add10(num) {
    return num + 10;
}
var result1 = callSomeFunction(add10, 10);
alert(result1);        //20

当然从一个函数中返回另一个函数,也是极为游泳的技术。
eg:假如有个数组,我们想要根据某个属性对数组进行排序。而传递给数组sort()方法的比较函数要接收两个参数,既要比较的值,可我们需要一种方式来指定按照哪个属性排序。
根据以上问题,我们可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数。

function creatComparisonFunction(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: "her", age: 17}, {name: "zera", age: "18"}];
data.sort(creatComparisonFunction("age"));
alert(data[0].age);         //her
data.sort(creatComparisonFunction("name"));
alert(data[0].name);         //zera

在函数内部,有两个特殊的对象:argument和this。
argument对象还有一个名叫callee的属性,是一个指针,指向拥有这个argument对象的函数。
看看这个经典的阶乘函数~~~~

function factorial(num){
    if(num <= 1){
        return 1;
    }else {
        return num * factorial(num-1);
    }
}//定义阶乘函数一般都要用到递归算法。问题是函数的执行和函数名factorial紧紧耦合在一起。不好不好~~
function factorial(num){
    if(num <= 1){
        return 1;
    }else {
        return num * argument.callee(num-1);
    }
}

再次强调,函数的名字仅仅是一个包含指针的变量而已。

当在网页的全局作用域中调用函数时,this对象引用的就是window

每个函数都包含两个属性:length和prototype。
length属性表示函数希望接收的命名参数的个数。
prototype是保存引用类型实例方法的真正所在。
每个函数都包含两个非继承而来的方法:apply()和call()。
用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
apply()方法接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组。
《javascript高级程序设计》读书笔记(四)_第3张图片
上面例子中,callSum1()在执行sum()函数时传入了this作为this值和argument对象。两个函数都会正常执行并返回正确的结果。

apply()和call()作用相同,区别仅在接受参数的方式不同。
《javascript高级程序设计》读书笔记(四)_第4张图片
在使用call()方法的情况下,callSum()必须明确地传入每一个参数,结果相同。

String类型提供了很多方法:

1、字符方法。

两个用于访问字符串中特定字符的方法:charAt()和charcodeAt().都接收一个参数,即基于0的字符位置。

var stringValue = “hello world”;
alert(stringValue.charAt(1));     //“e”
alert(stringValue.charcodeAt(1));     //属于”101”  也就是小写字母”e”的字符编码。
2、字符串操作方法

操作字符串的方法有:concat()、slice()、substr()和substring()方法。
concat()用于将一或多个字符串拼接起来,返回拼接得到的新字符串。

var stringValue = “hello ”;
var result = stringValue.concat("world");
alert(result);            //"hello world"
alert(stringValue);       //"hello"
var result1 = stringValue.concat("world","!!!");    //concat()方法可以接受任意多个参数
alert(result1);            //"hello world!!!"

虽然concat()是专门用来拼接字符串的方法,但实践中使用更多的还是加法操作符(+)。简便易行

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

3、字符串位置方法

有俩从字符串中查找子字符串的方法:indexOf()和lastIndexOf()。都是从一个字符串中搜索给定的子字符串,然后返回子字符串的位置(没找到返回子字符串,返回-1)。
区别在于:indexOf()方法从字符串的开头向后搜索,和lastIndexOf()方法从字符串的末尾向前搜索。

var stringValue = "hello world";
alert(stringValue.indexOf("o"));              //4
alert(stringValue.和lastIndexOf("o"));        //7
//这俩都可以接收可选的第二个参数,表示从字符串中哪个位置开始搜索。
alert(stringValue.indexOf("o", 6));           //7
alert(stringValue.和lastIndexOf("o", 6));     //4

还可以通过循环调用indexOf()或lastIndexOf()来找到所有匹配的子字符串。look~!

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 = stringValue.indexOf("e", pos + 1);
}
alert(positions);      //"3,24,32,35,52"

通过不断增加indexOf()方法开始查找的位置,遍历了一个长字符串,循环之外,先找到了"e"在字符串中的初始位置。

4、trim()方法

ECMAScript5为所有字符串定义了trim()方法。这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,返回结果。不改变原始字符串。

var stringValue = "    hello world       ";
var trimmedStringValue = stringValue.trim();
alert(stringValue);              //"    hello world       "     原始字符串不变
alert(trimmedStringValue);       //"hello world"   返回字符串的副本
5、字符串大小写转换方法

ECMAScript中涉及字符串大小写转换的方法有4个:toLowerCase()、toLocaleLowerCase()、toUpperCase() 和toLocaleUpperCase().

var stringValue = "hello world";
alert(stringValue.toLowerCase());               //"HELLO WORLD"
alert(stringValue.toLocaleLowerCase());         //"HELLO WORLD"
alert(stringValue.toUpperCase());               //"HELLO WORLD"
alert(stringValue.和toLocaleUpperCase());       //"HELLO WORLD"
6、字符串的模式匹配方法

String类型定义了几个用于在字符串中匹配模式的方法。
match()方法,本质与调用RegExp的exec方法相同。match()只接受一个参数,要么是正则表达式,要么是一个RegExp对象。

var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches = text.match(pattern);
alert(matchs.index);       //0
alert(matchs[0]);          //"cat"
alert(pattern.lastIndex);  //0

search()方法,参数与match()方法参数相同,由字符串或RegExp对象指定的一个正则表达式。

var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos);            //1

replace()方法,接受两个参数:第一个参数可以是一个RegExp对象或者一个字符串,第二个参数可以是一个字符串或者一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串,要想替换所有,唯一办法就是提供一个正则表达式,指定全局(g)标志。

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"

replace()方法的第二个参数也可以是一个函数。在只有一个匹配项的情况下,会向这个函数传递3个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。

function htmlEscape(text){
    return text.replace(/[<>"&]/g, function(match, pos, orginalText){
       switch(match) {
            case "<":
                return "<";
            case ">":
                return ">";
            case "&":
                return "&";
            case "\"":
                return """;
       } 
    });
}
alert(htmlEscape("

Hello world!

")); //<p class="greeting">Hello world!<p>

split()方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。可以接受可选的第二个参数,用于指定数组的大小,确保返回的数组不会超过既定的大小。

var colorText = "red,blue,green,yellow";
var color1 = colorText.split(",");           //["red","blue","green","yellow"]
var color2 = colorText.split(",", 2);        //["red", "blue"]
var color3 = colorText.split(/[^\,]+/);      //["", "", "", "", ""]
7、localeCompare()方法

与操作字符串有关的最后一个方法是localeCompare(),这个方法比较两个字符串。

var stringValue = "yellow";
alert(stringValue.localCompare("brick"));        //1
alert(stringValue.localCompare("yellow"));       //0
alert(stringValue.localCompare("zoo"));          //-1

isNaN()、isFinite()、parseInt()以及parseFloat(),实际都是Global对象的方法。除此之外,Global对象还包括其他一些方法。
eval()方法,当解析器调用eval()方法时,它会将传入的参数当作实际的ECMAScript语句来解析,然后把执行结果插入到原位置。

eval("var msg = 'hello world'; ");
alert(msg);          //"hello world"

在eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们包含在一个字符串中,它们只在eval()执行的时候创建。

在严格模式下,外部访问不到eval()中创建的任何变量或函数,为eval赋值也会导致错误。
eval能够解释代码字符串的能力非常强大,但也非常危险。因此使用必须极为谨慎。

下表列出了Global对象的所有属性
《javascript高级程序设计》读书笔记(四)_第5张图片

ECMAScript虽然没有指出如何直接访问Global对象,但web浏览器都是将这个全局对象作为window对象的一部分加以实现的。在全局作用域中声明的所有变量和函数,都成为了window对象的属性

var color = "red";
function sayColor() {
    alert(window.color);
}
window.sayColor();    //"red"

另一个取得Global对象的方法是:

var global = function() {
    return this;
}();

有没有给函数明确指定this值的情况下(无论是通过将函数添加为对象的方法,还是通过调用call()或apply()),this值等于Global对象。像这样子通过简单地返回this来取得Global对象,在任何执行环境下都是可行的。

单体内置对象还包括Math()对象。
Math()对象包含许多方法:
1、 min()和max()方法用于确定一组数值中的最小和最大值。

var num1 = Math.max(3, 54, 32, 16);
var num2 = Math.min(3, 54, 32, 16);
alert(num1);     //54
alert(num2);     //3
//下面这个技巧的关键是把Math对象作为apply()的第一个参数,从而正确地设置this值,然后可以将任何数组作为第二个参数。
var values = [1,2,3,4,5,6];
var max = Math.max.apply(Math, values);

2、 舍入方法
Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向上舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值向上舍入为最接近的整数;(这也是我们数学课学的舍入规则)

alert(Math.ceil(25.9));     //26
alert(Math.ceil(25.1));     //26

alert(Math.round(25.9));    //26
alert(Math.round(25.1));    //25

alert(Math.floor(25.9));    //25
alert(Math.floor(25.1));    //25

3、 random()方法
Math.random()方法返回介于0和1之间的一个随机数,不包括0和1。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

var num = Math.floor(Math.random() * 10 + 1);
//总共有10个可能的值(1到10),而第一个可能的值是1
//如果想要选择一个介于2到10之间的值,代码如下
var num = Math.floor(Math.random() * 9 + 2);

最后咱们总结下这篇笔记中的精华

  • Object是一个基础类型,其他所有类型都从Object继承基本的行为;
  • Array类型是一组值的有序列表,同事还提供了操作和转换这些值的功能;
  • Date类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
  • RegExp类型是ECMAScript支持正则表达式的一个接口,提供了最基本和一些高级的正则表达式功能。

函数实际上是Function类型的实例,因此函数也是对象,而这一点正是js最有特色的地方。由于函数是对象,所以也拥有方法。
因为有了基本包装类型,所以js中的基本类型值可以被当做对象来访问。
三种基本包装类型分别是:Boolean、Number和String

  • 每个包装类型都映射到同名的基本类型;
  • 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
  • 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。

在所有代码执行之前,作用域就已经存在两个内置对象:Global和Math。
大多数ECMAScript实现中不能直接访问Global对象,不过浏览器实现了承担角色的window对象。

未完待续!~

你可能感兴趣的:(javascript,前端,读书笔记)