文章目录
1、JavaScript的完整组成*
- ECMAScript,描述了该语言的语法和基本对象。
- 文档对象模型(DOM),描述处理网页内容的方法和接口。
- 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口。
ECMAScript【js标准】
由单行注释与块注释( // 、/**/)、变量、操作符、流程控制语句、数组、对象、函数、正则表达式等构成的标准。目前基本所有的js解释器都可以兼容ECMAScript。
DOM文档对象模型【document object model】
简单来说就是使用JavaScript操作html的API,是针对XML但经过扩展用于HTML的应用程序编程接口。DOM将整个页面映射成一个多节点结构。
例如:
var dom=document.getElementsByTagName(“input”);
var dom=document.getElementById(“input_name”);
dom.οnclick=function(){}
BOM浏览器对象模型【Browser Object Model】
简单来说就是使用JavaScript操作浏览器的API,开发人员可以使用BOM控制浏览器显示的页面以外的部分。
例如:
弹出新浏览器窗口;移动,缩放,关闭浏览器的功能;提供浏览器详细信息的navigator对象;提供浏览器所加载页面的详细信息的location对象;提供用户显示器分辨率详细信息的screen对象;对cookies的支持;支持XMLHttpRequest,IE中的ActiveXObject自定义对象
如:
alert()/prompt()/confirm()
setInterval()/setTimeout()
XMLHttpRequest,Ajax
需要注意的是:只有ECMAScript是标准,也就是在绝大多数浏览器以及js解析器(node)中运行效果相同,但是DOM与BOM是各大浏览器厂商自己提供的API,在使用上大同小异,但是也可能会出现少许不兼容的情况
2、JavaScript的特点
1、顺序解释执行的脚本语言
它的基本结构形式与c、c++、java十分类似。但它不像这些语言一样,需要先编译,而是==在程序运行过程中被逐行地解释。==它是需要嵌入到html页面中,让浏览器来解释执行的。
2、基于对象的语言
javascript是一种基于对象的语言,在程序中可以创建对象
3、简单性
它是一种基于java基本语法语句和控制流之上的简单而紧凑的设计, 基本java中的语法都可以使用
到javascript中,所以对于学过java语言的情况下,学习javascript也相对比较简单
4、弱类型语言
它的语法松散要求不严谨,比如一个变量在之前没有声明的情况下就可以直接使用,声明变量的时候也可以不声明变量的类型等
5、事件驱动
在页面上的操作,例如 左键/右键的单击、双击,键盘上面的按键的监听,鼠标的移动、鼠标拖拽、鼠标滚轴的滚动等等事件的响应处理都可以交给JavaScript
6、动态性
JavaScript可以直接对用户或客户输入做出响应,无须经过web服务程序
7、安全性
JavaScript不允许访问本地的硬盘,并不能将数据存入到服务器上,不允许对网络文档进行修改和
删除,只能通过浏览器实现信息浏览或动态交互。从而有效地防止数据的丢失
8、跨平台性
JavaScript是依赖于浏览器本身,与操作环境无关,只要能运行浏览器的计算机,并支持javascript
的浏览器就可正确执行。但是不同浏览器以及同一浏览器的不同版本对JavaScript的支持是不同的
(浏览器的兼容性)
3、JavaScript的作用
1、动态改进网页的设计布局(操作页面中的标签元素)
2、验证表单
3、检测浏览器、控制浏览器的行为
4、创建cookies
5、处理页面中触发的事件
6、在使用ajax的时候也要用到JavaScript
4、JavaScript的位置
4.1 内部样式
js中的内容写在< script > < /script >标签之间,而script标签又放置在< body > 或者 < head >标签中,例如:
1、写在head标签中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>first</title>
<!-- JavaScript写在head标签中 -->
<script type="text/javascript">
document.write("hello world");
</script>
</head>
<body>
</body>
</html>
2、写在body标签中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>second</title>
</head>
<body>
<!-- JavaScript写在body中 -->
<script type="text/javascript">
document.write("hello world");
</script>
</body>
</html>
补充:
在body中和在head中使用JavaScript的区别
在body部分中的JavaScript会在页面加载的时候被执行,在head部分中的JavaScript会在被调用的时候才执行。
因为浏览器解析html是从上到下的。如果把JavaScript放在head里的话,则先被解析,但这时候body还没有解析,所以会返回空值。一般都会绑定一个监听,当全部的html文档解析完之后再执行代码,例如:windows.onload = function(){// 这里放执行的代码}
,这就说明,如果我们想定义一个全局对象,而这个对象是页面中的某个按钮时,我们必须将其放入body中,道理很明显:如果放入head,那当你定义的时候,那个按钮都没有被加载,可能获得的是一个undefind值,所以一般习惯将JavaScript放在body的最后面。
3、 写在标签元素的事件属性中
<div onclick="javascript:alert('hello world')"></div>
4.3 外部样式
类似于css样式表的引用(写在外部的js文件中,在HTMl中引用外部js文件)
HTML文件
<script type="text/javascript" src="test.js"></script>
test.js文件
document.write("hello world");
5、JavaScript中的注释
与绝大多数语言类似,JavaScript也需要注释来说明其代码含义,或者用来进行代码调试,注释后的代码会被浏览器忽略不被执行。
(1)单行注释:
//注释内容
(2)块注释(多行注释)
/*
注释内容
*/
6、Javascript中的变量和数据类型
6.1 变量
变量是一个值的容器,该容器的值可以随时改变。ECMAScript的变量是弱类型(松散类型),可以用来保存任何类型的数据。
定义变量使用var关键字,也就是说任何类型的变量都可以使用var关键字来声明。
关键字与保留字
关键字:在js中有特殊功能的字词,目前常见的有break,do,try,typeof,case,if,else等。。。
保留字:未来可能成为关键字的字词,例如:package,abstract等,因为在不断改变,所以就不一一列举了
变量的命令规则
1、区分大小写
如:typeof是关键字,typeOf就与typeof不同,非关键字
2、标识符规则
标识符指变量,函数,属性的名字或者函数的参数,是按照以下规则组合起来的一或多个字符:
1、字母,数字,下划线,$ 组成
2、只能以字母、下划线、$ 开头
3、不能将关键字作为标识符
4、命名采用驼峰式命名(即当标识符有多个单词组成时,第一个单词首字母小写,后面单词的首字母均大写),例如:numberOfPeople
变量的使用
(1)声明变量
var 变量名;
(2)变量初始化
变量名 = 变量值;
(3)声明的同时初始化变量
var 变量名 = 变量值;
(4)声明多个变量(中间用逗号隔开)
var 变量名1 = 变量值1,变量名2 = 变量值2;
js中变量的特点
1、js中变量通常的使用分为如下三步:
//变量声明
var a;
//变量初始化
a = 3;
//变量调用
console.log(a);
2、由于js时弱类型语言,所以具有弱类型语言变量的特点:
- 变量的数据类型在初始化的时候确定
- 变量的数据类型可以随时发生改变
- 类型细分不明显
3、变量可以重复声明:
看如下案例:
var a = 3; //这里的a是整数类型
var a = "hello world"; //这里的a是字符串类型
4、变量值更新
var b = 20;
b = "js";
5、变量的声明提升
例如:
console.log(a); //undefined
var a = 3;
等价于如下
var a;
console.log(a); //undefined
a = 3;
在所有代码执行之前,js解释器会将js中所有的var声明的变量提升。 可以看到原本的var a = 3被拆分成了两个部分,var a声明部分和a = 3变量初始化部分,并且声明部分被提到了最前面,这就是"声明提升",而因为声明提前,赋值语句又在console语句的后面,所以输出的是undefined
6、var声明的变量的作用域
分析下面几个例题和注释可帮助理解:
补充,对于函数声明也会提前,并且函数声明会在变量声明的前面,具体请看这篇:
函数
(1)例题一:var 的变量声明提前只会提升到当前作用域的最前面
//这是函数,命名为foo
function foo(){
if(true){
var a = 3; //局部变量
console.log("inner",a);//inner 3
}
console.log("outer",a);//outer 3
}
foo();
console.log(a);//error!
分析:
(1)是把函数foo中if语句中的a变量的声明与初始化分开,把a变量的声明提前到了函数的最前面,if语句中留下的是变量的初始化,赋值为3,因为声明提前了,作用域为当前函数之内,也就是函数foo的括号之间,所以在if语句外的语句console.log("outer",a)
也处于a变量的声明范围之内,而在if语句中初始化a=3,所以if语句外的console.log("outer",a);
的变量a的值也是3。
(2)处于函数foo外的console.log(a);
不在局部变量a的作用域范围之内,且在自身的作用域内并没有进行变量的声明和初始化,所以会报错。
上面的代码相当于:
function foo(){
var a; //声明局部变量
if(true){
a = 3; //给变量赋值
console.log("inner",a);//inner 3
}
console.log("outer",a);//outer 3
}
foo();
//console.log(a);//error!
(2)例题二:如果在函数中定义变量没有加var,该变量为全局变量
function test(){
message = "hello";
}
test(); //调用方法后message被赋值hello
console.log(message); //hello
相当于:
var message;
function test(){
message = "hello";
}
test(); //调用方法后message被赋值hello
console.log(message); //hello
(3)例题三:用var操作符定义的变量将成为定义该变量的作用域中的局部变量
function b() {
a = 10;
return;
}
var a = 1;
b(); //b函数调用
console.log(a);//10
分析:
同样的,a是全局变量,调用b函数的时候又对a进行了赋值,根据变量可以重复赋值的规则,b函数调用过程中将原本a中存的值给替换掉了,所以导致输出的结果为函数b中的变量的值10。
(4)例题四:this关键字可以调用全局变量
x = 1;//window.x global.x 这是全局对象,也相当于全局变量var a = 1;
console.log(x); //1
function y() {
console.log(x); //undefined
console.log(this.x);//1,需要通过this关键字来调用全局对象
var x = 2;
console.log(x); //2 通过局部变量重新赋值x = 2;
}
y();
console.log(x); //1
分析:
(1)最外层的x=1是个全局变量,全局可以使用
(2)对于y函数中的第一个输出语句,函数中的var x = 2;
是一个局部变量,并且它其实被拆成了声明和赋值两个部分,而且声明被提升到了函数作用域的最前面,此时还未对局部变量进行赋值操作,所以导致第一个输出语句为undefined
(3)y函数中的第二个输出语句通过this关键字可以调用到全局对象,所以输出为0
(4)y函数中第三个输出语句之前定义了局部变量x并进行了赋值,所以输出为2,但该赋值只在y函数作用域内生效
(5)最后一个输出语句并没有被y函数中的局部变量赋值所影响,所以输出值为全局变量x的值
(5)例题五
//函数作用域:局部作用域
var a = 1; //全局变量
function b() {
a = 10; //局部变量
return;
//a函数声明,提前变量a,将a认为是函数b作用域的变量,具有局部效果
function a(){}
}
b();
console.log(a); // 1
6.2 数据类型
JavaScript中常见数据类型
基本类型:字符串(String)、数字(Number)、布尔类型(Boolean),对空(Null)、未定义(Undefined)、Symbol。。
引用类型:对象(Object)、数组(Array)、函数(Fuction)
补充:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
Java中的字符串是引用类型,别搞混了
Javascript中的动态类型意味着相同的变量可用作不同的类型,如下:
var x; // x 为 undefined
var x = 5; // 现在 x 为数字
var x = "John"; // 现在 x 为字符串
6.2.1 基本数据类型
字符串String
字符串是存储字符(比如 “Bill Gates”)的变量。字符串可以是引号中的任意文本,引号可以是单引号,也可以是双引号。如下:
var carname='Volvo XC60';
var carname="Volvo XC60";
补充:可以在字符串中使用引号,只要不匹配包围字符串的引号即可。
可以使用字符字面量,转义字符,如下:
\n 换行 \t 制表 \b 退格
\r 回车 \ 斜杠 ’ 单引号
" 双引号
字符长度可通过length属性获取字符长度,如下:
var str = "我是字符串";
console.log(str);
console.log(str.length);
var s4='\n\t\b\r';
字符串中的内置函数
var s = "hello world";
//获得字符串的长度
console.log(s.length);
//从下标为3的位置开始,截取4个字符,包括下标为3的位置的字符
console.log(s.substr(3,4));
//从下标为6的位置开始截取,截取到下标为8的位置,但是不包括下标为8的字符[6,8)
console.log(s.substring(6,8));
//trim()去掉字符串俩边的空格,但是这个方法有可能浏览器不支持.
console.log(s.trim().length);
//字符串转换为大写
console.log(s.toUpperCase());
//字符串转换为小写
console.log(s.toLowerCase());
//分割字符串 返回一个数组
console.log(s.split(" "));
console.log(s.split(" ").length);
console.log(s.split(" ")[0]);
console.log(s.split(" ")[1]);
数字Number
JavaScript 只有一种数字类型,所有的数字同意使用Number来表示,也就是说无论你是整数(int)、浮点数(单精度float、双精度浮点double),还是说你是二进制(Binary)、八进制(Octal)、十进制(decimal system),十六进制(Hexadecimal)都只用Number来表示。
var num1 = 34; //不使用小数点来写
var num2 = 010; //8
var num3 = 0x10; //16
console.log(num1,num2,num3);
var f1 = 3.1415926; //3.1415926
var f2 = 3.125e7; //31250000 //科学计数法
console.log(f1, f2);
数值检测
为甚要进行数值检测?
例如:var result = 10 / 'a';
结果肯定是不能求出来的,再例如,如果一个数的结果超过了JavaScript的数值取值范围,那么同样也不能够表示出来。什么是Nav?
JavaScript中如果一个本来要返回数值的操作数未返回数据那么结果就用NaN来表示;
判断返回结果是否为非数值的方法:
isNaN(变量); //如果不是数值,那么返回值为true,否则为false
数值范围:
由于内存的限制,ECMAScript不能保存世界上所有的数值。
ECMAScript能表示的最小数值保存在Number.MIN_VALUE中
能表示的最大的数值保存在Number.MAX_VALUE中。
如果某次计算的结果超过了JavaScript数值范围,将会返回Infinity(正无穷)或者-Infinity(负无穷)
数值范围检测
使用 isFinite()函数可以判断参数是否在最大值和最小值之间,如果在,返回true
布尔类型boolean
布尔(逻辑)只能有两个值:true 或 false,对应数字1和0
空Null
该类型的取值只有一个,即null。null可以表示一个空对象的指针。
怎么用:如果一个变量准备将来保存对象,可以将该变量初始化null而不是其他,这样可以通过检查null值就可以知道相应的变量是否已经保存了一个对象的引用。
未定义Undefined
Undefined 这个类型表示变量不含有值、未定义的、未进行初始化赋值的。
如:
var a;
console.log(a,typeof a);//undefined 'undefined'
//typeof用来判断a的数据类型
undefined与null的关系和区别
undefined继承null,所以undefined == null结果为true,但是null表示空对象,undefined表示未定义;
null与undefined用途不同,null可以用来表示一个空对象,但是没有必要把一个变量的值显式设置为undefined。
====================================
一般基本类型自身是不带有任何方法的,但Boolean、String、Number这三个基本数据类型为什么会可以调用方法呢?这与其对应的基本包装类型有关,具体请看这基本包装类型介绍
6.2.2 引用数据类型简介
在js中除了以上基本数据类型,其他所有类型都可以归结为引用数据类型,这里简单介绍下
对象Object
对象是模拟现实生活的对象,对象由键值对组成,通过使用大括号将所有键值对括起来。
javaScript中已经存在的类型的对象有:
var v = new Date();
var obj1 = new Object();//Object 对象
var obj2 = {};
var arr1 = new Array();//Array 对象
var arr2 = [];
var boo1 = new Boolean(true), boo2 = true;//Boolean 对象
var num1 = new Number(123), num2 = 123.45;//Number 对象
var str1 = new String("abc"), str2 = 'abc';//String 对象 12345678910
自定义对象:
格式:
var 对象名 = {
属性1: 属性值1,
属性2: 属性值2
}
例如:
var dog = {
name: 'momo',
age: 4
}
获取对象的属性:格式:
对象名.属性名
数组Array
数组是一个特殊的对象,包含了多个值,值与值之间使用逗号分隔开,所有的值通过中括号括起来。
var classArr = ['web2104','web2105','web2106']
var studentArr = ['zhangsan','lisi','wangwu']
可以通过数组下标获取对应的数据
classArr[0]; // web2104
函数Function
函数是代码执行单元,用于实现某些特殊的功能。
function sum(a, b) {
return a + b;
}
//执行函数
sum(1,2); // 3
基本数据类型和引用数据类型在内存中的存储方式
对于基本类型:
基本类型的变量和数值都保存在栈区。
例如:
//b直接将a的值存入,所以变量a和b的取值都一样
var a = 123;
b = a;
内存如图:
更改b的值为456时,并不会同时改变a中的取值,也就是说基本数据类型的值存储在栈中,并且值与值之间独立存在,修改一个值不会影响其他变量
对于引用类型:
引用类型存储的值是对象的地址,而这个对象在创建时是存储在内存的堆区中的。通过存储在栈区的地址来找到堆区中对应的对象。
//定义一个对象obj1
var obj1 = {
name: 'zhangsan'
}
//定义一个对象obj2,并将对象obj1赋值给对象obj2
var obj2 = obj1;
//输出两个对象的结果都相同
console.log(obj1.name); //zhangsan
console.log(obj2.name); //zhangsan
// 如果此时修改obj1的name
// 当obj1属性name变为"lisi"时,obj2属性name也变为"lisi"
obj1.name = 'lisi';
console.log(obj1.name); //lisi
console.log(obj2.name); //lisi
内存图如下:
分析:对象ojb1和obj2将真正的值存放在堆内存中,而在栈内存中存储的值是真正的值所对应的地址。
补充:深拷贝与浅拷贝
主要针对于引用数据类型参数说的,浅拷贝表示仅拷贝引用地址,深拷贝表示对于对象的克隆。
实现深拷贝的方法
- 通过json对象实现深拷贝(JSON.stringify,JSON.parse)
- Object.assign()拷贝
- lodash函数库实现深拷贝
- 递归的方式实现深拷贝