七天学会JavaScript~Day1
前言
一年一度的国庆长假终于来了,但是对于一名菜鸟来说,是绝对不能放过这么好的一个学习机会的,所以我打算花七天的时间把JavaScript的大体内容简单的过一遍。前端这一块呢,我几乎是一个小白。过去也只是写写Ajax,或者整几个XX事件,接收接收数据而已。所以这个国庆我是计划用七天的时间把JavaScript语言从头到尾,简单的过一遍。毕竟本人是后端开发的程序员,前端也不需要太过深入,换句话说是暂时不用太过深入。于是,前天下班的时候我就找领导借了本七百多页【JavaScript高级程序设计】的书,那么这七天的博客就是我七天的笔记。我会尽量把书中的精华总结出来。
一般情况下呢,一个后端程序员在他入职之前肯定是经历了一个学习阶段。而学习阶段肯定是学过Servlet,JSP的,不然后面的SSM什么的都没法学。而学JSP的前提也是要首先会一点HTML,CSS,JavaScript或者Jquery。所以说像这种速成的学法比较适合有一定基础的人而不是零基础。零基础如果要专门学前端的话不建议速成。
第一天的学习内容
JavaScript基本语法
垃圾收集机制
引用数据类型
Array类型
顺序栈数据结构
顺序队列数据结构
RegExp
JavaScript简介
JavaScript是诞生于1995年,很多没接触过JavaScript的人可能会认为这个语言一定和Java有关系,然而事实并不是这样。
JavaScript刚诞生的时候,主要目的还是为了处理以前由服务器端语言比如说Perl负责的一些输入验证操作。再此之前,必须把表单数据发送到服务器端才能确定用户是否没有填写某个必填域,学过JavaWeb的人一定是很容易理解这个概念的。如果说表单的每次请求都要发给后端才能验证判断是否遗漏哪些必填项的话,响应的速度肯定是会慢很多的。所以现在JavaScript也逐渐成为市面上常见浏览器的必备功能。
现如今呢,JavaScript已经变成了一个功能非常全面的编程语言,它从一个简单的输入验证器发展到现在确实非常出乎人的意料。你可以说它是一个非常简单的编程语言,也可以说它是一个非常难学的编程语言。说它简单,是因为它可以很快学会使用,但是如果要深入掌握,那就需要很多年的时间了。而我呢,是打算七天学完,所以说,我这七天也仅仅只是学会它的使用而已。如果要再深入研究底层的话应该是需要很长时间。
JavaScript基本语法
JavaScript的语法很多都借鉴了C语言或者类C语言。在JavaScript中是区分大小写的,第一个字符必须是一个字母、下划线(_)或者美元符号($)符号。注视这一块也是C语言风格的注释,可以是//也可以是。
typeof 操作符可以让用户知道变量是什么数据类型。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>网页标题</title>
<script type="text/javascript"> var flag = true; alert(typeof flag); //返回结果是 boolean </script>
</head>
<body>
</body>
</html>
NAN
NAN是英文Not a Number的缩写,从英文意思就知道是非数值。这个数值主要表示本来要返回一个数值的操作数未返回数值的情况。(这样就不会抛错误了)。就举个例子,当 9 / "hello" 的时候,返回的则是NAN。因为9是数值但是"hello"不是数值而是字符串。isNAN()函数就是用来判断一个值到底是不是数值
alert(isNaN(NaN)); //true
alert(isNaN(666)); //false
数值转换
在JavaScript里面有三个函数可以把非数值转换成数值: Number()、parseInt()、parseFloat()。第一个函数Number可以用于任何数据类型、另外两个函数就是专门给字符串用的,在Java语言里面也见过这样的方法。
使用Number转化成数值的时候,字符串必须完全是数字,否则返回NAN。使用parseInt的时候,如果第一个字符是数值那么它会判断第二个字符是不是数值。直到遇见非数值的时候,后面的就不会再判断直接返回前面的内容了。就比如num3只返回了15一个道理。
var num1 = Number("helloworld"); //NAN
var num2 = parseInt("hello"); //NAN
var num3 = parseInt("15asf96"); //15
var num4 = parseInt("4546465"); //4546465
var num5 = Number("asf45448f4sa86"); //NAN
var num6 = Number("15464"); //15464
var num7 = Number("15asfasf"); //NAN
alert(num1 + " " + num2 + " " + num3 + " " + num4 + " " + num5 + " " + num6 + " " + num7);
字符串面量
\n | 换行 |
\t | 制表 tab |
\b | 退格 |
\r | 回车 |
\\ | 斜杠 |
\' | 单引号 |
\"" | 双引号 |
\xnn | 以十六进制代码 nn 表示一个字符 |
\unnn | 以十六进制代码表示一个uniCode字符 |
for-in 语句
有点像for each
for(var propName in window){
document.write(propName);
}
with语句
with语句的作用是把代码的作用域全都设置到一个特定的对象中。下面两段代码的作用是相同的。
var str = "today is great day";
var a = str.substring(2);
var b = str.charAt(3);
alert("a = " + a + " b = " + b);
var str = "today is great day";
with(str){
var a = substring(2);
var b = charAt(3);
alert("a = " + a + " b = " + b);
}
函数
在JavaScript中函数都是统一使用function来声明。如果需要返回直接return就好了。
function my(num1,num2){
return num1 + num2;
}
var result = my(9,9);
alert("result = " + result);
没有重载
在JavaScript中,函数没有重载。假如程序员定义了两个名字相同的函数,调用的时候则会调用下面的那个。
= = 和 = = = 有什么区别?
“= = =”首先计算其操作数的值,然后比较这两个值,比较过程没有任何类型转换。相等运算符“= =”如果两个操作数不是同一类型,那么相等运算符会尝试一些类型转换,然后进行比较
var a = 1;
var b = '1';
alert(a == b); //true
alert(a === b); //false
垃圾收集
JavaScript具有自动垃圾收集机制,也就是说执行环境会负责管理代码执行过程中使用的内存。而在C和C++之类的语言中,开发人员的基本任务就是手工跟踪内存的使用情况,这样很容易造成许多问题。这个垃圾收集器的工作原理也很简单,其实就是找到那些不用的变量,然后释放掉它的内存。不需要像C++一样还要去delete。
当我们在一个函数中定义了一个局部变量,那么这个局部变量会在该函数执行的过程中存在。而这个过程中会为该局部变量在栈(或者堆)的内存上分配相应的空间以便存储他们的值。直到函数要执行结束了,这个时候局部变量就没有存在的必要,然后就会释放他们供内存使用。
标记清除
JavaScript中最常见的垃圾清理方式是标记清除。当变量进入环境的时候会将这个变量标记为进入环境,当变量要离开的时候会被标记成离开环境。垃圾收集器会在运行的时候给存储在内存中的所有变量都加上标记,然后它会去掉环境中的变量以及被环境中的变量引用的变量标记。而在此之后再被加上标记的变量就会被视为准备删除的变量,原因是环境中的变量已经无法访问这些变量了。最后垃圾收集器完成内存清除的工作。销毁那些带标记的值并收回他们所占用的内存空间。
管理内存
虽然JavaScript已经具有了垃圾收集机制,但是在内存管理和垃圾收集面临的问题还是有点与众不同。最常见的问题就是分配给Web浏览器的可用内存数量通常要比分给桌面的要少。这样做的目的主要是为了防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。所以说我们要确保占用最少的内存给浏览器最好的性能。
如果说一个数据已经不再有用了,则可以把他置为Null来释放这个引用。通常称之为解除引用。
function fun(name){
var obj = new Object();
obj.name = name;
return obj;
}
var local = fun("hello world");
alert(local);
//手工解除引用
local = null;
不过,这种做法并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,方便垃圾收集器下次执行的时候将其回收。
引用数据类型
Object类型
JavaScript中对象其实就是一组数据和功能的集合。对象可以通过执行new操作符跟要创建的对象类型的名称来创建。而创建Object类型的实例并为其添加属性或者方法就可以创建自定义对象。下面三段代码作为操作的案例。
使用构造函数的方法创建
function fun(){
var obj = new Object();
obj.name = "alvin";
obj.age = 12;
obj.score = 98;
alert("姓名: " + obj.name + " 年龄: " + obj.age + " 成绩: " + obj.score);
}
使用对象字面量的方法创建
var person = {
name : "bob",
age : 18,
score : 98
};
alert("姓名: " + person.name + " 年龄: " + person.age + " 成绩: " + person.score);
还可以直接 = {},此类操作和 new Object() 是相同的
var person = { };
person.name = "alvin";
person.age = 18;
person.score = 78;
alert("姓名: " + person.name + " 年龄: " + person.age + " 成绩: " + person.score);
Array类型
作为一名后端程序员来说,一看名字就知道这是数组,但是JavaScript的数组和Java或者C语言的数组不太一样。JavaScript的数组使用起来更加有点像是Python语言里面的列表。在C语言里面,数组的大小和类型都是固定的。也就是说,一旦定义了数组的大小和类型就不再可以改变。而JavaScript的数组大小可以动态调整,并且存储的类型可以是任何类型。下面一段代码举个例子。
var arr = new Array();
arr[0] = "hello";
arr[1] = 123;
arr[2] = 9.9;
arr[3] = true;
alert(arr);
数组的创建方法还有一种,就是前面说过的字面量表示法
var arr = [1,2,3,4,5,6,7];
alert(arr);
检测数组
在JavaScript里,如果要确定一个对象是不是数组就可以使用 instanceof 操作符得到满意的结果。
var arr = [1,2,3,4,5];
if(arr instanceof Array){
alert("是数组");
}else{
alert("不是数组");
}
但是这么做的话又会有一个问题,那就是它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个完全不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。如果说我要从一个框架向另一个框架传入数组。那么传入的数组和第二个框架中原生创建的数组分别具有各自不同的构造函数。于是乎后面就出现了Array.isArray()方法。
var arr = [1,2,3,4,5];
if(Array.isArray(arr)){
alert("是数组");
}else{
alert("不是数组");
}
转换方法
在JavaScript中所有对象都具有toLocaleString()、toString()和valueOf()方法。其中呢,valueOf 返回的还是数组本身,而调用toString就会返回数组的字符串。而每个元素之间都会有一个逗号,学过Java语言的话一定深有体会。
toLocaleString() 和 toString咋一看显示的内容好像差不多啊。但实际上还是有一定区别的。toLocaleString()是为了取得每一项的值,调用的是每一项的toLocaleString()方法,而不是toString()方法。
栈和队列
栈和队列都是属于数据结构一类,本人过去曾写过这类的博客。
栈和队列的基本概念
顺序栈和链栈
顺序栈和链栈的应用
顺序队和链队
使用自定义的栈来优化二叉树的遍历
在JavaScript中也提供了一种让数组的行为类似于其他数据结构的方法。就比如说,数组可以表现得像栈。栈是一种可以限制插入和删除的数据结构,其本质更像是一种受限制的线性表。栈既可以用数组表示也可以用链表表示,而在这里自然是数组表示的顺序栈。
push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并且返回修改数组的长度。而pop()方法则是从数组末尾移除最后一项,减少length值。然后返回移除的项。
//创建一个数组
var arr = new Array();
//推入两项
var count = arr.push("alvin","bob");
alert(count); //2
//再推入一个
count = arr.push("finally");
alert(count);
//取得最后一项
var item = arr.pop();
alert(item); //这里返回的是 finally。 也就是最后一项
//结果
alert(arr);
接着我们说说队列。队列和栈一样都是受限制的线性表。然后队列和栈是相反的数据结构,可以参考博客栈和队列的基本概念。栈是先进后出,而队列则是先进先出。由于push()是向数组末尾添加项的方法,所以模拟队列就需要一个从数组前端取的项的方法。而实现这个操作的方法则是shift()。它能够移除数组的第一项并且返回该项,然后数组长度-1。shift和push结合可以让数组用起来像是队列。
//创建一个数组
var arr = new Array();
//推入两项
var count = arr.push("alvin","bob");
alert(count); //2
//再推入一个
count = arr.push("finally");
alert(count);
//取得最后一项
var item = arr.shift();
alert(item); //这里返回的是 finally。 也就是最后一项
//结果
alert(arr);
我们发现代码其实没什么改变,只是把pop换成了shift而已~
排序方法
在数组中提供了两个用来排序的方法。它们分别是sort和reverse。sort是顺序,reverse是逆序,也就是翻转。
迭代方法
在JavaScript中为数组定义了五个迭代方法。每个方法接收两个参数。要在每一项上运行的函数作为该函数作用域对象。影响this本身。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。根据使用的方法不同,这个函数执行后的返回值可能会也可能不会影响方法的返回值。这里分别介绍一下
every() | 对数组中的每一项给定运行函数,如果该函数对每一项都返回true,那么就返回true |
filter() | 对数组中的每一项给定运行函数,返回该函数会返回true的项组成数组。 |
forEach() | 对数组中的每一项给定运行函数,这个方法没有返回值/ |
map() | 对数组中的每一项给定运行函数,返回每次调用的结果组成的数组 |
some() | 对数组中的每一项给定运行函数,如果该函数对任一项返回true那么就返回true。 |
语法示例
var numbers = [1,2,3,4,5,6,7];
var result = numbers.some(function(item,index,array){
return (item > 2);
});
alert(result);
归并方法
在JavaScript中还为数组提供了两个归并数组的方法。他们都会迭代数组的所有项然后构建一个最终返回的值。reduce()是从第一个开始。而reduceRight()则是从最后一个开始。
//求数组中所有值之和
var arr = [1,2,3,4,5];
var sum = arr.reduce(function(prev,cur,index,array){
return prev + cur;
});
alert(sum);
Date类型
JavaScript中的Data类型是在早期Java语言中util包中的Date基础上构建的。方法比较多,使用的时候可以看手册或者API。
//获得当前的时间
var now = new Date();
alert(now);
//设置时间
now = new Date("2018-9-12");
alert(now);
toDateString() | 以特定的格式显示年,月,日,周 |
toTimeString() | 以特定的格式显示时,分,秒,地区 |
toLocaleDateString() | 以特定地区的格式显示年,月,日,周 |
toLocaleTimeString() | 以特定地区的格式显示年,月,日,周 |
toUTCString() | 以特定的格式完整的UTC日期 |
RegExp
JavaScript通过RegEXp类型来支持正则表达式
var patt=/pattern/modifiers;
pattern(模式) 描述了表达式的模式
modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配
当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)。比如,以下是等价的:
var re = new RegExp("\\w+");
var re = /\w+/;
每个正则表达式都可带有一或多个标志(flags),用来表明正则表达式的行为。正则表达式的匹配模式支持三种标志。
g : 表示全局模式。这个模式将被应用于所有字符串,而不是在发现第一个匹配项的时候就立即停止。
i : 表示不区分大小写模式。也就是确定匹配项时忽略模式和字符串的大小写。
m :表示多行模式,就是在到达一行文本末尾时还会继续查找下一行中是否与模式匹配的项。
所以说一个正则表达式就是一个模式和三个标志的组合体。不同的组合产生不同的效果。
//匹配字符串中所有good 实例
var pattern = /good/g;
//匹配第一个bat或cat 不区分大小写
var pattern2 = /[bc]at/i;
//匹配所有以at结尾的三个字符的组合,不区分大小写
var pattern3 = / .at/gi;
字面量模式 | 等价的字符串 |
/\[bc\]at/ | "\ \[bc\\]at" |
/\.at/ | "\\.at" |
/name\/age/ | "name\\/age" |
/\d. \d{1,2}/ | "\\d. \\d{1,2}" |
/\w\\hello\\123/ | "\\w\\\\hello\\\\123" |
使用正则表达式字面量和使用RegExp构造函数创建的正则表达式不太一样。在JavaScript中正则表达式字面量始终会共享同一个RegExp实例,而使用构造函数创建的每一个RegExp实例都是一个新的实例。
RegExp实例属性
global | 布尔值,表示是否设置了g的标志 |
ignoreCase | 布尔值,表示是否设置了i的标志 |
lastIndex | 整数,表示开始搜索下一个匹配项的字符位置,从0算起。 |
multiline | 布尔值,表示是否设置了m的标志 |
source | 正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。 |
通过这些属性可以获知一个正则表达式的各方面信息
var pattern = /\[bc\]at/i;
//false
alert(pattern.global);
//true
alert(pattern.ignoreCase);
//false
alert(pattern.multiline);
//0
alert(pattern.lastIndex);
//\[bc\]at
alert(pattern.source);