JavaScript
JS的介绍
1.Javascript是什么
是一种运行在浏览器的编程语言,用于实现网页特效、表单验证、数据交互、服务端编程
组成;ECMAScript(语言基础)+Web APIs(DOM文档对象模型+BOM浏览器对象模型)
搜索网站:MDN
2.JS书写位置
①内部JS:直接写在html文件里,用script标签包住写在上面
<script>
alert('Hello World~!');
</script>
②外部JS:写在以.js结尾的文件里,通过script标签引入到html页面里
(script中间无需写代码否则会被忽略)
<script src="my.js"></script>
③内联JS:写在代码内部(了解,但vue框架会用该模式)
<input type="button" value="点我试试" onclick="alert('Hello World')" />
3.JS注释
①单行注释:// 快捷键ctrl+/
②多行注释:/* */ 快捷键 shift+alt+a
4.JS结束符
可写可不写 要么都写 要么都不写 用;结束
5.输入和输出语法
①输出语法:
document.write( ‘要出的内容’)作用:向body内输出内容
alert(‘弹出的内容’)作用:页面弹出警示对话框
console.log(‘控制台打印’) 作用:控制台打印输出给程序员
②输入语法:
prompt(‘显示文字’) 作用:显示一个对话框用来提示用户输入文字
6.代码执行顺序
按照html文档顺序执行
alert()和prompt()会跳过页面渲染先被执行(目前仅做了解)
字面量
字面量:没有用标识符封装起来的的量,是值的原始状态
数组字面量、字符串字面量……所代表的含义就是它字面的意思
<script>
console.log(1)
console.log("Hello")
</script>
变量
1.定义
存储数据的容器,变量本身不是数据本身(本质是存放数据的小空间)
变量并不存储任何值,而是存储值的地址
2.基本使用
①声明(定义变量):let 变量名 es6以后用lei不用var了
let允许重复声明,声明多个变量用,隔开
②赋值 :即赋值号=
3.命名规则和规范
不能用关键字、只能用下划线、字母(区分大小写)、数字和$组成且数字不能开头
规范:起名要有意义,第一个单词首字母小写,后面每个单词开头大写
4.数组
定义:一种将一组数据存储在单个变量名的方式
let 数组名[数据1,数据2,数据3,…,数据n]
5.变量提升
变量提升允许在变量声明之前即被访问(仅存在于var声明变量)
注意:1.变量在未声明时即被访问会报语法错误。2.变量在var声明之前被访问,变量的值为undefined。3.let/const声明的变量不存在变量提升。4.变量提升出现在相同作用域中。5.实际开发中推荐先声明再访问变量。
<script>
//访问变量str
console.log(str+'world')
//声明变量str
let str='hello'
</script>
常量
概念:使用const声明的变量称为常量
命名规范和变量基本一致
常量使用:const G = 9.8
注意:常量不允许重新赋值,声明的时候必须赋值,不需要重新赋值的数据使用const
标识符
所有可以由我们自主命名的内容都叫标识符,如:变量名、函数名、类名……
命名规范:
- 标识符只能含有字母、数字、下划线、$、并且数字不能开头
- 标识符不能是JS中的关键字和保留字(private、implement、interface、protected、public、static等)
- 驼峰命名法,首字母小写每个单词开头大写
数据类型
- 基本数据类型:数值(Number)、大整数(Bigint)字符串型(String)、布尔型(Boolean)、未定义型(Undefined)、空类型(Null)、符号(Symbol es6)
- 引用数据类型:对象object
1.Number
- 可以是整数、浮点数
Infinity是一个特殊的数值表示无穷,NaN也是特殊数值表示非法数值- JS中的数值并不是无限大的,当数值超过一定范围后会显示近似值
- 算数运算符:+、-、*、/(求商)、%(取余)
2.Bigint
- 大整数用来表示一些比较大的整数
- 一些大整数以n结尾,表示数字范围是无限大
3.String
- 用单引号、双引号或反引号包裹的数据都叫字符串,推荐使用单引号
- 字符串拼接:+运算符,数字相加字符相连
- 转义字符
"'\\t\n - 模板字符串:用反单引号来拼接字符串和变量,内容拼接变量时用
${}包住变量
4.Boolean
- 表示肯定或否定的数据类型,两个固定值:True/False
5.Undefined
- 只有一个值undefined,只声明变量不赋值时默认值为undefined,
- 给抛出异常一个返回值,只声明不赋值会报错,因此有个undefined值
6.Null
- null代表“无”“空”“值未知”,未声明变量或变量赋值null
- typeof检查空值会返回object(对象),因此无法检查空值
类型转换和类型检查
1.类型转换
- 转换成字符串
let a=10
a=a.toString() //调用toString方法转换成字符串并改变a的类型
//null和undefined没有toString方法 会报错
let b=null
b-String(b) //null和undefined有String方法
- 转换成数值
let a='132'
a=Number(a) //a=132
/*使用Number()函数:
-字符串:如果字符串是合法数字直接转成数字,如果不是转换成NaN,如果是空转成0
-布尔值:true转成1,false转成0
-null转成0,undefined转成NaN
*/
/*只适用于字符串转换:如果不是字符串会转换成字符串再转成数字
-parseInt() 将一个字符串转换为整数
-parseFloat() 字符串转换成小数
*/
let b='123px' //不是合法数字 Number()会转成NaN
b=parseInt(b) //b=123
- 转换成布尔值
/*使用Boolean()函数:
-数字:0和NaN为false,其余为true
-字符串:空串为false,其余为true
-null和undefined都为false
-对象:对象为true
*/
let a=-1
a=Boolean(a) //true
2.类型检查
console.log(typeof a) //typeof运算符 返回数据类型
运算符
1.赋值运算符
例子:a+=2→a=a+2 类比
2.一元运算符(自增)
例子:正负号
自增:++ 自减:--
注意:前自增++i 先自加再赋值 后自增i++先赋值再自加
3.比较运算符
注意:比较字符串是比较ASCII编码
4.逻辑运算符
5.运算符优先级
6.展开运算符
...将一个数组进行展开,典型运用场景:求数组最值、合并数组等。
const arr = [1,5,3,8,2]
console.log(...arr) //1,5,3,8,2
说明:1.不会修改原数组。
const arr = [1,2,3]
//1.求数组最值
console.log(Marh.max(...arr))
console.log(Math.min(...arr))
//2.合并数组
const arr2=[4,5]
const arr3=[...arr,...arr2] //[1,2,3,4,5]
语句
1.表达式和语句
表达式时可以被求值的代码,JS引擎会计算出一个结果
语句一般时可以执行的代码
2.分支语句
定义:选择性地执行代码
①if分支
单分支:if(条件){满足条件要执行的代码}
双分支:if(条件){满足条件要执行的代码}else{不满足条件执行的代码}
多分支:if(条件1){代码1}else if(条件2){代码2}else(条件n){代码n}
// 条件成立执行代码,否则什么也不做
if (条件表达式) {
// 条件成立执行的代码语句
}
②三元运算符
条件?满足条件执行的代码:不满足条件执行的代码(一般用于取值)
//补0案例
h = h < 10 ? '0' + h : h
//表达式1 ? 表达式2 : 表达式3;
③switch语句
switch( 表达式 ){
case value1:
// 表达式 等于 value1 时要执行的代码
break;
case value2:
// 表达式 等于 value2 时要执行的代码
break;
default:
// 表达式 不等于任何一个 value 时要执行的代码
}
-
关键字 switch 后面括号内可以是表达式或值, 通常是一个变量
-
关键字 case , 后跟一个选项的表达式或值,后面跟一个冒号
-
switch 表达式的值会与结构中的 case 的值做比较
-
如果存在匹配全等(===) ,则与该 case 关联的代码块会被执行,并在遇到 break 时停止,整个 switch 语句代码执行结束
-
如果所有的 case 的值都和表达式的值不匹配,则执行 default 里的代码
注意: 执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句。
2.断点调试
F12→sources(资源)→双击进入html文件→双击代码行→刷新
3.循环语句
①while语句
while (条件表达式) {
// 循环体代码
}
- 1 先执行条件表达式,如果结果为 true,则执行循环体代码;如果为 false,则退出循环,执行后面代码
- 2 执行循环体代码
- 3 循环体代码执行完毕后,程序会继续判断执行条件表达式,如条件仍为true,则会继续执行循环体,直到循环条件为 false 时,整个循环过程才会结束
注意:
- 使用 while 循环时一定要注意,它必须要有退出条件,否则会成为死循环
②do-while循环
do {
// 循环体代码 - 条件表达式为 true 时重复执行循环体代码
} while(条件表达式);
-
1 先执行一次循环体代码
-
2 再执行条件表达式,如果结果为 true,则继续执行循环体代码,如果为 false,则退出循环,继续执行后面代码
注意:先再执行循环体,再判断,do…while循环语句至少会执行一次循环体代码
③for循环
~~~JavaScript
for(初始化变量; 条件表达式; 操作表达式 ){
//循环体
}
~~~
4.循环退出
break:退出循环
continue:结束本次循环,继续下次循环
代码规范
1.标识符命名规范
- 变量、函数的命名必须要有意义
- 变量的名称一般用名词
- 函数的名称一般用动词
2.操作符规范
// 操作符的左右两侧各保留一个空格
for (var i = 1; i <= 5; i++) {
if (i == 3) {
break; // 直接退出整个 for 循环,跳到整个for循环下面的语句
}
console.log('我正在吃第' + i + '个包子呢');
}
3.单行注释规范
for (var i = 1; i <= 5; i++) {
if (i == 3) {
break; // 单行注释前面注意有个空格
}
console.log('我正在吃第' + i + '个包子呢');
}
4.其他规范
关键词、操作符之间后加空格
数组
1.数组是什么
是一种可以按顺序保存数据(有索引值和下标) 的数据类型(Array)
2.基本使用
①声明(字面量声明):let 数组名 = [数据1,数据2,…,数据n]
(构造函数声明)let 数组名 = new Array(数据1,数据2,…,数据n)
②取值:数组名[下标](下标是从0开始)
③遍历数组: for(let i =0;i<数组名.length;i++){数组名[i]}
3.操作数组
①增:
arr.push(元素1,元素2,…,元素n)
添加到数组的末尾并且返回该数组的新长度
arr.unshift(元素1,元素2,…,元素n)
添加到数组的末尾开头并且返回该数组的新长度
② 删:
arr.pop()
删除数组最后一个元素并返回该元素的值
arr.shift()
删除数组第一个元素并返回该元素的值
arr.splice(操作的下标i,删除的个数n【默认删到最后】)
删除第i个元素后的n个元素
③ 改:数组[下标]=新值
函数
1.函数的使用
①声明: function 函数名(){函数体}
命名最好为小驼峰命名且前缀最好为动词
②调用:函数名() 可重复调用
2.函数的传参
①声明: function 函数名(形参1,…,形参n){函数体}
②调用:函数名(实参1,实参2,…,实参n)
如果用户不输入实参可以在声明中给形参默认值为0
3.函数返回值
let result = prompt(‘请输入一个数字’)
result即prompt()的返回值
语法:return 返回值
细节:①在函数体中使用return能将内部的执行结果交给函数外部使用。②return后面代码不会再被执行,会立即结束当前函数所以return后面的数据不要换行写。③return函数可以没有return,此时默认返回值为undefined。
按F11进入函数内部看执行过程
4.作用域
①全局作用域:在里面或js文件内写的都是全局作用域
②局部作用域:在函数内部写的变量
特殊情况:如果函数内部变量没有声明直接赋值,也当全局变量来看。函数内部的形参可以看作局部变量
5.匿名函数
①函数表达式:把函数赋值给一个变量let fn = function(){}
必须先声明后调用fn()
②立即执行:避免全局变量的污染,不需要调用直接执行
第一个括号内是形参,第二个括号内实参
6.逻辑中断
逻辑运算符里的短路:只存在于&&和||中,当满足一定条件会让右边代码不执行
&& 和 左边为False就短路 || 或 左边为True就短路
类似写法:function getsum(x,y){
x=x||0
y=y||0
console.log(x+y)
}
7.转换为布尔型
布尔型:False/True (' '、0、undefined、null、false、NaN布尔值都为False,其他为True)
语法:Boolean(其他类型)
8.函数提升
函数提升是指函数在声明之前就可以被调用。
<script>
//会把所有函数声明提升到当前作用域的最前面
fn()
function fn(){
consoloe.log('函数提升')
}
</script> //不报错
9.函数参数
①动态参数:arguments是函数内部内置的伪数组变量,只存在函数里面,动态获取函数的实参。(伪数组不能用pop、push方法)
<script>
function getSum(){
let sum = 0
for(let i = 0;i<arguments.length;i++){
sum+=arguments[i] //遍历数组
}
console.log(sum)
}
getSum(2,3) //传递的值个数不限制
getSum(1,2,3)
</script>
②剩余参数:允许我们将一个不定数量的参数表示为一个真数组。(提倡)
<script>
function getSum(a,b,...arr){
let sum = 0
for(let i = 0;i<arr.length;i++){
sum+=arr[i] //遍历数组
}
sum=sum+a+b
console.log(sum)
}
getSum(2,3)
getSum(1,2,3)
</script>
箭头函数(ES6)
1.基本语法
//普通函数
const fn = function(){
console.log(123)
}
//箭头函数
const fn = (形参)=>{ //只有一个形参的时候可以省略()
console.log(形参) //只有一行代码可以省略{}
}
//只有一行代码的时候可以省略return
const fn = x => x+x
console.log(fn(x))
//箭头函数可以直接返回一个对象
const fn = (uname)=>({name:uname})
fn('徐乐柔')
2.参数
箭头函数没有arguments动态参数,但是有...arr剩余参数
//利用箭头函数求和
const getSum = (...arr) => {
let sum = 0
for(let i = 0;i<arr.length;i++){
sum+= arr[i]
}
return sum
}
getSum(2,3)
getSum(1,2,3)
3.箭头函数的this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
普通函数this的指向:谁调用该函数,this就指向谁
箭头函数this的指向:
const fn= () =>{
console.log(this) //指向window
}
//对象方法箭头函数this
const obj ={
uname='Xulerou',
sayHi:()=>{
console.log(this) //this指向window
}
}
obj.sayHi() //因为sayHi中没有this,该作用域链是obj,上一级则是window
const obj ={
uanme:'Xulerou',
sayHi:function(){
const count = () =>{
console.log(this) //this指向obj
}
count()
}
}
obj.sayHi() //该作用域链是function(),上一级是obj
对象
1.对象的定义
对象(object)是Javascript里的一种数据类型,可以理解为是一种无序的数据集合,用于描述某个事物。(类似于Py里的字典)
2.对象的使用
①声明语法:let 对象名 { }或 let 对象名 = new Object()
对象由属性和方法组成
属性:数据描述性的信息,一般为名词性
即属性名:属性值,属性名:属性值
②调用:obj.属性名
如:console.log(obj);console.log(obj.name)
3.对象的操作
①改:对象.属性=值
②删:delete 对象名.属性名
③增:对象名.新属性名=新值
④查:对象.属性 或对象名[’属性名‘] (遍历)
4.对象的方法
方法:数据行为性的信息,一般为动词性,本质为函数
即方法名:函数,方法名:函数
调用:对象名.方法名()
⭐⭐⭐5.对象的遍历
for Each语法(Java中的增强for循环)
属性值是key 获得对象值是obj[key]
//声明对象
let obj={
uname:'Xulerou',
age:18,
gender:'女'
}
//遍历对象
for(let key in obj){
console.log(key) //key为带有引号的属性名
//console.log(obj.key) 得到undefined
console.log(obj[key]) //中括号中含有引号
}
6.内置对象
Math:提供一些了做数学运算的方法
可以搜索MDN Web Docs进行查看
拓展:基本数据类型和引用数据类型
简单数据类型(值类型):存储时存的是值本身,如:string、number、boolean、undefined、null
引用数据类型:存储时存的仅仅是地址(引用),如:通过new关键字创建的对象(Object、Array、Date等)
作用域
1.局部作用域
局部作用域分为函数作用域和块作用域。
①函数作用域:在函数内部生命的变量只能在函数内部被访问,外部无法直接访问。
<script>
function getSum(){
//函数内部是函数作用域 属于局部变量
const sum = 20
}
console.log(num)//此处报错 函数外部不能用局部变量
</script>
总结:1.函数内部的变量在外部无法被访问。2.函数的参数也是函数内部参量。3.不同函数内部声明的变量无法相互访问。4.函数执行完毕后,函数内部的变量被清空。
②块作用域:在JS中用{}包裹的代码称为代码块,代码块内部生命的变量外部有可能无法被访问。
for(let t=1; t< 6;t++){
//t只能在该代码块中被访问
console.log(t)
}
console.log(t) //报错
总结:1.let声明的变量会产生块作用域,var不会产生。2.const声明的常量也会产生块作用域。3.不同代码块直接的变量无法相互访问。4.推荐使用let或const
2.全局作用域
<script>标签和.js文件的最外层就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。
<script>
//全局作用域下声明了num
const num = 10
function fn(){
//函数内部可以使用全局作用域的变量
console.log(num) //10
}
</script>
注意:尽可能少的声明全局变量,防止全局变量被污染。
3.作用域链
<script>
//全局作用域
let a=1
let b=2
//局部作用域
function f(){
let a = 1
function g(){
a=2
console.log(a)
}
g() //调用g
}
f() //调用f 结果为2
</script>
作用域链的本质是底层的变量查找机制,在函数被执行时,会优先查找当前函数作用域中查找变量,如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域
总结:1.嵌套关系的作用域形成作用域链。2.相同作用域链从小到大查找变量。3.子作用域能够访问父作用域,但父作用域无法访问子作用域
4.垃圾回收机制
JS中内存的分配和回收都是自动完成的,内存不使用的时候会被垃圾回收器自动回收。
1.内存分配:当我们声明变量、函数、对象的时候,系统会自动为它们分配内存。
2.内存使用:即读写内存,也就是使用变量、函数等。
3.内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存。
说明:全局变量一般不会回收(关闭页面回收),一般情况下局部变量的值不用了会被自动回收
拓展 算法说明:
栈:由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里
堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型放在堆里。
算法:1.跟踪记录被引用的次数。2.如果被引用了一次,那么记录次数1,多次引用会累加++ 。3.如果减少一个引用就1--。4.如果引用次数时0,则释放内存。
JS闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域。闭包=内层函数+外层函数的变量
function outer(){
const a = 1
function f(){
console.log(a) //里层的函数用到了外层函数的变量
}
return f
}
const fun = outer()
fun() //1
//外部函数使用内部函数的变量
解构赋值
1.数组解构
将数组的单元值快速批量赋值给一系列变量的简介语法。
const [max,min,avg] = [100,60,80]
console.log(max)//最大值100
console.log(min)//最小值60
console.log(avg)//平均值80
let a = 1
let b = 2
;[a,b]=[b,a] //先把b赋值给a,再把a赋值给b
必须加分号的两种情况:1.立即执行函数:(function(){})( );.2.使用数组的时候:代码 + ;+[数组]。
2.对象解构
将对象属性和方法快速批量赋值给一系列变量的简介语法。
//批量声明变量name age
const user = {
uname:'Xulerou',
age:'18'
}
const {name,age}={uname:'Xulerou',age:'18'}
//等价于const uname = obj.uname
//变量名和属性名必须一样找不到变量名一致的变量为undefined
//对象解构的变量名可以重新改名 旧变量名:新变量名
const{uname:unsername,age}={uname:'xulerou',age:18}
console.log(username)
console.log(age)
//解构数组对象
const pig = [
{uanme:'佩奇',
age:'18'}
]
const [{uname,age}] = pig
forEach遍历数组
主要使用场景:遍历数组的每个元素(不能遍历对象)
//语法
arr.forEach(function(当前数组元素,当前元素索引号){
函数体
}) //只遍历不返回值
const arr =['red','blue','pink']
arr.forEach(function(item,index){
console.log(item) //red blue pink
console.log(index) //1 2 3
})
深入对象
1.创建对象的方式
//1.利用对象字面量创建
const obj = {
name:"xulerou"
}
//2.利用new Object创建
const obj = new Object({uname:'Xulerou'})
//或者obj.uname = 'Xulerou'
//3.利用构造函数创建对象
2.构造函数
构造函数是一种特殊的函数,主要用来初始化对象。使用场景可以通过构造函数快速创建多个类似的对象。
//命名以大写字母开头,只能由new操作符来执行
function Person(name,age,gender){
this.name = name
this.age = age
this.gender = gender
}
const Xu = new Person('徐乐柔',18,'女')
const Chen = new Person('陈伟彬',19,'男')
console.log(Xu.name)
说明:1.使用new关键字调用函数的行为被称为实例化。2.实例化构造函数没有参数是可以省略{ }。3.构造函数内部无需写return,返回值为新创建的对象。4.new Date``new Object也是实例化构造函数。
new实例化过程:1.创建新对象。2.this指向新对象。3.执行构造函数,修改this添加新属性。4.返回新对象。
3.实例成员和静态成员
①实例成员:通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和示例方法)。
说明:1.为构造函数传入参数,创建结构相同但值不同的对象。2.构造函数创建的实例对象彼此独立互不影响。
//命名以大写字母开头,只能由new操作符来执行
function Person(name,age,gender){
this.name = name
this.age = age
this.gender = gender
}
const Xu = new Person('徐乐柔',18,'女')
//Xu为实例对象
Xu.sayHi = () =>{
console.log('hi') //实例方法 也是实例成员
}
②静态成员:构造函数的属性和方法被称为静态成员。
说明:1.静态成员只能构造函数访问。2.静态方法中的this指向构造函数。比如Date.now()、Math.PI、Math.random
function Person(name,age,gender){
//省略实例成员
}
//静态属性
Person.eyes = 2
//静态方法
Person.walk = function(){
console.log('人都会走路')
//this指向Person
console.log(this.eyes)
}
内置构造函数
引用类型:Object、Array、RegExp(正则)、Date
包装类型:String、Number、Boolean
1.Object
//通过构造函数创建普通对象
const user = new Object({name:'徐乐柔',age:18})
//还是推荐使用字面量方式声明对象
//常用静态方法:
//1.获取对象里面的属性和值 Object.keys()\Object.values()
const arr = Object.keys(user) //属于静态方法
console.log(arr) //['name','age']
console.log(Object.values(user)) //['徐乐柔',18]
//2.Object.assign对象拷贝
const obj = {}
Object.assign(obj,user)
console.log(obj) //{name:'徐乐柔',age:18}
console.log(user,{gender:'女'})//{name:'徐乐柔',age:18,gender:'女'}
2.Array
//通过构造函数创建普通数组
const arr = new Array(3,5)
//还是推荐使用字面量方式声明对象
//常用方法:
//1.forEach遍历数组
const arr =['red','blue','pink']
arr.forEach(function(item,index){
console.log(item) //red blue pink
console.log(index) //1 2 3
})
//2.filter过滤数组,返回筛选满足条件的新数组
const arr = [1,6,9,3,7,5,10,2,12];
const newArr = arr.filter(function(item){
return item >= 5; // 过滤出来数组中>=5的元素
})
console.log(newArr) // [6, 9, 7, 5, 10, 12]
//3.map迭代返回新数组
const arr = ['red', 'blue', 'green'];
const newArr = arr.map(function(ele, index){
console.log(ele); // 数组元素
console.log(index); // 数组索引号
return ele + '颜色';
);
console.log(newArr); // ['red颜色', 'blue颜色', 'green颜色']
//4.reduce累计器,返回累计处理的结果经常用于求和
const arr =[1,5,8]
const sum = arr.reduce(function(prev,current){
return prev + current // 14 没有初始值
})
const sum = arr.reduce(function(prev,current){
return prev + current // 24
},10) //有初始值
其他方法:(在CSDN找)
| 其他方法 | 解析 | 语法 |
|---|---|---|
join | 数组元素拼接为字符串,返回字符串 | |
find | 查找元素,返回符合的第一个索引值 | arr.find(函数,[thisArg]) |
every | 检测是否所有元素都满足条件 | arr.every(函数[,索引[,array]])[,thisArg] |
3.String
常见实例方法: