JavaScript基础
JavaScript ( JS )诞生于 1995年 ,是一种具有函数优先的轻量级, 解释型的编程语言。
编译型语言是指运行之前将所有内容编辑后才开始运行,解释型语言是指在执行过程中进行编译。
JavaScript 标准 由ECMA制定(ECMA-262),维护组织为TC-39:ECMAscript发展委员会
ECMAscript规定了JS编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准。
JavaScript和ECMAscript:JavaScript是ECMAscript的实现,ECMAscript是JavaScript的标准。
JavaScript和Java没有关系。
ES6是JavaScript的一个版本(ES2015之后的版本统称为ES6)
JavaScript工作原理
采用单线程模式
的嵌入式脚本语言 (运行在浏览器,node环境)
初期,设计初衷为运行在浏览器端的脚本语言(操作dom)
采用单线程方式(同一时间只能做一件事),执行代码的线程只有一个,任务是需要排队的,如果某一个任务执行时间长,就会出现阻塞
。
假设为多线程,可能会出现多个线程同时操作同一个dom的问题。
为解决阻塞问题,可以采用异步方式,setTimeOut某一些功能需要等待多长时间后执行 ;Ajax 通常也为异步,数据回来的时间不一定
JavaScript执行机制
- 先执行执行栈中的同步任务;
- 异步任务(回调函数)放入任务队列中;
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,则被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获取任务,执行任务,再获取任务,再执行,所以这种机制被称为事件循环
同步模式,代码按顺序执行
,函数在调用时才会执行,代码被压入执行栈,执行后销毁,将结果输出到控制台;同一时间只能做一件事情。
同步任务都在主线程上执行,形成一个执行栈。
异步模式,异步消息压入(web api/node api)内部环境,一定时间后(按实际顺序)执行,执行时压入消息队列
中,事件循环时刻检查消息队列中是否有消息,检测到有消息时,按顺序将消息压入执行栈中,销毁打印。同一时间可以做多件事情(一件事情的执行时间较长时,可以先执行下一件事情)。
异步任务放在消息队列中。
JS的异步是通过回调函数
实现的。
异步任务主要有以下三种类型:
-
普通事件:如click,resize等;
-
资源加载:如load,error等;
-
定时器:setTimeout,setInterval等。
异步不会影响同步执行。console.log(1); setTimeout(function(){ console.log(3); },2000); console.log(2); // 1 2 3
console.log(1);
setTimeout(function(){
console.log(3);
},0);
console.log(2); //1 2 3 先执行同步任务,再执行异步任务
浏览器执行js:
浏览器分为两部分:渲染引擎和JS引擎,JS引擎也称为JS解释器,用来读取网页中的JavaScript代码,对其处理后进行运行。
浏览器本身并不会执行JS代码,是通过内置的JS引擎执行JS代码,JS引擎执行代码时逐行解释每一句源码,将其转换为机器语言,由计算机去执行。
js垃圾回收机制
主要解决内存泄露问题,内存泄露的含义是某些不需要的变量还存在内存
内存泄露:内存中存在一些不再需要的变量(垃圾,占用内存)
垃圾回收机制:间隔的不定期的寻找不再使用的变量,并释放。
两种方式:标记清除,引用计数
被视为垃圾的情况: 没有被引用的变量,几个对象相互引用形成闭环。
不会被视为垃圾的情况:全局变量(时刻待命),有具体的引用关系(证明有用,闭包)。
在函数功能体中,每一次执行完毕后,不被引用的变量会被销毁。
function test(){
//在函数的功能体中,每次执行完毕后,不被引用的变量会被回收
var num=0;
console.log(++num);
}
test(); //1
test(); //1
test(); //1
JavaScript的组成
ECMAScript(JavaScript语法)
DOM(页面文档对象模型,js操作html的api),通过DOM提供的接口可以对页面上的各种元素进行操作。
BOM(浏览器对象模型,js操作浏览器的api),独立于内容,开发人员可以使用BOM控制浏览器显示的页面以外的部分,操作浏览器窗口
JavaScript的特点
-
具有两面性:
可以在浏览器端运行: 使网页更丰富;进行表单验证(使用正则表达式);发送ajax请求;操作cookie;处理数据;dom/bom 操作;
也可以在nodejs(服务器端)运行:后端开发;提供项目接口. -
解释性语言
被内置于浏览器或者NodeJS平台中的JS解析器解析执行,执行前无需编译。 -
弱类型语言 声明变量时,不需要指定他的数据类型,而变量的数据类型取决于赋值时值的数据类型(var a;), 且变量的数据类型可以随时发生改变
-
从上往下顺序解析执行。
当把JavaScript引入代码放在头部时,因为代码是逐行进行的,所以body内的代码获取不到元素,需要放在body的底部
<head>
<script src="./js/index.js" > </script>
</head>
<body>
<div id="a1"> </div> //null 不可获取a1
</body>
var a1 = document.getElementById (' a1 ');
console.log( a1 )
body>
<div id="a1"> </div>
<script src="./js/index.js" > </script> //将js文件引入代码放在body底部,可以获取a1
</body>
var a1 = document.getElementById (' a1 ');
console.log( a1 )
给JavaScript引入代码中添加async或defer时,异步执行,js和body同时进行,可以获取到元素。
当页面引入多个js代码时,defer是两个js文件都加载完成后再开始按顺序先后执行,而async是先加载完成先执行后加载完成的后完成(注重顺序问题时使用defer,不注重顺序时使用 async)
<head>
<script src="./js/index.js" async> </script> //添加async或defer,可以获取到a1
</head>
<body>
<div id="a1"> </div>
</body>
var a1 = document.getElementById (' a1 ');
console.log( a1 )
window.οnlοad=function(){ } 其中的代码会等HTML页面所有代码加载完毕后再执行,就不必担心顺序问题
<head>
<script src="./js/index.js" async> </script> //添加async或defer,可以获取到a1
</head>
<body>
<div id="a1"> </div>
</body>
window.onload=function(){
var a1 = document.getElementById (' a1 ');
console.log( a1 )
}
当在< script >标签中使用src=“ ” 引入js代码时,页面中< script >中再出现js代码时,会被忽略
<head>
<script type="text/javascript" src="hello.js"></script>
<script type="text/javascript">
var str="hello world";
console.log(str);
</script> // 忽略
</head>
书写位置
-
行内式JS
可以将单行少量JS代码写在HTML标签的事件属性中(以on开头的属性)< input type="button" value="点我" onclick="alert('Hello world')"/>
-
内嵌式
< script > JS代码 </ script>
-
外部引入
< script src="js地址"> < / script>
运行环境
1.浏览器运行:
- 在HTML文件中在script标签中写js代码或在html页面中引入外部js代码,再用浏览器运行;
- 在浏览器控制台可以直接编写js代码;
2.电脑上运行:(需要安装node环境)
- cmd打开电脑终端,node回车编写代码,node index.js 或 node index 运行js代码
- vscode 中在英文状态下按Ctrl+~打开集成终端,进行js代码编写和运行
在vscode中安装插件:
npm i nodemon -g (全局安装)可以自动检测文件的更改,重新启动程序,方便调试;
nodemon index.js 使用插件运行文件,修改保存文件后,自动重启,ctrl+c结束进程
插件安装npm i readLine-sync
使用:const readLine = require(‘readLine-sync’)
var input = readLine.question(‘请输入×××’);
3.云服务器运行:(node环境下)
Linux系统
cmd ssh连接云服务器;
安装node;
node -v 检测node版本;
touch 创建文件;
vi index.js 使用vi编辑器编辑文件,若文件不存在则创建新文件进行编辑;
node index.js执行js代码;
cat index.js 查看文件内容;
node 回车进行编辑js代码;
node编辑状态下的命令:
.clear清空实例,
.editor进入编辑模式可以同时输入多行代码,ctrl+d键会将代码结果进行打印。
ctrl+c退出编辑help帮助,
.exit退出node环境
.load加载已存在的文件,
.save将刚编辑的代码进行保存,
.save 文件名 : 将已经写好的代码保存到文件中
注释
单行注释:// (ctrl+ / )
多行注释: /* */ (shift+Alt+ a)
输入输出语句
alert(msg) 浏览器弹出警示框,展示给用户
console.log(msg) 浏览器控制台打印输出信息,展示给开发人员
prompt(info) 浏览器弹出输入框,用户输入。
关键字和保留字
关键字:(在JS中有特殊功能)
保留字:(将来可能成为关键字)
js是区分大小写的(HTML是不区分大小写的,css严格区分大小写):typeof 关键字, typeOf 非关键字
标识符
指变量,函数,属性的名字或者函数的参数。
标识符是按照以下规则组合起来的一或多个字符(严格区分大小写):
- 字母,数字,下划线,$ 组成;
- 只能以字母,下划线,$开头;
- 不能将关键字或保留字作为标识符(尽量不要使用name作为变量名);
- 命名采用驼峰式命名:
大驼峰式(类名):UserName;
小驼峰式(变量名,函数):userName; - 名称尽量有意义(不能使用中文)
语句
每个语句以分号结尾,如果省略分号,由解析器确定语句的结尾,即分号可以省略,但是我们要求每个语句的末尾都应该有分号。
变量
变量是一个存放数据的容器,该容器的值可以随时改变。可以通过变量名访问内存中分配的空间。
本质:变量是程序在内存中申请的一块用来存放数据的空间。
ECMAScript的变量是弱类型(松散类型),可以用来保存任何类型的数据。
定义变量时使用var关键字。
变量只能声明一次,重复声明无效。声明在内存中申请一个空的空间。
变量可以重复赋值
在node中运行js时,变量保存在global中;在浏览器中运行时,变量保存在window中
变量的使用:
声明 var message;
赋值 message = “hello”
初始化(声明并赋值) var message = “hello”;
定义多个变量 var message= “hello”, found=false, age = 29; var a =b=c= 3;
变量调用 console.log(message);
变量名的命名规则:
- 变量名由字母,数字,下划线以及$组成。
- 不要使用下划线或者数字作为变量名的开头
- 变量名应该具有一定的意义,使用小驼峰命名规则 var userAgeTotal = “”;
- 不要使用关键字或是保留字
变量的声明
声明变量的本质是去内存申请空间
var用于声明一个变量,在es6中,可以通过let声明一个变量,通过const声明一个常量
var a =b=c= 3;
var d=10,e=20,f,g;
特殊情况:
-
只声明,不赋值 : undefined
var age; console.log(age);
-
不声明,不赋值,直接使用 : 报错
console.log(age);
-
不声明,只赋值 : 不会报错但是不建议这样使用
age=10; console.log(age);
变量提升
全局块中的变量声明会自动提升到全局代码块的最顶端,但是赋值不会被提升;
同理局部快中的声明会被提升到局部代码的最顶端,赋值不会被提升。
1) console.log(a); // 变量未声明就打印会出错 error
2) var a;
console.log(a); //undefined
3) console.log(a);
var a; // undefined 不会报错,在代码执行前全局块中的声明会自动提升到全局代码块的最顶端
等价于
var a;
console.log(a);
4) var a=0;
function test() { var a;
console.log(a); 等价于 console.log(a);
var a=1; a = 1;
}
test (); //undefined 局部代码块中声明(var=a)会被提升到局部代码块的最顶端,但赋值(a=1)不会提升
console.log(a); //a=0
5) var a=0;
function test() {
console.log(a);
var a=1;
console.log(a)
}
test (); //undefined a=1 局部代码块中声明(var=a)会被提升,但赋值(a=1)不会提升
console.log(a); //a=0
如果在函数中定义变量没有加var,该变量为全局变量
function test(){
message = "hello"; //message为全局变量
}
test();
alert(message); //可以访问
用var操作符定义的变量将成为定义该变量的作用域中的局部变量
var a = 1; //局部变量
function b() {
a = 10; //全局变量
return;
}
b();
console.log(a); //10
全局变量不能获取局部变量,而局部变量可以获取到全局变量
1)function test(){
console.log(a);
var a=1; //局部变量
}
console.log(a); ///error 全局中不能获取局部变量中的值
2)x = 1; //全局变量
console.log(x); //1
function y() {
console.log(x); //undefined
console.log(this.x); //1
var x = 2; //局部变量
console.log(x); //2
}
y();
console.log(x); //1
3)var a = 1; //a函数声明,提前变量a,将a认为是函数b作用域的变量,具有局部效果
function b() {
a = 10; //全局变量
return;
function a(){}
}
b();
console.log(a);
4)function test() {
a=3;
console.log (a)
}
console.log(a); //不能获取到a的值,因为此时函数还未执行
test();
console.log(a); //函数执行后可以获取到a的值
变量的作用域
全局变量和局部变量。javascript的作用域是相对函数而言的,可以称为函数作用域
全局作用域: 最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的;
局部作用域: 局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的