JavaScript

 一、ECMAScript 

实际上,一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:

  • 核心(ECMAScript)
  • 文档对象模型(DOM) Document object model (整合js,css,html)
  • 浏览器对象模型(BOM) Broswer object model(整合js和浏览器)

 注:ES6就是指ECMAScript 6。

 二、JavaScript 的基础 

 2.1 引入方式 

# Script标签内写代码
    <script>
        alert('hello yuan')
    </script>

# 导入JS文件
<script src="myscript.js"></script>

 2.2 变量 

x=5
y=6
z=x+y

在代数中,我们使用字母(比如 x)来保存值(比如 5)。

通过上面的表达式 z=x+y,我们能够计算出 z 的值为 11。

在 JavaScript 中,这些字母被称为变量。

①变量是弱类型的(很随便);

②声明变量时不用声明变量类型,全都使用var关键字;

var name = "pd";
var name;

②一行可以声明多个变量,并且可以是不同类型;

var name="pd", age=18, hobby="swimming";

③(了解)声明变量时,可以不用var,如果不用var,那么它是全局变量;

变量命名,首字符只能是字母,下划线,$美元符,不能以数字开头,且区分大小写,x与X是两个变量;

⑤变量还应遵守以下某条著名的命名规则:

Camel 标记法
首字母是小写的,接下来的字母都以大写字符开头。例如:
var myTestValue = 0, mySecondValue = "hi";
Pascal 标记法
首字母是大写的,接下来的字母都以大写字符开头。例如:
Var MyTestValue = 0, MySecondValue = "hi";
匈牙利类型标记法
在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串,如下所示“
Var iMyTestValue = 0, sMySecondValue = "hi";
命名规则

⑤保留字不能用做变量名;

abstract
boolean
byte
char
class
const
debugger
double
enum
export
extends
final
float
goto
implements
import
int
interface
long
native
package
private
protected
public
short
static
super
synchronized
throws
transient
volatile
保留字

补充:

ES6新增了 let 命令,用于声明变量。其用法类似于 var,但是所声明的变量只在 let 命令所在的代码块内有效。例如:for循环的计数器就很适合使用let命令。

for (let i=0;i<arr.length;i++){...}

ES6新增 const 用来声明常量。一旦声明,其值就不能改变。

const PI = 3.1415;
PI // 3.1415

PI = 3
// TypeError: "PI" is read-only

 2.3 基础规范 

①每行结束可以不加分号,没有分号会以换行符作为每行的结束;

a=1;b=2;
a=1 b=2;------错误

a=1
b=2

//推荐
a=1;
b=2;
View Code

②注释;

// 这是单行注释

/*
这是
多行注释
*/

使用 {} 来封装代码块;

 2.4 常亮和标识符 

常量 :直接在程序中出现的数据值

标识符

  • 由不以数字开头的字母、数字、下划线(_)、美元符号($)组成;
  • 常用于表示函数、变量等的名称;
  • 例如:_abc,$abc,abc,abc123是标识符,而1abc不是;
  • 保留字不允许被定义为标识符。

 三、JavaScript 数据类型 

// JavaScript拥有动态类型

var x;  // 此时x是undefined
var x = 1;  // 此时x是数字
var x = "pd"  // 此时x是字符串 

 3.1 数字类型(Number)

不区分整型和浮点型,就只有一种数字类型。

var a = 12.34;
var b = 20;
var c = 123e5;  // 12300000
var d = 123e-5;  // 0.00123

还有一种NaN,表示不是一个数字(Not a Number)。

常用方法:

parseInt("123")  // 返回123
parseInt("ABC")  // 返回NaN,NaN属性是代表非数字值的特殊值;该属性用于指示某个值不是数字。
parseFloat("123.456")  // 返回123.456

 3.2 字符串(String)

  • 字符串常量首尾由单引号或双引号括起
  • 字符串中部分特殊字符必须加上右划线\
  • 常用的转义字符 \n:换行 \':单引号 \":双引号 \\:右划线
var a = "Hello"
var b = "world;
var c = a + b; 
console.log(c);  // 得到Helloworld

String数据类型的使用:Unicode的插入方法

<script>
  var str="\u4f60\u597d\n欢迎来到\"JavaScript世界\"";
  alert(str);
</script> 

 3.3 布尔型(Boolean)

Boolean类型仅有两个值:true和false(区别于Python,JS的 true 和 false 都是小写),也代表1和0,实际运算中true=1,false=0
布尔值也可以看作on/off、yes/no、1/0对应true/false
Boolean值主要用于JavaScript的控制语句,例如
    if (x==1){
    y=y+1;
    }else{
    y=y-1;
    }

 ""(空字符串)、0、null、undefined、NaN都是false。

 3.4 null和undefined 

Undefined 类型
Undefined 类型只有一个值,即 undefined。当声明的变量未初始化时,该变量的默认值是 undefined。
当函数无明确返回值时,返回的也是值 "undefined"。

Null 类型
另一种只有一个值的类型是 Null,它只有一个专用值 null,即它的字面量。值 undefined 实际上是从值 null 派生来的,
因此 ECMAScript 把它们定义为相等的。

尽管这两个值相等,但它们的含义不同。undefined 是声明了变量但未对其初始化时赋予该变量的值,null 则用于表示尚未存
在的对象。如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null

null表示变量的值是空,undefined则表示只声明了变量,但还没有赋值。

 3.5 Others 

数据类型转换

JavaScript 属于松散类型的程序语言
变量在声明的时候并不需要指定数据类型
变量只有在赋值的时候才会确定数据类型
表达式中包含不同类型数据则在计算过程中会强制进行类别转换

数字 + 字符串:数字转换为字符串
数字 + 布尔值:true 转换为 1,false 转换为 0
字符串 + 布尔值:布尔值转换为字符串 truefalse

强制类型转换函数

// 函数parseInt:强制转换成整数
parseInt("6.12"); // 6
parseInt("12a");  // 12
parseInt("a12");  // NaN
parseInt("1a2");  // 1

// 函数parseFloat:强制转换成浮点数
parseFloat("6.12"); // 6.12

// 函数eval:将字符串强制转换为表达式并返回结果
eval("1+1");  // 2
eval("1<2");  // true

类型查询(typeof)

ECMAScript 提供了 typeof 运算符来判断一个值是否在某种类型的范围内。可以用这种运算符判断一个值是否表示一种原始类型:如果它是原始类型,还可以判断它表示哪种原始类型。

 typeof是一个一元运算符(就像++,--,!,- 等一元运算符),不是一个函数,也不是一个语句。

typeof("test"+3);    // "string"
typeof(null);      // "object"
typeof(true+1);      // "number"
typeof(true-false);  // "number"

对变量或值调用 typeof 运算符将返回下列值之一:

  undefined   如果变量是 Undefined 类型的
  boolean      如果变量是 Boolean 类型的
  number       如果变量是 Number 类型的
  string          如果变量是 String 类型的
  object         如果变量是一种引用类型或 Null 类型的

 四、ECMAScript 运算符 

 4.1 ECMAScript 算数运算符 

加(+)、 减(-)、 乘(*) 、除(/) 、余数(% )  加、减、乘、除、余数和数学中的运算方法一样  例如:9/2=4.5,4*5=20,9%2=1

-除了可以表示减号还可以表示负号  例如:x=-y

+除了可以表示加法运算还可以用于字符串的连接  例如:"abc"+"def"="abcdef"
 // 递增(++) 、递减(--)

i++相当于i=i+1,i--相当于i=i-1

一元加减法:

var a = "10";
alert(typeof(a));
a = +a;  // 类型转换
alert(typeof(a));

var x = "pd";
x=+x;
alert(x);  // NaN  属于Number类型的一个特殊值,当遇到将字符串转成数字无效时,就会得到一个NaN数据
alert(typeof(x));  // Number

// NaN特点
var n=NaN;
alert(n>3);
alert(n<3);
alert(n==3);
alert(n==NaN);

alert(n!=NaN); // NaN参与的所有的运算都是false,除了!=

 4.2 ECMAScript 逻辑运算符 

等于 ( == ) 、不等于( != ) 、大于( > ) 、小于( < ) 
、大于等于(>=) 、小于等于(<=)
与 (&&) 、或(||) 、非(!)
1 && 1 = 1  1 || 1 = 1
1 && 0 = 0  1 || 0 = 1
0 && 0 = 0  0 || 0 = 0

!0 // true
!1 // false

注意:

1 == "1"  // true
1 === "1"  // false

逻辑 AND 运算符(&&)

逻辑 AND 运算的运算数可以是任何类型的,不止是 Boolean 值。

如果某个运算数不是原始的 Boolean 型值,逻辑 AND 运算并不一定返回 Boolean 值:

  • 如果某个运算数是 null,返回 null。
  • 如果某个运算数是 NaN,返回 NaN。
  • 如果某个运算数是 undefined,返回undefined。

逻辑 OR 运算符(||)

与逻辑 AND 运算符相似,如果某个运算数不是 Boolean 值,逻辑 OR 运算并不一定返回 Boolean 值。

 4.3 ECMAScript 赋值运算符 

=  +=  -=  *=  /=
JavaScript中 = 代表赋值,两个等号 == 表示判断是否相等;
例如,x=1表示给 x 赋值为 1if (x==1){...}程序表示当x与1相等时;
if(x=="on"){…}程序表示当x与“on”相等时;

配合其他运算符形成的简化表达式:
例如i+=1相当于i=i+1,x&=y相当于x=x&y。

 4.4 ECMAScript 等性运算符 

执行类型转换的规则如下:

  • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
  • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
  • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
  • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。

在比较时,该运算符还遵守下列规则:

  • 值 null 和 undefined 相等。 
  • 在检查相等性时,不能把 null 和 undefined 转换成其他值。 
  • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。
  • 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。 

 4.5 ECMAScript 关系运算符(重要)

var bResult = "Blue" < "alpha";
alert(bResult); //输出 true

在上面的例子中,字符串 "Blue" 小于 "alpha",因为字母 B 的字符代码是 66,字母 a 的字符代码是 97。

比较数字和字符串

另一种棘手的状况发生在比较两个字符串形式的数字时,比如:

var bResult = "25" < "3";
alert(bResult); //输出 "true"

上面这段代码比较的是字符串 "25" 和 "3"。两个运算数都是字符串,所以比较的是它们的字符代码("2" 的字符代码是 50,"3" 的字符代码是 51)。

不过,如果把某个运算数该为数字,那么结果就有趣了:

var bResult = "25" < 3;
alert(bResult); //输出 "false"

这里,字符串 "25" 将被转换成数字 25,然后与数字 3 进行比较,结果不出所料。

总结:

  • 比较运算符两侧如果一个是数字类型,一个是其他类型,会将其类型转换成数字类型。
  • 比较运算符两侧如果都是字符串类型,比较的是最高位的asc码,如果最高位相等,继续取第二位比较。

 4.6 全等号和非全等号 

等号和非等号的同类运算符是全等号和非全等号。这两个运算符所做的与等号和非等号相同,只是它们在检查相等性前,不执行类型转换。

 五、控制语句 

 5.1 if-else 

var a = 10;
if (a > 5){
  console.log("yes");
}else {
  console.log("no");
}
var x= (new Date()).getDay();  //获取今天的星期值,0为星期天
var y;

if ( (x==6) || (x==0) ) {
y="周末";
}else{
y="工作日";
}

alert(y);


// 等价于
y="工作日";
if ((x==6)||(x==0)){
y="周末";
}

alert(y);

 5.2 if else-if else 

var a = 10;
if (a > 5){
  console.log("a > 5");
}else if (a < 5) {
  console.log("a < 5");
}else {
  console.log("a = 5");
}

 5.3 switch 

var today = 1;
switch (today){
  case 1:
  console.log("麻辣香锅");
  break;
  case 2:
  console.log("麻辣烫");
  break;
  default:
  console.log("麻辣小龙虾")
}

switch中的case子句通常都会加break语句,否则程序会继续执行后续case中的语句。

switch 比 else if 结构更加简洁清晰,使程序可读性更强,效率更高。

首先要看一个问题,if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断;而 switch 只能对基本类型进行数值比较。两者的可比性就仅限在两个基本类型比较的范围内。
说到基本类型的数值比较,那当然要有两个数。然后重点来了:
if 语句每一句都是独立的,看下面的语句:
if (a == 1) ...
else if (a == 2) ...
这样 a 要被读入寄存器两次,1 和 2 分别被读入寄存器一次。于是你是否发现其实 a 读两次是有点多余的,在你全部比较完之前只需要一次读入寄存器就行了,其余都是额外开销。但是 if 语句必须每次都把里面的两个数从内存拿出来读到寄存器,它不知道你其实比较的是同一个 a。
于是 switch case 就出来了,把上面的改成 switch case 版本:
switch (a){
    case 0:
    break;
    case 1:
}

         
总结:
1.switch用来根据一个整型值进行多路分支,并且编译器可以对多路分支进行优化;
2.switch-case只将表达式计算一次,然后将表达式的值与每个case的值比较,进而选择执行哪一个case的语句块;
3.if..else 的判断条件范围较广,每条语句基本上独立的,每次判断时都要条件加载一次。
所以在多路分支时用switch比if..else if .. else结构要效率高。
switch为什么效率高?

 5.4 for 

for (初始化;条件;增量){
    语句1;
    ...
}
功能说明:实现条件循环,当条件成立时,执行语句1,否则跳出循环体。

for (var i=0;i<10;i++) {
  console.log(i);
}

注意:

doms=document.getElementsByTagName("p");

for (var i in doms){
   console.log(i); // 0 1 2 length item namedItem
   //console.log(doms[i])
}

//循环的是你获取的th一个DOM元素集,for in 用来循环对象的所有属性,dom 元素集包含了你上面输出的属性。
//如果你只要循环 dom 对象的话,可以用 for 循环:

for (var i=0;i<doms.length;i++){
    console.log(i) ; // 0 1 2
    //console.log(doms[i])
}
View Code

 结论:for i in 不推荐使用 

 5.5 while 

while (条件){
语句1;
...
}
功能说明:运行功能和for类似,当条件成立循环执行语句花括号{}内的语句,否则跳出循环。


var i = 0;
while (i < 10) {
  console.log(i);
  i++;
}
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script language="JavaScript">
    // func是定义的函数名,前面必须加上function和空格
    function func(){
        var helloStr;
        var myName=prompt("请问您贵姓?","p");
        helloStr="您好,"+myName+'先生,欢迎进入"探索之旅"!';
        alert(helloStr);
        document.write(helloStr);
    }
    // 这里是对前面定义的函数进行调用
    func();
    </script>
</head>
<body>
</body>
</html>
View Code

 5.6 三元运算 

var a = 1;
var b = 2;
c = a > b ? a : b

 六、ECMA 对象 

从传统意义上来说,ECMAScript 并不真正具有类。事实上,除了说明不存在类,在 ECMA-262 中根本没有出现“类”这个词。ECMAScript 定义了“对象定义”,逻辑上等价于其他程序设计语言中的类。

var o = new Object();

对象的概念与分类

  • 由ECMAScript定义的本地对象,独立于宿主环境的 ECMAScript 实现提供的对象 .(native object)
  • ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。(built-in object)
  • 所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。所有 BOM 和 DOM 对象都是宿主对象。

 object对象ECMAScript 中的所有对象都由这个对象继承而来;Object 对象中的所有属性和方法都会出现在其他对象中。

11种内置对象:Array ,String ,Date, Math, Boolean,Number ,Function,Global,Error,RegExp,Object

在JavaScript中除了null和undefined以外其他的数据类型都被定义成了对象,也可以用创建对象的方法定义变量,String、Math、Array、Date、RegExp都是JavaScript中重要的内置对象,在JavaScript程序大多数功能都是通过对象实现的。

<script language="javascript">
// 利用数字对象获取可表示最大数
var aa=Number.MAX_VALUE; 
// 创建字符串对象
var bb=new String("hello JavaScript"); 
// 创建日期对象
var cc=new Date();
// 数组对象
var dd=new Array("星期一","星期二","星期三","星期四"); 
</script>

 6.1 String对象 

// 自动创建字符串对象
var str1="hello world";
调用字符串的对象属性或方法时自动创建对象,用完就丢弃。


// 手工创建字符串对象
var str1= new String("hello word");
采用new创建字符串对象str1,全局有效。

String对象常用方法:

        

                    

    

  拼接字符串一般使用 + 

string.slice(start, stop)和string.substring(start, stop):

两者的相同点:
如果start等于end,返回空字符串
如果stop参数省略,则取到字符串末
如果某个参数超过string的长度,这个参数会被替换为string的长度

substirng()的特点:
如果 start > stop ,start和stop将被交换
如果参数是负数或者不是数字,将会被0替换

silce()的特点:
如果 start > stop 不会交换两者
如果start小于0,则切割从字符串末尾往前数的第abs(start)个的字符开始(包括该位置的字符)
如果stop小于0,则切割在从字符串末尾往前数的第abs(stop)个字符结束(不包含该位置字符)
.slice()和.substring()的区别

补充:

ES6中引入了模板字符串。模板字符串(template string)是增强版的字符串,用反引号 ` 标识。它可以当做普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通字符串
`这是普通字符串!`
// 多行文本
`这是多行的
文本`
// 字符串中嵌入变量
var name = "q1mi", time = "today";
`Hello ${name}, how are you ${time}?`

注意:

如果模板字符串中需要使用反引号,则在其前面要用反斜杠转义。

 6.2 Array对象 

创建数组对象

数组对象的作用是:使用单独的变量名来存储一系列的值。类似于Python中的列表。

Array 对象用于在单个的变量中存储多个值。
语法:

创建方式1:
var a=[1,2,3];

创建方式2:
new Array();  // 创建数组时允许指定元素个数也可以不指定元素个数。
new Array(size);  // 1个参数且为数字,即代表size,not content
new Array(element0, element1, ..., elementn)//也可以直接在建立对象时初始化数组元素,元素类型允许不同
var test=new Array(100,"a",true);

Array对象常用方法:

        

        

   

关于sort()需要注意:

如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的
顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值
的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
View Code

示例:

function sortNumber(a,b){
    return a - b
};
var arr = [11, 100, 22, 55, 33, 44];
arr.sort(sortNumber);  // [11, 22, 33, 44, 55, 100]

 关于遍历数组中的元素,可以使用下面的方式:

var arr = [10, 20, 30, 40];
for (var i=0;i<arr.length;i++) {
  console.log(arr[i]);
};

forEach() 

语法:forEach(function(currentValue, index, arr), thisValue);

splice() 

语法:splice(index,howmany,item1,.....,itemX)

map() 

语法:map(function(currentValue,index,arr), thisValue)

 6.3 Date对象 

创建Date对象

//方法1:不指定参数
var nowd1=new Date();
alert(nowd1.toLocaleString());  //2018/10/23 下午8:06:34
alert(nowd1.toLocaleTimeString());  //下午8:06:03
//方法2:参数为日期字符串
var nowd2=new Date("2004/3/20 11:12");
alert(nowd2.toLocaleString());
var nowd3=new Date("04/03/20 11:12");
alert(nowd3.toLocaleString());
//方法3:参数为毫秒数
var nowd3=new Date(5000);
alert(nowd3.toLocaleString());
alert(nowd3.toUTCString());

//方法4:参数为年月日小时分钟秒毫秒
var nowd4=new Date(2004,2,20,11,12,0,300);
alert(nowd4.toLocaleString());
//毫秒并不直接显示
View Code

Date对象的方法:获取日期和时间

获取日期和时间
getDate()                 获取日
getDay ()                 获取星期
getMonth ()               获取月(0-11)
getFullYear ()            获取完整年份
getYear ()                获取年
getHours ()               获取小时
getMinutes ()             获取分钟
getSeconds ()             获取秒
getMilliseconds ()        获取毫秒
getTime ()                返回累计毫秒数(从1970/1/1午夜)
View Code

练习实例:

function getCurrentDate(){
        //1. 创建Date对象
        var date = new Date(); //没有填入任何参数那么就是当前时间
        //2. 获得当前年份
        var year = date.getFullYear();
        //3. 获得当前月份 js中月份是从0到11.
        var month = date.getMonth()+1;
        //4. 获得当前日
        var day = date.getDate();
        //5. 获得当前小时
        var hour = date.getHours();
        //6. 获得当前分钟
        var min = date.getMinutes();
        //7. 获得当前秒
        var sec = date.getSeconds();
        //8. 获得当前星期
        var week = date.getDay(); //没有getWeek
        // 2014年06月18日 15:40:30 星期三
        return year+"年"+changeNum(month)+"月"+day+"日 "+hour+":"+min+":"+sec+" "+parseWeek(week);
    }

alert(getCurrentDate());

//解决 自动补齐成两位数字的方法
    function changeNum(num){
    if(num < 10){
        return "0"+num;
    }else{
        return num;
    }

}
//将数字 0~6 转换成 星期日到星期六
    function parseWeek(week){
    var arr = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
    //             0      1      2      3 .............
    return arr[week];
}
View Code

Date对象的方法:设置日期和时间

//设置日期和时间
//setDate(day_of_month)   设置日
//setMonth (month)        设置月
//setFullYear (year)      设置年
//setHours (hour)         设置小时
//setMinutes (minute)     设置分钟
//setSeconds (second)     设置秒
//setMillliseconds (ms)   设置毫秒(0-999)
//setTime (allms)        设置累计毫秒(从1970/1/1午夜)
    
var x=new Date();
x.setFullYear (1997);  //设置年1997
x.setMonth(7);         //设置月7
x.setDate(1);          //设置日1
x.setHours(5);         //设置小时5
x.setMinutes(12);      //设置分钟12
x.setSeconds(54);      //设置秒54
x.setMilliseconds(230);//设置毫秒230
document.write(x.toLocaleString( )+"<br>");
//返回1997年8月1日5点12分54秒

x.setTime(870409430000); //设置累计毫秒数
document.write(x.toLocaleString( )+"<br>");
//返回1997年8月1日12点23分50秒 
View Code

Date对象的方法:日期和时间的转换

日期和时间的转换:

getTimezoneOffset():8个时区×15度×4分/度=480;
返回本地时间与GMT的时间差,以分钟为单位
toUTCString()
返回国际标准时间字符串
toLocalString()
返回本地格式时间字符串
Date.parse(x)
返回累计毫秒数(从1970/1/1午夜到本地时间)
Date.UTC(x)
返回累计毫秒数(从1970/1/1午夜到国际时间)
View Code

 6.4 RegExp对象 

//RegExp对象

//创建正则对象方式1
// 参数1 正则表达式(不能有空格)
// 参数2 匹配模式:常用g(全局匹配;找到所有匹配,而不是在第一个匹配后停止)和i(忽略大小写)

// 用户名只能是英文字母、数字和_,并且首字母必须是英文字母。长度最短不能少于6位 最长不能超过12位。

// 创建RegExp对象方式(逗号后面不要加空格)
var reg1 = new RegExp("^[a-zA-Z][a-zA-Z0-9_]{5,11}$");

// 匹配响应的字符串
var s1 = "bc123";

//RegExp对象的test方法,测试一个字符串是否符合对应的正则规则,返回值是true或false。
reg1.test(s1);  // true

// 创建方式2
// /填写正则表达式/匹配模式(逗号后面不要加空格)
var reg2 = /^[a-zA-Z][a-zA-Z0-9_]{5,11}$/;

reg2.test(s1);  // true


// String对象与正则结合的4个方法
var s2 = "hello world";

s2.match(/o/g);         // ["o", "o"]             查找字符串中 符合正则 的内容
s2.search(/h/g);        // 0                      查找字符串中符合正则表达式的内容位置
s2.split(/o/g);         // ["hell", " w", "rld"]  按照正则表达式对字符串进行切割
s2.replace(/o/g, "s");  // "hells wsrld"          对字符串按照正则进行替换

// 关于匹配模式:g和i的简单示例
var s1 = "name:Alex age:18";

s1.replace(/a/, "哈哈哈");      // "n哈哈哈me:Alex age:18"
s1.replace(/a/g, "哈哈哈");     // "n哈哈哈me:Alex 哈哈哈ge:18"      全局匹配
s1.replace(/a/gi, "哈哈哈");    // "n哈哈哈me:哈哈哈lex 哈哈哈ge:18"  不区分大小写


// 注意事项1:
// 如果regExpObject带有全局标志g,test()函数不是从字符串的开头开始查找,而是从属性regExpObject.lastIndex所指定的索引处开始查找。
// 该属性值默认为0,所以第一次仍然是从字符串的开头查找。
// 当找到一个匹配时,test()函数会将regExpObject.lastIndex的值改为字符串中本次匹配内容的最后一个字符的下一个索引位置。
// 当再次执行test()函数时,将会从该索引位置处开始查找,从而找到下一个匹配。
// 因此,当我们使用test()函数执行了一次匹配之后,如果想要重新使用test()函数从头开始查找,则需要手动将regExpObject.lastIndex的值重置为 0。
// 如果test()函数再也找不到可以匹配的文本时,该函数会自动把regExpObject.lastIndex属性重置为 0。

var reg3 = /foo/g;
// 此时 regex.lastIndex=0
reg3.test('foo'); // 返回true
// 此时 regex.lastIndex=3
reg3.test('xxxfoo'); // 还是返回true
// 所以我们在使用test()方法校验一个字符串是否完全匹配时,一定要加上^和$符号。

// 注意事项2(说出来你可能不信系列):
// 当我们不加参数调用RegExpObj.test()方法时, 相当于执行RegExpObj.test("undefined"), 并且/undefined/.test()默认返回true。
var reg4 = /^undefined$/;
reg4.test(); // 返回true
reg4.test(undefined); // 返回true
reg4.test("undefined"); // 返回true
View Code

 6.5 Math对象 

    //Math对象
    //该对象中的属性方法 和数学有关.
    //Math是内置对象 , 与Global的不同之处是, 在调用时 需要打出 "Math."前缀.
    //属性学习:
    //alert(Math.PI);
    //方法学习:
        //alert(Math.random()); // 获得随机数 0~1 不包括1.
        //alert(Math.round(1.5)); // 四舍五入
        //练习:获取1-100的随机整数,包括1和100
             //var num=Math.random();
            //num=num*10;
            //num=Math.round(num);
            // alert(num)
        //============max  min=========================
        /* alert(Math.max(1,2));// 2
        alert(Math.min(1,2));// 1 */
        //-------------pow--------------------------------
        alert(Math.pow(2,4));// pow 计算参数1 的参数2 次方.



abs(x)      返回数的绝对值。
exp(x)      返回 e 的指数。
floor(x)    对数进行下舍入。
log(x)      返回数的自然对数(底为e)。
max(x,y)    返回 x 和 y 中的最高值。
min(x,y)    返回 x 和 y 中的最低值。
pow(x,y)    返回 x 的 y 次幂。
random()    返回 0 ~ 1 之间的随机数。
round(x)    把数四舍五入为最接近的整数。
sin(x)      返回数的正弦。
sqrt(x)     返回数的平方根。
tan(x)      返回角的正切。
View Code

 6.6 JSON对象 

var obj1 = {name: "Alex", age: 18};
var str1 = '{"name": "Alex", "age": 18}';
// 对象转换成JSON字符串
var str = JSON.stringify(obj1);
// JSON字符串转换成对象
var obj = JSON.parse(str1); 

 6.7 Function对象(重点)

 Function 类可以表示开发者定义的任何函数。

  • 可以使用变量、常量或表达式作为函数调用的参数
  • 函数由关键字 function 定义
  • 函数名的定义规则与标识符一致,大小写是敏感的
  • 返回值必须使用 return
// 用 Function 类直接创建函数的语法如下
function 函数名 (参数){

  函数体;
  return 返回值;
}

// 或者
var 函数名 = new Function("参数1","参数n","function_body");

虽然由于字符串的关系,第二种形式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用Function 类明确创建的函数行为是相同的;

示例:

// 方式1
function func1(){
    alert('hello pd');
    return 8
}
 
ret=func1();
alert(ret)

// 方式2
var func1=new Function("name","alert(\"hello \"+name);")
func1("pd")

6.7.1 函数的调用

function func1(a,b){
    alert(a+b);
}
//只要函数名写对即可,参数怎么填都不报错
func1(1,2);    //3
func1(1,2,3); //3
func1(1);      //NaN
func1();        //NaN

6.7.2 匿名函数

// 匿名函数
var func = function(arg){
    return "tony";
}

// 匿名函数的应用(立即执行函数)
(function(){
    alert("tony");
})()

(function(arg){
    console.log(arg);
})('123')
View Code

6.7.3 函数的内置对象arguments

function add(a,b){
    console.log(a+b);  // 3
    console.log(arguments.length);  // 2
    console.log(arguments);  // [1,2]

    }
add(1,2)
----------------------------------------
// arguments的用处1
(function add() {
    let r = 0;
    for (let i = 0; i < arguments.length; i++) {
        r = r + arguments[i];
    }
    alert(r)
})(1,2,3,4,5)
----------------------------------------
// arguments的用处2
function foo(a,b,c){
    if (arguments.length!=3){
        throw new Error("Function foo called with "+arguments.length+" arguments,but it just need 3 arguments.");
    }else {
        alert("success!");
    }
}
foo(1,2,3,4,5);
View Code

 注意:函数只能返回一个值,如果要返回多个值,只能将其放在数组或对象中返回。

6.7.4 函数的全局变量和局部变量

局部变量:在JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它(该变量的作用域是函数内部)。只要函数运行完毕,本地变量就会被删除。

全局变量:在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

变量生存周期:

  • JavaScript变量的生命期从它们被声明的时间开始。
  • 局部变量会在函数运行以后被删除。
  • 全局变量会在页面关闭后被删除。

6.7.5 函数的作用域链和闭包

作用域:JavaScript 的作用域和 Python 相似,if while 等控制语句并没有自己作用域,而函数是有自己的作用域的;首先在函数内部查找变量,找不到则到外层函数查找,逐步找到最外层。

嵌套函数的作用域:

例1:

var city = 'beijing';
function func(){ var city = 'shanghai'; function inner(){ var city = 'shenzhen'; console.log(city); } inner(); }
func();
// shenzhen

例2:

var city = 'beijing';
function Bar(){ console.log(city); } function func(){ var city = 'shanghai'; return Bar; }
var ret = func(); ret(); // beijing ret()相当于Bar()

闭包:

var city = 'beijing';

function func(){
    var city = "shanghai";
    function inner(){
        console.log(city);
    }
    return inner;
}

var ret = func();
ret();  // shanghai

作用域链(Scope Chain):

  在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

var x=1;
function foo(){
    var y = 2;
    function bar(){
        var z = 3;
    }
}

// bar的作用域链:barScopeChain=[bar.AO, foo.AO, global.VO];
// foo的作用域链:fooScopeChain=[foo.Ao, global.VO];
// 什么是AO,VO?
在函数创建时,每个函数都会创建一个活动对象 Active Object(AO);全局对象为 Global Object(VO);
创建函数的过程也就是为这个对象添加属性的过程,作用域链就是由这些绑定了属性的活动对象构成的。
例如: 找x变量;bar函数在搜寻变量x的过程中,先从自身AO对象上找,如果bar.AO存在这个属性,那么会
      直接使用这个属性的值,如果不存在,则会转到父级函数的AO对象,也就是foo.AO。如果找到x属性
      则使用,找不到继续在 VO 对象查找,找到x的属性,返回属性值。如果在VO中没有找到,则会抛出异
    常ReferenceError。
// 执行上下文。 函数在执行时会创建一个称为“执行上下文(execution context)”的内部对象,执行上下文定义了函数执 行时的环境。每个执行上下文都有自己的作用域链,用于标识符解析,当执行上下文被创建时,而它的作用域 链初始化为当前运行函数的[[Scope]]所包含的对象。 // 函数执行 在函数执行过程中,每遇到一个变量,都会检索从哪里获取和存储数据,该过程从作用域链头部,也就是从活 动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没有则继续搜索作用域 链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义,函数执行过程中,每个标识符都 要经历这样的搜索过程。

创建作用域链的过程

函数进入全局,创建VO对象,绑定x属性<入栈>
    global.VO={x=underfind; foo:reference of function}(这里只是预解析,为
    AO对象绑定声明的属性,函数执行时才会执行赋值语句,所以值是underfind)
遇到foo函数,创建foo.AO,绑定y属性<入栈>
    foo.AO={y=underfind, bar:reference of function}
遇到bar函数,创建bar.AO,绑定z属性<入栈>
    bar.AO={z:underfind}
    
作用域链和执行上下文都会保存在堆栈中,所以:
    bar函数的scope chain为:[0]bar.AO-->[1]foo.AO-->[2]global.VO
    foo函数的scope chain为:[0]foo.AO-->[1]global.Vo

//建议:少定义全局变量
//理由:因为作用域链是栈的结构,全局变量在栈底,每次访问全局变量都会遍历一次栈,这样会影响效率

函数的 scope 等于自身的 AO 对象加上父级的 scope,也可以理解为一个函数的作用域等于自身活动对象加上父级作用域。

函数执行前后的作用域链:

注意:作用域链的非自己部分在函数对象被建立(函数声明、函数表达式)的时候建立,而不需要等到执行。

6.7.6 词法分析

JS代码运行前,有一个类似编译的过程即词法分析,词法分析主要有3个步骤:分析函数参数、分析变量声明、分析函数声明。

具体步骤如下:

在函数运行的瞬间,会生成一个活动对象 Active Object (AO)。

①分析函数参数

  • 将函数的形参添加为AO属性,属性的默认值为undefined。
  • 接收函数的实参,并覆盖原属性值。

②分析变量声明/分析局部变量

  • 若AO中不存在与声明的变量所对应的属性,则添加AO属性为为undefined。
  • 若AO中已存在与声明的变量所对应的属性,则不做任何修改。

③分析函数声明

  • 若AO中存在与函数名所对应的属性,则覆盖原属性为一个函数表达式。

具体分析如下:

①分析函数参数

1 function func(age){
2     console.log(age);
3 }
4 
5 func();  // 将函数的形参添加为AO属性,属性的默认值为undefined;即AO.age = undefined
6 func(10);  // 接收函数的实参,并覆盖原属性值;即AO.age = 10

②分析变量声明/分析局部变量

1 function func(age){
2     console.log(age);  // 10
3     // 分析变量声明/分析局部变量
4     // 若AO中已存在与声明的变量所对应的属性,则不做任何修改。
5     var age = 20;  // 执行过程:对变量进行赋值
6     console.log(age);  // 20
7 }
8 
9 func(10);

第5行代码有var age = 20,但此时已存在AO.age = 10(步骤①中已说明),则不做任何修改,即AO.age = 10

③分析函数声明

 1 function func(age){
 2     console.log(age); // function age(){}
 3     // 分析变量声明/分析局部变量
 4     // 若AO中已存在与声明的变量所对应的属性,则不做任何修改。
 5     var age = 20;  // 执行过程:对变量进行赋值
 6     console.log(age); // 20
 7     // 分析函数声明
 8     // 若AO中存在与函数名所对应的属性,则覆盖原属性为一个函数表达式。
 9     function age(){
10     }
11     console.log(age);  // 20
12 }
13 
14 func(10);

第9行代码有 age,则将 function age(){} 赋给 AO.age,即 AO.age = function age(){};

第5行代码 20 赋给变量 age,即 age = 20;

第6行代码运行时,age 已经被赋值为 20,所以结果是 20;

第9、10行代码是一个函数表达式,所以不会做任何操作;

第11行代码运行时,age 还是 20 ,所以结果也是 20;

其他例子测试以及结果:

// 例1
var
age = 10; function foo(){ console.log(age); var age = 20; console.log(age); } foo(); // 结果 undefined 20
// 例2
var
age = 10; function foo(){ console.log(age); // function age(){console.log("什么都没干");} var age = 20; console.log(age); //20 function age(){ console.log("什么都没干"); } console.log(age); //20 } foo();
// 例3
function
func(age){ var age; console.log(age); // function age(){console.log(age);} function age(){ console.log(age); // function age(){console.log(age);} } age(); console.log(age); // function age(){console.log(age);} } func(10);
// 例4
function
func(age){ var age; console.log(age); var age = 20; console.log(age); function age(){ console.log(age); } age(); console.log(age); } func(10);

// 例5
function
func(age){ console.log(age); var age = function age(){ console.log(age); }; age(); console.log(age); } func(10);

 

posted @ 2018-10-15 18:02  就俗人一个  阅读(360)  评论(0编辑  收藏  举报