数组
概述: 数组一般是多个数据类型相同的数据集合。
声明数组:
1.使用[ ] 声明数组
var arr = [1,2,3] 数据之间使用,分隔
2.使用new 关键词进行声明 (对象)
var arr1 = new Array(10) //里面参数指定对应的长度 如果你没有写 表示长度为0
console.log(arr1[0] ) //undefinedvar 声明 为数组arr开辟了10个空间,没有赋值操作 undefined
var arr2 = new Array(1,2,3,4) //当前数组里面的数据有 1 2 3 4
length属性:可以访问数组长度,也可通过该属性设置数组长度
var arr = new Array()
console.log(arr.length); //通过length来访问数组的长度
arr.length = 11 //设置对应的长度
console.log(arr); 长度为11的空数组
数组可通过下标访问
console.log(arr[0])//获取第一个
//可以允许字符串
console.log(arr['0']); //获取第一个
数组赋值
arr[0] = 10
console.log(arr[0]) //10
// 给数组里面的元素随机给值
var arr = new Array()
for(var i=0;i<10;i++){
arr[i] = Math.random() //0-1 包含0 不包含1的
}
console.log(arr); // 打印包含10个小于1的随机数数组
数组遍历:
传统的for循环遍历:
var arr = [1,2,3,45,12]
//利用顺序表的特点 有序
for(var i=0;i<arr.length;i++){
console.log(arr[i])
}
for in遍历 (对象 下标 迭代器 next)
var arr = [1,2,3,45]
for(var index in arr){ //index表示的为下标
console.log(arr[index])
}
for of进行遍历(数组 迭代器来实现的)
//使用for of遍历(只能遍历数组)
for(var value of arr){ //value表示的是里面值
console.log(value)
}
数组的方法:
数组是一个存储结构(只要是存储数据结构,就存在增删改查的操作)
添加 (add push append..)
栈方法 (先进后出 后进先出)push 入栈 pop出栈操作
push方法(添加到最后一个)
var arr = [1]
arr.push(10)
console.log(arr) //[1,10]
队列方法(先进先出,后进后出)
unshift(添加到第一个)
var arr = [1]
arr.unshift(10)
console.log(arr) //[10,1]
删除 (delete(硬删) remove(软删)..)
栈方法
pop方法(删除最后面)
var arr = [1,2,3]
arr.pop() //根据下标索引,但括号中的参数一般不写下标,默认删除最后一个
console.log(arr) //[1,2]
队列方法
shift方法(删除第一个)
var arr = [1,2,3]
arr.shift()
console.log(arr) //[2,3]
修改 (replace替换 update 更新)
//会改变原本的数组
反转 reverse(将最后一个变到第一个 一个个对应的换位置)
var arr = [1,2,3,4,8]
var arr1 = arr.reverse(); //返回一个数组 这个数组就是反转后的数组
arr1.unshift(10) //返回的反转后的数组其实就我们原本的数组
console.log(arr) //反转后的结果 [8,4,3,2,1]
console.log(Object.is(arr1,arr));//true
排序sort
//sort方法排序 //默认情况下他是根据第一个字符的ACSII码进行排序 (ACSII码排序)
var arr2 = [15,20,11,4,5]
arr2.sort() //返回一个数组 这个数组是排序好的数组 他跟上面一样 就是返回的这个数组其实就是原本的数组
console.log(arr2);
// sort 其实是一个高阶函数 高阶函数就是里面用函数做为参数的函数
var arr3 = [15,20,11,4,5]
arr3.sort(function(a,b){
//1 和 -1来进行大小区分和排序规则
return b-a //a-b是正序 b-a就倒序
})
console.log(arr3);
不会影响原本数组的方法
//不会影响原本数组的方法 返回新的数组
concat:连接
var arr = [1,2,3,4]
var arr1 = [1,2,3,4]
var arr2 = [1,2,3,4]
var arr3 = [1,2,3,4]
// concat 连接 把多个数组变成一个数组 返回
注: ...扩展运算符 打开数组取出里面的值(...证明可以写任意个) ? 表示可写可不写
var newArr = arr.concat(arr1,arr2,arr3)
console.log(newArr); //1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 length=16
console.log(arr); //1,2,3,4 不影响原数组
slice截取
// slice 切片 把一个数组里面东西提出 返回的新的数组
var arr = [1,2,3,4]
var sliceArr = arr.slice()//没有参数,默认全切
console.log(sliceArr); //1,2,3,4
console.log(arr); //1,2,3,4 不影响原数组
var sliceArr1 = arr.slice(0)//从0开始切到最后 如果下标不存在返回一个空数组
console.log(sliceArr1);//1,2,3,4
var sliceArr2 = arr.slice(2,3)//包含结束的下标 包含开始的下标 [2,3)
console.log(sliceArr2); //3
concat方法slice方法返回的数组跟原本的数组不是一个对象 但是里面的值或者对象他的地址是一样的(浅拷贝)
var obj = {name:'jack'}
var objArr = [obj]
var objArr1 = objArr.concat()
var objArr2 = objArr.slice()
console.log(objArr[0].name); //jack
objArr1[0].name = '张三' //给数组对象1里面的name赋值
console.log(objArr2[0].name); //张三
console.log(objArr[0].name); //张三
splice方法(删除)
//splice会影响之前的数组 可以实现增删改查
var arr = [12,13,45]
//参数 开始位置 删除的个数(可以写可以不写 数组的length) 返回一个新的数组
// var newArr = arr.splice(0) //从开始删
// console.log(newArr); //12,13,45
console.log(arr); // [ ]
var newArr = arr.splice(1,2) //从开始删 删除两个
console.log(newArr); //13,45
console.log(arr); // 12
//获取删除的内容 其实就截取里面的内容(不足是会改变之前的数组)
splice() 详解:
插入: 如果有3个或以上参数,且表示插入第二个参数(长度)为0,则
arr.splice(1, 0, “绿巨人”, “冬兵”); //在下标为1的位置插入: "绿巨人","冬兵"
替换: 如果有3个或以上的参数, 且第二个参数(长度)不为0, 则表示替换
arr.splice(1, 1, “绿巨人”, “冬兵”); //在下标为1的位置替换成: "绿巨人","冬兵"
删除: 如果只有两个参数, 则表示删除指定区域的数据
arr.splice(0, 2); //删除原数组的部分数据, 并返回截取的数据
join() : 连接数组中的元素, 并返回连接后的字符串, 不传参则以逗号连接
arr.join(“+”);
数据结构:
数据的结构,包括数据的逻辑结构 存储结构 算法
存储结构 (数据存储的结构方式)
线性结构
数组(顺序表)队列 栈 堆 链表
非线性结构
树 图 hash(散列表)
只要是能存数据的容器 就必须具备增删改查的方法
排序算法:
冒泡排序 (最基础的排序) O(n^2)
//冒泡排序核心点 俩个for循环嵌套 第一个趟数 相当于length-1 第二个每趟比较是递减
//相邻的俩个相比 j和j+1相比
function bubble(arr){
//遍历数组
for(var i=1;i<arr.length;i++){
//判断对应的没有比较的值
for(var j=0;j<arr.length-i;j++){
//相邻的俩个进行比较
if(arr[j]>arr[j+1]){
//换位置
var temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr
}
2.选择排序 (选择最大值的下标(或者最小值的下标)进行比较的排序)O(n^2)
function selecter(arr){
//遍历数组
for(var i=0;i<arr.length;i++){
var min = i //记录最小下标 默认当前的i
for(var j=i+1;j<arr.length;j++){ //遍历后面的内容
//如果当前值比最小值还小
if(arr[j]<arr[min]){
//记录一下这个下标
min = j
}
}
//判断当前最小下标是否为开始的默认下标 不是就换位置
if(min!=i){
//换位置
var temp = arr[min]
arr[min] = arr[i]
arr[i] = temp
}
}
return arr
}
3.快速排序 (在数据量不多最快的 冒泡排序的进阶)二分 O(nLogn)
function quick(arr){
if(arr.length<=1){
return arr
}
//定义左边数组 右边数组 基数
var left = [],right = [] ,mid=arr[0]
//遍历数组
for(var i=1;i<arr.length;i++){
arr[i]>mid?right.push(arr[i]):left.push(arr[i])
}
return quick(left).concat([mid],quick(right))
}
4.希尔排序 (插入排序的进阶)
5.插入排序 (插入数据的时候进行排序)
6.归并排序 (大数据排序的常用排序算法)
函数
概述:
函数是对一段代码的封装,实现某个特定的功能。
优点:减少冗余代码,提高可维护性及可阅读性。
分类:
系统函数:所有window里的函数。(console.log() alert() prompt())
内置函数:所有内置对象里的函数。(Math.pow())
自定义函数:自己定义的函数。
自定义函数的定义与调用:
1使用function关键词定义,定义匿名函数(没有名字的函数)
function(形参,可省略){
函数体(代码
}
//直接调用 自执行的匿名函数(自动调用)
匿名自执行函数不能传参
(function(){
cosole.log('匿名函数')
})()
匿名函数(声明较少,没有复用性)
匿名函数的形参传递:
匿名函数一般不传参,只调用一次,传参没有意义。
2使用function关键词定义具名函数(有名字的函数)
function 函数名(形参,形参...){
函数体(代码)}
//声明function sayHello(){
console.log(hello!)}
sayHello();
具名函数的变种声明:
var sayHi=function(){
console.log("hi")}
sayHi();
此为具名函数的两种声明,从调用速度来说,前者更快。
function和var在预编译阶段就会声明。
var关键字修饰的变量在预编译阶段不会赋值。
形参与实参
形参是形容的参数,是声明是用来接纳实参的量。
调用时的参数是实参。
3使用new Function方式
var 函数名 =new Function('形参','形参1' '函数体')
var sayBye =new Function('console.log("bye bye!")')
sayBye()
预编译:
1声明对应的function和var关键词修饰的变量(开辟内存)
2对应的function的内存空间会在开辟以后,将相应的代码块放到其中,等待调用。
3var修饰的关键词只会开辟一个空间,不会进行赋值(默认为undefined)
return关键词:
return:在函数中返回对应的数据(当你调用了return后,后面的内容将不再执行。)
没有return关键词,返回undefined。
函数执行过程:
1.把对应的开辟的function内存里面的代码块丢给方法栈(执行栈)去执行。
2.执行栈就会自动执行相应的方法 执行完返回对应的结果
3.当前结果返回完毕以后,对应的执行栈里面的内存空间要进行回收(GC)将这个内存空间销毁
函数作用域:
var number = 2;//全局作用域 ,var关键词声明的是伪全局作用
function factorial(n){
console.log(number)//undefined
number=1//局部变量,位于某一个代码的里面,称为局部变量,局部变量不能被全局访问
return number}
var number = 2;//全局作用域 ,
function factorial(n){
console.log(number)//2 作用域链,向上找
var number=1
作用域:
当前变量的作用范围。
局部作用域:在一个函数内生命的。或者在一段代码块内声明的。
全局作用域:在全局声明,作用范围为全局。
作用域链:
当前的作用域内没有找到对应的变量就会向上去寻找,这个过程构成的链式结构称为作用域链
函数的arguments(参数数组,参数的集合)
arguments是一个伪数组(有部分数组特性),可以通过length对应长度[]下标来访问里面的元素。
函数的嵌套:
函数内部可以再包含其他函数;
函数可以相互调用,也可以向外调用,但不能调用同级函数的嵌套函数。
注:函数抽取冗余代码,参数为(可变的内容),返回值为想从此函数中得到什么。
DOM的简单操作
1.通过id获取对应的标签
document.getElementById("id")
2.input框的值获取value属性
document.getElementById(input框的id).value
3.点击事件onclick
element.onclick = function(){
}
以事件驱动。
//通过输入框输入数值判断对应的奇偶并打印
<input id="number" type="text">
判断奇偶
<script>
function handlerClick(){
//拿到input框里面的内容 获取到input框
var inputValue = document.getElementById('number').value //string类型
// console.log(typeof inputValue); 如果是+法操作必须要先转类型
//判断奇偶的操作
if(inputValue%2==0){
console.log('当前为偶数');
}else{
console.log('当前为奇数');
}
}
//首先需要点击按钮 获取按键 加点击事件
//事件触发自动调用对应的函数 (事件驱动)
document.getElementById('btn').onclick = handlerClick
</script>
递归算法:
三要素:找规律,找临界值(没有规律的值),自己调自己(在函数内部调用自己的函数)
// 2 4 6 8 10 第100的值是?
function fn(n){
if(){
}else{
}
}
递归效率极低,一般不推荐使用递归除了文件遍历,菜单遍历,
bfs广度优先搜索,dfs深度优先搜索(递归思想)
程序控制语句
条件控制语句:
if:
if 如果(条件一)
else if (条件二)
else
同时满足条件一和条件二,只会进入第一个满足的条件。
如if (条件表达式){
需要执行的代码}
else if(条件表达式){需要执行的代码
}else{需要执行的代码
}
条件表达式为Boolean类型的值,如果不是布尔值会自动转换。
switch
switch是对于对应值的判断,判断条件表达式的值,case中包含值选项。
//恒等判断,值和对应类型应一样
switch(表达式){
case 值(常量): 操作 break;
case 值: 操作 break;
case 值: 操作 break;
default:当上面case都不满足时执行
}
break:跳出switch
循环控制语句
while ,do while , for
三要素:初始值(初始的变量值),迭代量(基于初始值的改变),条件 (基于初始值的判断)
while语句
while (条件表达式){
执行代码}
var 初始值变量=值
while(条件){
迭代量
执行代码}
例:循环打印1-10
var i=1;
while(i<=10){ //11次
console.log(i) //10次
I++}
自旋:
do-while语句
do {执行的代码}while(条件)
var 初始值=值
do {
执行的代码
迭代量变化}while(条件)
与while区别:先执行后判断,少判断一次
1-100累加:
var i=0;
var sum=0
do {
i++
sum +=i}while(i<100)
console.log(sum);
while和do while区别:
1.while先判断后执行,do while 先执行后判断
2.do while最少执行一次,while最少执行0次。故常用while实现执行多次的内容(不规定最少执行次数)do while (规定必须执行一次时)
for循环
for(初始值;条件;迭代量){
执行代码}
1-100累加:
for(var i=0;i<=100;i++){
sum +=1}
console.log(sum);
附:for(;;){
coonsole.log("hello")
//死循环 省略条件和迭代量必定死循环}
初始值可以省略不写for(;i<100;i++)
时间复杂度(按照次数计算,判断内容执行效率)
O(1):每行只执行一遍 常量阶
O(logN):由两个值来决定次数 指数阶
var i=1; 由i和2决定
while(i<100){
i*=2}
O(n):由对应的一个值决定 线性阶
for(var i=0;i<100;i++){
console.log('执行'+n+'遍')}
传统意义上,对应的代码时间复杂度越低对应的执行速度越快,效率越高。
while的时间复杂度低于for循环:(故而算法优化可使用while来替代for)
var i= 0;执行一次
i++;执行一次
console.log("hello")执行一次 O(3)
console.log("hello")执行一次 //都是数值次数
var i=0 执行一次 n 依赖这个n变化而变化
while(i<10){ 执行11次
i++ 执行10次
console.log(i) 执行10次
} //O(n) 线性阶
var i=2;
while(i<100){
i*=2}
O(2logN) O(logN)
O(1)<O(logN)<O(n)<O(nlogn)<O(n^2)
O(nlogn):循环嵌套指数阶循环
for(var i=0;i<100;i++){
var i=1
while(i<100){
i*=2
}}
O(n^2):双层循环嵌套 平方阶
循环嵌套:
嵌套多个循环,不同循环也可嵌套
打印多行*
var row=4
var col=10
//外层控制行,内层控制列
for(var i=0;i<row;i++){
var j=0
var rowStr ="每行的字符串"
while(j<col){
j++
//字符串拼接
rowStr+=“*”
}
console.log(rowStr)//document.wirte(rowStr+"")
}
//执行次数,外层循环次数*内层循环次数 O( n^2)
循环嵌套最宜嵌套两层,不推荐嵌套多层,会增加太多的时间复杂度
break和continue
break:在多层循环中只跳出当前的一层,,如果已执行break语句就不会再执行循环体中位于break后的语句。
continue:跳过本次循环,循环仍在继续,只能在循环中使用
一元运算符
()不能和++一起用,两者处于同一优先级
console.log(++(a--));报错
字符串和数值进行比较
console.log("123">123); false 自动转为number
console.log("123A">123); false 自动转为number,如果不能转就会出现NaN
console.log(NaN>NaN); false
undefined派生自null:
console.log(undefined==null); true
console.log(undefined===null); true
比较字符串:比较两者ASCII码,比较第一位
A:65 ; a:96
console.log("bAA">"azz"); false
boolean和null进行比较,自动转成数值
console.log(true>null) true
console.log(true>undefined) flase
比较出现NaN即为flase
等于和恒等
console.log(Number(true)==1); true
console.log(Number(true)===1); true
console.log(Boolean(0)==flase); true
存在数据类型转换时,先进行数据类型转换再比较
null值同0比较
null是一个空对象引用,,对应是引用类型,注:引用类型比较的是地址。
console.log(null==0); flase 等于比较时 不会进行数据转换
console.log(undefined==0); flase undefined为NaN
逻辑运算符
短路原则
&&短路:只要前为假后就不再比
var a=10,b=20,c=30;
console.log(a>b&&b<c);
||短路:只要前为true后就不再比
console.log(c>b||a>b);
!取反
断路原则
&断路,不论前真假,继续比较后
|断路
|| 有一个为true 取true
console.log(a>b ||20) //20
var i=0||10
console.log(i);
//两个都是false 取最后一个
var str =undefined || " "
console.log(str)
//如果两个都为true,取第一个true
var str1= "A "||"B"
console.log(str1);
var str2=" "||'false' ||'true'
console.log(str2);
三目运算优先级同对应逻辑运算优先级一样
var str3=(10 >20 ? ' ': '123') ||(30>20 ? ' ' :'456')
console.log(str3);
var str3=10 >20 ? ' ': '123') ||(30>20 ? ' ' :'456')
&&:若全为false直接取false ,如果true取最近一个
取非“自动转换为boolean
var str6=!123
console.log(str6); //false
初识JavaScript
javaScript起源:
诞生于1995年,原名LiveScript,更名为JavaScript,Netscape研发。
javaScript特点:
轻量级语言,单线程语句(一个线程解析),弱语言(没有固定类型,给定数值类型),脚本语言(可侵入,实现xss攻击)
能被v8引擎解析,所有浏览器已经支持。
javaScript内容:
ECMAScript(基本语法及相关对象es3及以上),DOM(文档对象模型,操作HTML),BOM(浏览器对象模型,操作浏览器)
书写javaScript:
1写在<script>标签内
2写在外部js文件中
3写在对应世间属性中
变量定义(使用var关键词声明):
var变量=值
变量命名
见名知意,驼峰法;数字,字母,下划线 美元符$;不能以数字开始,不能使用关键字(会占用之前的关键词引用空间)。
普通变量首字母小写,常量全大写,标识符区分大小写
前缀,fn:函数;re:正则。
注释:解释语句,不会被浏览器编译
单行注释:// ctrl+/
多行注释:/* */ alt +shift+a
数据类型:
number类型:所有数值
string字符串类型:单引号,双引号都是字符v
boolean布尔型:true false
null空类型:
undefined:
可使用tupeof来查看对应类型
类型转换:
typeof:查看数据类型
number转string
tosString方法(隐式转换)
string转number(显示转换)
1.number方法,直接转 number类型
2使用parseInt:转整型
3使用parseFloat:转小数
isNaN判断数据类型是否NaN:
是返回true,不是false
无穷:
无穷大:infinity
无穷小:-infinity
布尔类型转换:
非空即为true
Boolean()方法转为布尔类型
数值型:非0和NaN即为true
undefined和对应的null为Boolean为false
将boolean类转为number类型:false 0 ;true 1
将对应的null转为number:0
undefined转为number:NaN
运算符和表达式:
算术运算:+ - * / %
String +number=String :发生连接操作,自动转为string.
// - * / % 全部转为number类型进行操作。
‘12’-1=11;
true-1=0;
unde-1=NaN; 出现NaN计算结果就是NaN
null-1=-1;
注:string大于number,Boolean ,null ,undefined小于number
取余,取模:大数取余小数,得到的是余数 ,小数取余大数得到小数。
++;--前置后置的区别:
前置先执行对应++ --,再执行对应的代码。
优先级:先算括号里的,再看++,--,再乘除取余,最后加减,再进行比较运算,再逻辑运算,最后赋值运算
逻辑运算:&&,||,!非
&&:同true则为true;||有true则是true;!取反
比较运算:
// > < >= <= == != === 全等,两边数值类型完全相同
位运算:转为二进制在进行位的变化运算
// >> << :补零操作 ~:去掉小数
注:怎样快速从2得到8:var i = 2;console.log(2
<<2);
三元运算符(三目运算符)
表达式(boolean类型表达式)
?true的内容:false的内容
var a=10 ;
var b=10;
a>b?10:20; //20
'123a'/10?'hello':hi); //hi '123a'/10=NaN
number对应的方法:
保留几位小数的方法:
默认保留16位小数,整数位也是位,超出不显示。2……-32
var number1=3;
var number2=10
console.log(number2/number1)
保留小数(方法会优先调用),原理:转成字符串对其做截取操作。
console.log((number2/number1).toFixed(3));
保留三位小数,但数据类型变为字符型。
toFIxed()转为字符串,保留多位小数。
进制转换:
十进制转二进制(除2取余)
二进制转十进制,根据对应的尾数乘以对应的2的次方将所有值相加
十进制转8进制(除8取余)
十进制转16进制(除16取余)
将二进制,八进制,十六进制转换为十进制(parseInt,parseFloat)
将十进制转成二进制,八进制,十六进制(number.toString(8))55
前面写0x表示当前是一个16进制数
前面写0 ,当前为十进制还是八进制具体还是看后面的数值。