JavaScript

一、 JavaScript 基础

什么是语言

计算机就是一个由人来控制的机器,人让它干嘛,它就得干嘛,要学习的语言就是人和计算机交流的工具,人类通过语言来控制、操作计算机。编程语言和说的中文、英文本质上没有区别,只是语法比较特殊。

语言的发展

  • 纸带机:机器语言
  • 汇编语言:符号语言
  • 现代语言:高级语言

起源

JavaScript诞生于1995年,它的出现主要是用于处理网页中的前端验证。所谓的前端验证,就是指检查用户输入的内容是否符合一定的规则。比如:用户名的长度,密码的长度,邮箱的格式等。

简史

  • JavaScript是由网景公司发明,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript。
  • 1996年微软公司在其最新的IE3浏览器中引入了自已对JavaScript的实现JScript。
  • 于是在市面上存在两个版本的JavaScript,一个网景公司的JavaScript和微软的JScript。
  • 为了确保不同的浏览器上运行的JavaScript标准一致,所以几个公司共同定制了JS的标准名命名为ECMAScript。

时间表

年份 事件
1995年 网景公司开发了JavaScript
1996年 微软发布了和JavaScript兼容的JScript
1997年 ECMAScript第1版(ECMA-262)
1998年 ECMAScript第2版
1998年 DOM Level 1的制定
1998年 新型语言DHTML登场
1999年 ECMAScript第3版
2000年 DOM Level 2的制定
2002年 ISO/IEC16262:2002的确立
2004年 DOM Level 3的制定
2005年 新型语言AJAX登场
2009年 ECMAScript第5版
2009年 新型语言HTML5登场

标准

ECMAScript是一个标准,而这个标准需要由各个厂商去实现。不同的浏览器厂商对该标准会有不同的实现。

浏览器 JavaScript实现方式
FireFox SpiderMonkey
Internet Explorer JScript/Chakra
Safari JavaScriptCore
Chrome v8

特点

JS的特点

  • 解释型语言
  • 类似于C和Java的语法结构
  • 动态语言
  • 基于原型的面向对象

解释型语言

JavaScript是一门解释型语言,所谓解释型值语言不需要被编译为机器码在执行,而是直接执行。由于少了编译这一步骤,所以解释型语言开发起来尤为轻松,但是解释型语言运行较慢也是它的劣势。不过解释型语言中使用了技术,使得运行速度得以改善。

类似于 C 和 Java 的语法结构

JavaScript的语法结构与C和Java很像,向for、if、while等语句和Java的基本上是一模一样的。所以有过C和Java基础的同学学习起来会轻松很多。不过JavaScript和与Java的关系也仅仅是看起来像而已。

动态语言

JavaScript是一门动态语言,所谓的动态语言可以暂时理解为在语言中的一切内容都是不确定的。比如一个变量,这一时刻是个整型,下一时刻可能会变成字符串了。当然这个问题以后再谈。不过在补充一句动态语言相比静态语言性能上要差一些,不过由于JavaScript中应用的JIT技术,所以JS可能是运行速度最快的动态语言了。

编写位置

之前提到的JS全都是客户端的JS,也就是说全都是需要在浏览器中运行的,所以JS代码全都需要在网页中编写。 JS代码需要编写到<script>标签中。 一般将<script>标签写到<head>中。(和<style>标签有点像)

属性:

  • type:默认值text/javascript可以不写,不写也是这个值。
  • src:当需要引入一个外部的js文件时,使用该属性指向文件的地址。

创建一个html文件

在html文件的<head>标签中创建一个<script>标签,并编写如下代码。

1<script type="text/javascript">
2console.log("Hello World");
3</script>

严格区分大小写

JavaScript是严格区分大小写的,也就是abcAbc会被解析器认为是两个不同的东西。 所以在编写上面的HelloWorld时,一定要注意区分大小写。

注释

注释中的内容不会被解析器解析执行,但是会在源码中显示,一般会使用注释对程序中的内容进行解释。 JS中的注释和Java的一致,分为两种:

  • 单行注释://注释内容
  • 多行注释:/*注释内容*/

标识符

所谓标识符,就是指变量、函数、属性的名字,或函数的参数 标识符可以是按照下列格式规则组合起来的一或多个字符:

  • 第一个字符必须是一个字母、下划线(_)或一个美元符号($)。
  • 其他字符可以是字母、下划线、美元符号或数字 按照惯例,ECMAScript标识符采用驼峰命名法 但是要注意的是JavaScript中的标识符不能是关键字和保留字符。

关键字和保留字符

关键字

单词 单词 单词 单词
break do instanceof typeof
case else new var
catch finally return void
continue for switch while
default if throw delete
in try function this
with debugger false true
null

保留字符

单词 单词 单词 单词
class enum extends super
const export import implements
let private public yield
interface package protected static

其他不建议使用的标识符

单词 单词 单词 单词
abstract double goto native
static boolean enum implements
package super byte export
import private synchronize char
extends int protected throws
class final interface public
transient const float long
short volatile arguments encodeURI
Infinity Number RegExp undefined
isFinite Object String Boolean
Error RangeError parseFloat SyntaxError
Date eval JSON ReferenceError
TypeError decodeURI EvalError Math
URIError decodeURIComponent Function NaN
isNaN parseInt Array encodeURIComponent

变量

变量的作用是给某一个值或对象标注名称。 比如程序中有一个值123,这个值是需要反复使用的,这个时候最好将123这个值赋值给一个变量,然后通过变量去使用123这个值。

变量的声明:

1使用var关键字声明一个变量
2var a;

变量的赋值:

1使用=为变量赋值
2a = 123;

声明和赋值同时进行:

1var a = 123;

数据类型

数据类型决定了一个数据的特征,比如:123和"123",直观上看这两个数据都是123,但实际上前者是一个数字,而后者是一个字符串。 对于不同的数据类型在进行操作时会有很大的不同。 JavaScript中一共有5种基本数据类型:

  • 字符串型(String)
  • 数值型(Number)
  • 布尔型(Boolean)
  • null型(Null)
  • undefined型(Undefined) 这5种之外的类型都称为Object,所以总的来看JavaScript中共有六种数据类型。

typeof运算符

使用typeof操作符可以用来检查一个变量的数据类型 使用方式:typeof数据,例如typeof 123。 返回结果:

  • typeof 数值 number
  • typeof 字符串 string
  • typeof 布尔型 boolean
  • typeof undefined undefined
  • typeof null object

String

String用于表示一个字符序列,即字符串。 字符串需要使用单引号双引号括起来。 转义字符:

转义字符 含义
\n 换行
\t 制表
' 单引号
" 双引号
\b 空格(严格来说是退格)
\r 回车
将其他数值转换为字符串有三种方式:toString()String()+

Number

Number类型用来表示整数和浮点数,最常用的功能就是用来表示10进制的整数和浮点数。 Number表示的数字大小是有限的,范围是:± 1.7976931348623157e+308 如果超过了这个范围,则会返回±InfinityNaN,即非数值(Not a Number)是一个特殊的数值,JS中当对数值进行计算时没有结果返回,则返回NaN

数值的转换

有三个函数可以把非数值转换为数值:Number()parseInt()parseFloat()Number()可以用来转换任意类型的数据,而后两者只能用于转换字符串。 parseInt()只会将字符串转换为整数,而parseFloat()可以转换为浮点数。

Boolean(布尔型)

布尔型也被称为逻辑值类型或者真假值类型。 布尔型只能够取真(true)和假(false)两种数值。除此以外,其他的值都不被支持。 其他的数据类型也可以通过Boolean()函数转换为布尔类型。 转换规则:

数据类型 转换为 true 转换为 false
Boolean true false
String 任何非空字符串 “”(空字符串)
Number 任何非 0 数字 0 和 NaN
Object 任何对象 null
Undefined n/a undefined

Undefined

Undefined类型只有一个值,即特殊的undefined。 在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。 需要注意的是typeof对没有初始化和没有声明的变量都会返回undefined。

Null

Null类型是第二个只有一个值的数据类型,这个特殊的值是null。 从语义上看null表示的是一个空的对象。所以使用typeof检查null会返回一个Object。 undefined值实际上是由null值衍生出来的,所以如果比较undefined和null是否相等,会返回true;

运算符

JS中为定义了一套对数据进行运算的运算符。 这其中包括:算数运算符、位运算符、关系运算符等。

算数运算符

算数运算符顾名思义就是进行算数操作的运算符。 JS中为提供了多种算数运算符。 算数运算符:

运算符 说明
+ 加法
- 减法
* 乘法
/ 除法
% 取模
++(前置) 自增,先将变量的值加 1,然后返回加 1 后的结果
–(前置) 自减,先将变量的值减 1,然后返回减 1 后的结果
++(后置) 自增,先返回变量的当前值,然后将变量的值加 1
–(后置) 自减,先返回变量的当前值,然后将变量的值减 1

自增和自减

自增 ++ 自减 -- 一自增和自减分为前置运算和后置元素。 所谓的前置元素就是将元素符放到变量的前边,而后置将元素符放到变量的后边。 例子:

  • 前置自增:++a
  • 后置自减:a-- 运算符在前置时,表达式值等于变量原值。
    运算符在后置时,表达式值等于变量变更以后的值。

逻辑操作符

一般情况下使用逻辑运算符会返回一个布尔值。
逻辑运算符主要有三个:非、与、或。
在进行逻辑操作时如果操作数不是布尔类型则会将其转换布尔类型在进行计算。
非使用符号!表示,与使用&&表示,或使用||表示

非运算符使用!表示。 非运算符可以应用于任意值,无论值是什么类型,这个运算符都会返回一个布尔值。 非运算符会对原值取反,比如原值是true使用非运算符会返回false,原值为false使用非运算符会返回true

与运算符

与运算符使用&&表示。 与运算符可以应用于任何数据类型,且不一定返回布尔值。 对于非布尔值运算,会先将非布尔值转换为布尔值。 对布尔值做运算时,如果两个值都为true则返回true,否则返回false。 非布尔值时:如果两个都为true,则返回第二个值,如果两个值中有false则返回靠前的false的值。

或运算符使用||表示。

或运算符可以应用于任何数据类型,且不一定返回布尔值。 对于非布尔值运算,会先将非布尔值转换为布尔值。 对布尔值进行运算时,如果两个值都为false则返回false,否则返回true。 非布尔值时:如果两个都为false,则返回第二个值,否则返回靠前true的值。

赋值运算符

简单的赋值操作符由等于号=表示 其作用就是把右侧的值赋给左侧的变量 如果在等于号左边添加加减乘除等运算符,就可以完成复合赋值操作 +=*=-=/=%= 比如:a+=10a=a+10是一样的

关系运算符

1小于<)、大于>)、小于等于<=和大于等于>=

这几个关系运算符用于对两个值进行比较,比较的规则与在数学课上所学的一样。 这几个运算符都返回一个布尔值。用来表示两个值之间的关系是否成立。

1- 5 > 10 false
2- 5 < 10 true
3 5<= 10 true
4- 5 >= 10 false

相等

JS中使用==来判断两个值是否相等,如果相等则返回true。 使用!=来表示两个值是否不相等,如果不等则返回true。 注意:nullundefined使用==判断时是相等的。

表达式 结果
null == undefined true
true == 1 true
“NaN” == NaN false
true == 2 false
5 == NaN false
undefined == 0 false
NaN == NaN false
null == 0 false
NaN!= NaN true
“5” == 5 true
false == 0 true

全等

除了==以外,JS中还提供了=== 三等表示全等,他和==基本一致,不过==在判断两个值时会进行自动的类型转换,而===不会。 也就是说"5"==5会返回true,而"5"===5会返回false; 同样还有!==表示不全等,同样比较时不会自动转型, 也就是说"5"!=5会返回false,而"5"!==5会返回true;

逗号

使用逗号可以在一条语句中执行多次操作 比如:var num1=1, num2=2, num3=3; 使用逗号运算符分隔的语句会从左到右顺序依次执行。

条件运算符

条件运算符也称为三元运算符。通常运算符写为? 这个运算符需要三个操作数,第一个操作数在?之前,第二个操作数在?和:之间,第三个操作数在:之后, 例如:x > 0 ? x : -x // 求x的绝对值 上边的例子,首先会执行x>0,如果返回true则执行冒号左边的代码,并将结果返回,这里就是返回x本身,如果返回false则执行冒号右边的代码,并将结果返回。

运算符的优先级

在 JavaScript 中,运算符的优先级决定了在表达式中哪个运算符先被执行。以下是 JavaScript 中运算符的优先级从高到低的概述:

一、优先级最高的运算符

  1. 圆括号 ():用于改变运算的优先级,括号内的表达式先被计算。

二、一元运算符

  1. 自增 ++(前置和后置)、自减 --(前置和后置)、一元加 +、一元减 -、逻辑非 !、按位非 ~、类型转换运算符(如 Number()String()Boolean())等。

三、算术运算符

  1. 先乘除取模:*/%
  2. 后加减:+-

四、位移运算符

  1. 按位左移 <<、按位右移 >>、无符号右移 >>>

五、关系运算符

  1. 小于 <、小于等于 <=、大于 >、大于等于 >=instanceofin

六、相等运算符

  1. 先判断严格相等 === 和严格不相等 !==
  2. 再判断相等 == 和不相等 !=

七、位运算符

  1. 按位与 &
  2. 按位异或 ^
  3. 按位或 |

八、逻辑运算符

  1. 先逻辑与 &&
  2. 后逻辑或 ||

九、条件运算符(三目运算符)

  1. ? :

十、赋值运算符

  1. 简单赋值 =、复合赋值(如 +=-=*=/= 等)。

例如,在表达式 2 + 3 * 4 中,由于乘法 * 的优先级高于加法 +,所以先计算 3 * 4,结果为 12,然后再计算 2 + 12,最终结果为 14。

如果不确定运算符的优先级,可以使用圆括号来明确运算的顺序,以确保表达式按照预期进行计算。

语句

前边所说的表达式和运算符等内容可以理解成是一门语言中的单词,短语。 而语句(statement)就是这个语言中一句一句完整的话了。 语句是一个程序的基本单位,JS的程序就是由一条一条语句构成的,每一条语句使用;结尾。 JS中的语句默认是由上至下顺序执行的,但是也可以通过一些流程控制语句来控制语句的执行顺序。

代码块

代码块是在大括号{}中所写的语句,以此将多条语句的集合视为一条语句来使用。 例如:

1var a = 123;
2a++;
3alert(a) ;

一般使用代码块将需要一起执行的语句进行分组,需要注意的是,代码块结尾不需要加分号。

条件语句

条件语句是通过判断指定表达式的值来决定执行还是跳过某些语句。 最基本的条件语句:

  • if...else
  • switch...case

if…else语句

if..else语句是一种最基本的控制语句,它让JavaScript可以有条件的执行语句。 第一种形式:

1if(expression)
2    statement

第二种形式:

1if(expression)
2    statement
3else
4    statement

除了if和else还可以使用elseif来创建多个条件分支。

if语句例子

例1

1if(age >= 18) {
2    alert("您已经成年!");
3}

例2

1if(age >= 18){
2    alert("您已经成年!");
3}else {
4    alert("你还未成年!");
5}

例3

1if(age < 18){
2    alert("你还未成年!");
3} else if(age <= 30){
4    alert("您已经是个青年了!");
5} else {
6    alert("你已经是个中年了!");
7}

switch…case语句

switch…case是另一种流程控制语句。 switch语句更适用于多条分支使用同一条语句的情况。 语法:

 1switch表达式{
 2case 表达式1
 3    语句
 4    break
 5case 表达式2
 6    语句
 7    break
 8default:
 9    语句
10}

需要注意的是case语句只是标识的程序运行的起点,并不是终点,所以一旦符合case的条件程序会一直运行到结束。所以一般会在case中添加break作为语句的结束。

循环语句

和条件语句一样,循环语句也是基本的控制语句。 循环中的语句只要满足一定的条件将会一直执行。

while

while语句是一个最基本的循环语句。 while语句也被称为while循环。 语法:

1while(条件表达式){
2语句
3}

和if一样while中的条件表达式将会被转换为布尔类型,只要该值为真,则代码块将会一直重复执行。 代码块每执行一次,条件表达式将会重新计算。

do…while

do..while和while非常类似,只不过它会在循环的尾部而不是顶部检查表达式的值,do..while循环会至少执行一次。 语法:

1do {
2    语句
3} while条件表达式);

相比于while,do..while的使用情况并不是很多。

for

for语句也是循环控制语句,也称它为for循环。 大部分循环都会有一个计数器用以控制循环执行的次数,计数器的三个关键操作是初始化、检测和更新。for语句就将这三步操作明确为了语法的一部分。 语法:

1for初始化表达式条件表达式更新表达式{
2    语句
3}

break和continue

break和continue语句用于在循环中精确地控制代码的执行 使用break语句会使程序立刻退出最近的循环,强制执行循环后边的语句。 break和continue语句只在循环和switch语句中使用。 使用continue语句会使程序跳过当次循环,继续执行下一次循环,并不会结束整个循环。 continue只能在循环中使用,不能出现在其他的结构中。

label

使用label语句可以在代码中添加标签,以便将来使用。 语法:

1label: statement

例子:

1start:for (var i=0;i < count;i++) {
2    alert(i);
3}

这个例子中定义的start标签可以在将来由break或continue语句引用。加标签的语句一般都要与for语句等循环语句配合使用。

二、 对象

Object对象

Object类型,也称为一个对象。是JavaScript中的引用数据类型。 它是一种复合值,它将很多值聚合到一起,可以通过名字访问这些值。 对象也可以看做是属性的无序集合,每个属性都是一个名/值对。 对象除了可以创建自有属性,还可以通过从一个名为原型的对象那里继承属性。 除了字符串、数字、true、false、null和undefined之外,JS中的值都是对象。

创建对象

创建对象有两种方式: 第一种

1var person = new Object();
2person.name = "孙悟空";
3person.age = 18;

第二种

1var person = {
2  name: "孙悟空",
3  age: 18
4};

对象属性的访问

访问属性的两种方式:

  • 点访问
    1对象.属性名
  • 方括号访问
    1对象['属性名']

基本数据类型

JS中的变量可能包含两种不同数据类型的值:基本数据类型和引用数据类型。 JS中一共有5种基本数据类型:String、Number、Boolean、Undefined、Null。 基本数据类型的值是无法修改的,是不可变的。 基本数据类型的比较是值的比较,也就是只要两个变量的值相等,就认为这两个变量相等。

引用数据类型

引用类型的值是保存在内存中的对象。 当一个变量是一个对象时,实际上变量中保存的并不是对象本身,而是对象的引用。 当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象。 这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个。

栈和堆

JavaScript在运行时数据是保存到栈内存和堆内存当中的。 简单来说栈内存用来保存变量和基本类型。堆内存用来保存对象。 在声明一个变量时实际上就是在栈内存中创建了一个空间用来保存变量。 如果是基本类型则在栈内存中直接保存,如果是引用类型则会在堆内存中保存,变量中保存的实际上是对象在堆内存中的地址。

数组

数组也是对象的一种。 数组是一种用于表达有顺序关系的值的集合的语言结构。 创建数组:

1var array = [1, 44, 33];

数组内的各个值被称作元素。每一个元素都可以通过索引(下标)来快速读取。索引是从零开始的整数。

函数

函数是由一连串的子程序(语句的集合)所组成的,可以被外部程序调用。向函数传递参数之后,函数可以返回一定的值。 通常情况下,JavaScript代码是自上而下执行的,不过函数体内部的代码则不是这样。如果只是对函数进行了声明,其中的代码并不会执行。只有在调用函数时才会执行函数体内部的代码。 这里需要注意的是JavaScript中的函数也是一个对象。

函数的声明

首先明确一点函数也是一个对象,所以函数也是在堆内存中保存的。 函数声明比较特殊,需要使用function关键字声明。

1var sum = function(a, b) {
2  return a + b;
3};

上边的例子就是创建了一个函数对象,并将函数对象赋值给了sum这个变量。其中()中的内容表示执行函数时需要的参数,{}中的内容表示函数的主体。

函数的调用

调用函数时,传递给函数的参数称为实参(实际参数)。 如果想调用上边定义的sum函数,可以这样写:

1var result = sum(123, 456);

这样表示调用sum这个函数,并将123和456作为实参传递给函数,函数中会将两个参数求和并赋值给result

传递参数

JS中的所有的参数传递都是按值传递的。 也就是说把函数外部的值赋值给函数内部的参数,就和把值从一个变量赋值给另一个变量是一样的。

执行环境

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。 全局执行环境是最外围的一个执行环境。在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。 某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。 在内部环境可以读取外部环境的变量,反之则不行。

函数内部属性

在函数内部,有两个特殊的对象:

  • arguments:该对象实际上是一个数组,用于保存函数的参数。
  • thisthis引用的是一个对象。对于最外层代码与函数内部的情况,其引用目标是不同的。此外,即使在函数内部,根据函数调用方式的不同,引用对象也会有所不同。需要注意的是,this引用会根据代码的上下文语境自动改变其引用对象。

this引用的规则

在最外层代码中,this引用的是全局对象。 在函数内,this根据函数调用方式的不同而有所不同:

  • 构造函数:所生成的对象
  • 调用对象的方法:当前对象
  • applycall调用:参数指定的对象
  • 其他方式:全局对象(window

构造函数

构造函数是用于生成对象的函数,像之前调用的Object()就是一个构造函数。 创建一个构造函数:

1function MyClass(x, y) {
2  this.x = x;
3  this.y = y;
4}

调用构造函数: 构造函数本身和普通的函数声明形式相同。 构造函数通过new关键字来调用,new关键字会新创建一个对象并返回。 通过new关键字调用的构造函数内的this引用引用了(被新生成的)对象。

new关键字

使用new关键字执行一个构造函数时:

  1. 首先,会先创建一个空的对象。
  2. 然后,会执行相应的构造函数。构造函数中的this将会引用这个新对象。
  3. 最后,将对象作为执行结果返回。 构造函数总是由new关键字调用。 构造函数和普通函数的区别就在于调用方式的不同。 任何函数都可以通过new来调用,所以函数都可以是构造函数。 在开发中,通常会区分用于执行的函数和构造函数。 构造函数的首字母要大写。

属性的访问

在对象中保存的数据或者说是变量,称为是一个对象的属性。 读取对象的属性有两种方式:

  • 点访问:对象.属性名
  • 方括号访问:对象[属性名] 修改属性值也很简单:
  • 对象.属性名 = 属性值 删除属性:
  • delete 对象.属性名 constructor:每个对象中都有一个constructor属性,它引用了当前对象的构造函数。

垃圾回收

不再使用的对象的内存将会自动回收,这种功能称作垃圾回收。 所谓不再使用的对象,指的是没有被任何一个属性(变量)引用的对象。 垃圾回收的目的是,使开发者不必为对象的生命周期管理花费太多精力。

原型继承

JS是一门面向对象的语言,而且它还是一个基于原型的面向对象的语言。 所谓的原型实际上指的是,在构造函数中存在着一个名为原型的(prototype)对象,这个对象中保存着一些属性,凡是通过该构造函数创建的对象都可以访问存在于原型中的属性。 最典型的原型中的属性就是toString()函数,实际上对象中并没有定义这个函数,但是却可以调用,那是因为这个函数存在于Object对应的原型中。

设置原型

原型就是一个对象,和其他对象没有任何区别,可以通过构造函数来获取原型对象。

  • 构造函数.prototype 和其他对象一样可以添加修改删除原型中的属性,也可以修改原型对象的引用。 需要注意的是prototype属性只存在于函数对象中,其他对象是没有prototype属性的。 每一个对象都有原型,包括原型对象也有原型。特殊的是Object的原型对象没有原型。

获取原型对象的方法

除了可以通过构造函数获取原型对象以外,还可以通过具体的对象来获取原型对象。

  • Object.getPrototypeOf(对象)
  • 对象.proto
  • 对象.constructor.prototype 需要注意的是,可以获取到Object的原型对象,也可以对它的属性进行操作,但是不能修改Object原型对象的引用。

原型链

基于上边所说的,每个对象都有原型对象,原型对象也有原型对象。 由此,对象,和对象的原型,以及原型的原型,就构成了一个原型链。 比如这么一个对象:

1var obj = new MyClass(123, 456);

这个对象本身,原型MyClass.prototype,原型原型对象的原型对象是ObjectObject对象还有其原型。 这组对象就构成了一个原型链。 这个链的次序是:obj对象、obj对象原型、原型的原型(Object)、Object的原型。 当从一个对象中获取属性时,会首先从当前对象中查找,如果没有则顺着向上查找原型对象,直到找到Object对象的原型位置,找到则返回,找不到则返回undefined

instanceof

之前学习基本数据类型时学习了typeof用来检查一个变量的类型。 但是typeof对于对象来说却不是那么好用,因为任何对象使用typeof都会返回Object。而想要获取的是对象的具体类型。 这时就需要使用instanceof运算符了,它主要用来检查一个对象的具体类型。 语法:

1var result = 变量 instanceof 类型;

引用类型

上边说到JS中除了5种基本数据类型以外其余的全都是对象,也就是引用数据类型。 但是虽然全都是对象,对象的种类却是非常多的。 比如说过的Array(数组),Function(函数)这些都是不同类型的对象。 实际上在JavaScript中还提供了多种不同类型的对象。

Object

目前为止,看到的最多的类型就是Object,它也是在JS中使用的最多的对象。 虽然Object对象中并没有为提供太多的功能,但是会经常会用途来存储和传输数据。 创建Object对象有两种方式:

1var obj = new Object();
2var obj = {};

上边的两种方式都可以返回一个Object对象。 但是第一种使用了一个new关键字和一个Object函数。 这个函数就是专门用来创建一个Object对象并返回的,像这种函数称为构造函数。

Array

Array用于表示一个有序的数组。 JS的数组中可以保存任意类型的数据。 创建一个数组的方式有两种:

  • 使用构造器:
    1var arr = new Array(数组的长度);
    2var arr = new Array(123, 'hello', true);
  • 使用字面量:
    1var arr = [];
    2var arr = [123, 'hello', false];

读取数组中的值使用数组[索引]的方式,注意索引是从0开始的。

Date

Date类型用来表示一个时间。 Date采取的是时间戳的形式表示时间,所谓的时间戳指的是从1970年1月1日0时0秒0分开始经过的毫秒数来计算时间。 直接使用new Date()就可以创建一个Date对象。 创造对象时不传参数默认创建当前时间。可以传递一个毫秒数用来创建具体的时间。 也可以传递一个日期的字符串,来创建一个时间。 格式为:月份/日/年时:分:秒 例如:06/13/2004 12:12:12

Function

Function类型代表一个函数,每一个函数都是一个Function类型的对象。而且都与其他引用类型一样具有属性和方法。 由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。 函数的声明有两种方式:

1function sum() {}
2var sum = function() {};

由于存在函数声明提升的过程,第一种方式在函数声明之前就可以调用函数,而第二种不行。

函数也可以作为参数

函数也是一个对象,所以函数和其他对象一样也可以作为一个参数传递给另外一个函数。 但是要注意的是使用函数作为参数时,变量后面千万不要加括号,不加括号表示将函数本身作为参数,加上括号表示将函数执行的结果作为参数。

函数对象的方法

每个函数都有两个方法:callapplycallapply都可以指定一个函数的运行环境对象,换句话说就是设置函数执行时的this值。 使用方式:

1函数对象.call(this对象, 参数数组);
2函数对象.apply(this对象, 参数1, 参数2, 参数N);

闭包(closure)

闭包是JS一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。 因为函数是JS中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。 也可以将闭包的特征理解为其相关的局部变量在函数调用结束之后将会继续存在。

基本包装类型

基本数据类型是不能去调用方法的,所以JS中还提供了3个特殊的引用类型:BooleanNumberString。 这三个类型分别包装了Boolean、Number、String并扩展了许多实用的方法。 他们的使用方式和普通的对象一样。 要注意的是使用typeof检查这些包装类型时返回的都是object

Boolean

Boolean类型是与布尔值对应的引用类型。 可以采用这种方式创建:

1var booleanObject = new Boolean(true);

最好永远不要使用Boolean包装类。

Number

Number是数值对应的引用数据类型。创建Number对象只需要在调用构造函数时传递一个数值:

1var num = new Number(20);

使用数值时建议使用基本数值,而不建议使用包装类。

String

String类型是字符串的对象包装类型,可以像下面这样使用String构造函数来创建:

1var str = new String("hello world");

可以使用length属性来获取字符串的长度。

Math

JS还为保存数学公式和信息提供了一个公共位置,即Math对象。 与在JavaScript直接编写的计算功能相比,Math对象提供的计算功能执行起来要快得多。 Math对象中还提供了辅助完成这些计算的属性和方法。

Math对象的属性

  • Math.E:自然对数的底数,即常量e的值。
  • Math.LN10:10的自然对数。
  • Math.LN2:2的自然对数。
  • Math.LOG2E:以2为底e的对数。
  • Math.LOG10E:以10为底e的对数。
  • Math.PI:圆的值。
  • Math.SQRT1_2:1/2的平方根(即2的平方根的倒数)。
  • Math.SQRT2:2的平方根。

Math的方法

  • 最大最小值:Math.max()获取最大值,Math.min()获取最小值。
  • 舍入:
    • 向上舍入:Math.ceil()
    • 向下舍入:Math.floor()
    • 四舍五入:Math.round()
  • 随机数:Math.random()
  • 选取某个范围内的随机值:
    1 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

三、 DOM

什么是DOM

DOM,全称Document Object Model文档对象模型。JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲的操作WEB页面。

模型

  • 文档:表示的就是整个的HTML网页文档。
  • 对象:表示将网页中的每一个部分都转换为了一个对象。
  • 模型:使用模型来表示对象之间的关系,这样方便获取对象。
1<html>
2<head>
3<title>网页的标题</title>
4</head>
5<body>
6<a href="1.html">超连接</a>
7</body>
8</html>
  • html:文档节点
  • head:元素节点
  • title:文本节点
  • body:元素节点
  • a:元素节点

节点

节点Node,是构成网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点。 比如:html标签、属性、文本、注释、整个文档等都是一个节点。 虽然都是节点,但是实际上他们的具体类型是不同的。 比如:标签称为元素节点、属性称为属性节点、文本称为文本节点、文档称为文档节点。 节点的类型不同,属性和方法也都不尽相同。

节点的类型

  • 节点:Node
    • 构成HTML文档最基本的单元。
    • 常用节点分为四类:
      • 文档节点:整个HTML文档
      • 元素节点:HTML文档中的HTML标签
      • 属性节点:元素的属性
      • 文本节点:HTML标签中的文本内容

节点的属性

节点类型 nodeName nodeType nodeValue
文档节点 #document null
元素节点 标签名 null
属性节点 属性名 属性值
文本节点 #text 3 ★文本内容

文档节点(document)

文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点。 document对象作为window对象的属性存在的,不用获取可以直接使用。 通过该对象可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。

元素节点(Element)

HTML中的各种标签都是元素节点,这也是最常用的一个节点。 浏览器会将页面中所有的标签都转换为一个元素节点,可以通过document的方法来获取元素节点。 比如 :

  • document.getElementById(),根据id属性值获取一个元素节点对象。

文本节点(Text)

文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点。 它包括可以字面解释的纯文本内容。 文本节点一般是作为元素节点的子节点存在的。 获取文本节点时,一般先要获取元素节点。在通过元素节点获取文本节点。 例如:

  • 元素节点.firstChild,获取元素节点的第一个子节点,一般为文本节点。

属性节点 (Attr)

属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。 可以通过元素节点来获取指定的属性节点。 例如:

  • 元素节点.getAttributeNode(“属性名”)。 注意:一般不使用属性节点。

事件

事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。 JavaScript 与HTML之间的交互是通过事件实现的。 对于Web应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,等等。

获取元素节点

通过document对象调用

  1. getElementById()
    • 通过id属性获取一个元素节点对象。
  2. getElementsByTagName()
    • 通过标签名获取一组元素节点对象。
  3. getElementsByName()
    • 通过name属性获取一组元素节点对象。

获取元素节点的子节点

通过具体的元素节点调用

  1. getElementsByTagName()
    • 方法,返回当前节点的指定标签名后代节点。
  2. childNodes
    • 属性,表示当前节点的所有子节点。
  3. firstChild
    • 属性,表示当前节点的第一个子节点。
  4. lastChild
    • 属性,表示当前节点的最后一个子节点。

获取父节点和兄弟节点

通过具体的节点调用

  1. parentNode
    • 属性,表示当前节点的父节点。
  2. previousSibling
    • 属性,表示当前节点的前一个兄弟节点。
  3. nextSibling
    • 属性,表示当前节点的后一个兄弟节点。

元素节点的属性

获取,元素对象.属性名 例 : element.value, element.id, element.className。 设置,元素对象.属性名=新的值 例 : element.value = “hello”, element.id = “id1”, element.className = “newClass”。

其他属性

  • nodeValue
    • 文本节点可以通过nodeValue属性获取和设置文本节点的内容。
  • innerHTML
    • 元素节点通过该属性获取和设置标签内部的html代码。

使用CSS选择器进行查询

querySelector()querySelectorAll() 这两个方法都是用document对象来调用,两个方法使用相同,都是传递一个选择器字符串作为参数,方法会自动根据选择器字符串去网页中查找元素。 不同的地方是querySelector()只会返回找到的第一个元素,而querySelectorAll()会返回所有符合条件的元素。

节点的修改

这里的修改主要指对元素节点的操作

  • 创建节点:document.createElement(标签名)
  • 删除节点:父节点.removeChild(子节点)
  • 替换节点:父节点.replaceChild(新节点,旧节点)
  • 插入节点:
    • 父节点.appendChild((子节点))
    • 父节点.insertBefore(新节点,旧节点)

四、 事件

关于事件实际上已经初步接触过了,指的就是用户与浏览器交互的一瞬间。 通过为指定事件绑定回调函数的形式来处理事件,当指定事件触发以后回调函数就会被调用,这样页面就可以完成和用户的交互了。 这里还要更加深入的聊一聊事件的其他内容。

事件处理程序

可以通过两种方式为一个元素绑定事件处理程序:

  1. 通过HTML元素指定事件属性来绑定
  2. 通过DOM对象指定的属性来绑定 这两种方式都是日常用的比较多的,但是更推荐使用第二种方式。 还有一种方式比较特殊称为设置事件监听器。使用如下方式:
1元素对象.addEventListener();

通过HTML标签的属性设置

通过HTML属性来绑定事件处理程序是最简单的方式

1<button onclick="alert('hello');alert('world')">按钮</button>

这种方式当点击按钮以后,onclick属性中对应的JS代码将会执行,也就是点击按钮以后,页面中会弹出两个提示框。 这种方式直接将代码编写到了onclick属性中,可以编写多行js代码,当然也可以事先在外部定义好函数。 这种方式的优点在于,设定步骤非常简单,并且能够确保事件处理程序会在载入时被设定。 如果在函数的最后return false则会取消元素的默认行为。

通过DOM对象的属性绑定

但是其实上面的写法虽然简单,但却将JS和HTML的代码编写到了一起,并不推荐使用,更推荐如下的写法:

1var btn = document.getElementById('btn');
2btn.onclick = function() {
3  alert("hello");
4};

这种写法将HTML代码和JS写在不同的位置,维护起来更加容易。

设置事件监听器

前边两种方式都可以绑定事件处理程序,但是它们都有一个缺点就是都只能绑定一个程序,而不能为一个事件绑定多个程序。 这时就可以可以使用addEventListener来处理,这个方法需要两个参数:一个是事件字符串,一个是响应函数

1btn.addEventListener('click', function() { alert("hello"); });

但是要注意的是ie8以下的浏览器是不支持上边的方法的,需要使用attachEvent代替。 也可以使用removeEventListenerdetachEvent移除事件。

事件处理中的this

在事件处理程序内的 this 所引用的对象即是设定了该事件处理程序的元素。 也就是事件是给那个对象绑定的this就是哪个对象。

事件对象

在DOM对象上的某个事件被触发时,会产生一个事件对象Event,这个对象中包含看所有事件有关的信息。 包括导致事件的元素、事件的类型以及其其他与特定事件相关的信息。 例如,鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含与按下的键有关的信息。 所有浏览器都支持event对象,但支持方式不同。

DOM标准的浏览器会将一个event对象传入到事件的处理程序当中。 无论事件处理程序是什么都会传入一个event对象。 可以通过这种方式获取:

1btn.onclick = function(event) {
2  alert(event.type);
3};

Event对象包含与创建它的特定事件有关的属性和方法。 触发的事件类型不一样,可用的属性和方法也不一样。

Event对象的通用属性/方法

属性/方法 类型 读/写 说明
bubbles Boolean 只读 事件是否冒泡
cancelable Boolean 只读 是否可以取消事件的默认行为
currentTarget Element 只读 当前正在处理的事件元素
defaultPrevented Boolean 只读 是否调用了preventDefault()
detail Number 只读 与事件相关的细节信息
eventPhase Number 只读 阶段1捕获2:目标3:冒泡
preventDefault() Function 只读 取消事件的默认行为
stopImmediatePropagation() Function 只读 取消事件的进一步捕获或冒泡
stopPropagation() Function 只读 取消事件的进一步捕获或冒泡
target Element 只读 事件的目标
trusted Boolean 只读 是否是浏览器内置事件
type String 只读 被触发的事件的类型

IE中的事件对象

与访问 DOM 中的 event 对象不同,要访问 IE 中的event对象有几种不同的方式,取决于指定事件处理程序的方法。 在IE中event对象作为window对象的属性存在的,可以使用window.event来获取event对象。 在使用attachEvent()的情况下,也会在处理程序中传递一个event对象,也可以按照前边的方式使用。

Event对象的通用属性/方法 (IE)

属性/方法 类型 读/写 说明
cancelBubble Boolean 读/写 是否取消冒泡
returnValue Boolean 读/写 是否执行默认行为
srcElement Element 只读 事件的目标
type String 只读 被触发的事件的类型

事件的触发

事件的发生主要是由用户操作引起的。 比如mousemove这个事件就是由于用户移动鼠标引起的,在鼠标指针移动的过程中该事件会持续发生。 当指定事件被触发时,浏览器就会调用对应的函数去响应事件,一般情况下事件没触发一次,函数就会执行一次。 因此设置鼠标移动的事件可能会影响到鼠标的移动速度。 所以设置该类事件时一定要谨慎。

事件的传播

在网页中标签与标签之间是有嵌套关系的,比如这样一个页面:

1<html>
2<body>
3<div id="foo">
4<button id="bar">sample</button>
5</div>
6</body>
7</html>

如果这时用户点击了sample按钮,则会以该按钮作为事件目标触发一次点击事件。 这时,事件的处理将会分为捕获阶段、目标阶段、事件冒泡这三个阶段。

事件的传播流程

  1. 捕获阶段

    • windowdocument → …
    • 捕获阶段:这一阶段会从window对象开始向下一直遍历到目标对象,如果发现有对对象绑定了响应事件则做相应的处理。
  2. 事件冒泡阶段

    • htmlbodydivbutton
    • 点击事件的触发
    • 事件冒泡阶段:这一阶段,事件的传播方式和捕获阶段正好相反,会从事件目标一直向上遍历,直至window对象结束,这时对象上绑定的响应函数也会执行。
  3. 目标阶段

    • 目标阶段:这一阶段已经遍历结束,则会执行目标对象上绑定的响应函数。

取消事件传播

可以使用event对象的两个方法完成:

  • stopPropagation()
  • stopImmediatePropagation() 取消默认行为:
  • preventDefault()

五、 BOM

什么是BOM

ECMAScript无疑是JavaScript的核心,但是要想在浏览器中使用JavaScript,那么BOM(浏览器对象模型)才是真正的核心。 BOM提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。 BOM将浏览器中的各个部分转换成了一个一个的对象,通过修改这些对象的属性,调用他们的方法,从而控制浏览器的各种行为。

window对象

window对象是BOM的核心,它表示一个浏览器的实例。 在浏览器中可以通过window对象来访问操作浏览器,同时window也是作为全局对象存在的。

全局作用域:

window对象是浏览器中的全局对象,因此所有在全局作用域中声明的变量、对象、函数都会变成window对象的属性和方法。

窗口大小

浏览器中提供了四个属性用来确定窗口的大小:

  • 网页窗口的大小:innerWidthinnerHeight
  • 浏览器本身的尺寸:outerWidthouterHeight

打开窗口

使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。 这个方法需要四个参数:

  • 需要加载的url地址
  • 窗口的目标
  • 一个特性的字符串
  • 是否创建新的历史记录

超时调用

超时调用:

1setTimeout()

一超过一定时间以后执行指定函数,需要两个参数:

  • 要执行的内容
  • 超过的时间

取消超时调用:

1clearTimeout()

超时调用都是在全局作用域中执行的。

间歇调用

间歇调用:

1setInterval()

一每隔一段时间执行指定代码,需要两个参数:

  • 要执行的代码
  • 间隔的时间

取消间隔调用:

1clearInterval()

系统对话框

浏览器通过alert()confirm()prompt()方法可以调用系统对话框向用户显示消息。 它们的外观由操作系统及(或)浏览器设置决定,而不是由CSS决定。 显示系统对话框时会导致程序终止,当关闭对话框程序会恢复执行。

alert

1alert("Hello World");

alert()接收一个字符串并显示给用户。 调用alert()方法会向用户显示一个包含一个确认按钮的对话框。

confirm

confirm和alert类似,只不过confirm弹出的对话框有一个确认和取消按钮。 用户可以通过按钮来确认是否执行操作。

1confirm("你确定吗?")

这个函数的执行会返回一个布尔值,如果选择确定则返回true,如果点击取消则返回false。

prompt

prompt会弹出一个带输入框的提示框,并可以将用户输入的内容返回。 它需要两个值作为参数:

  • 显示的提示文字
  • 文本框中的默认值
1prompt("你的年龄是?", 18)

例子:

  • 你的年龄是?
  • 18

location对象

location对象提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。

  • href属性:href属性可以获取或修改当前页面的完整的URL地址,使浏览器跳转到指定页面。
  • assign()方法:所用和href一样,使浏览器跳转页面,新地址错误参数传递到assign()方法中。
  • replace()方法:功能一样,只不过使用replace方法跳转地址不会体现到历史记录中。
  • reload()方法:用于强制刷新当前页面。

navigator对象包含了浏览器的版本、浏览器所支持的插件、浏览器所使用的语言等各种与浏览器相关的信息。 有时会使用navigator的userAgent属性来检查用户浏览器的版本。

screen对象

screen对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。 该对象作用不大,一般不太使用。

history对象

history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。

  • go():使用go()方法可以在用户的历史记录中任意跳转,可以向后也可以向前。
  • back():向后跳转。
  • forward():向前跳转。

document

document对象也是window的一个属性,这个对象代表的是整个网页的文档对象。 对网页的大部分操作都需要以document对象作为起点。 关于document对象的内容,后边还要具体讲解。