一. JavaScript概念
- 是一种
脚本语言
(不具备开发系统的能力),是一种弱语言,可以直接解析执行。 - 运行在
客户端浏览器
上面 - 与操作系统无关,是一种
跨平台语言
。
二. 命名规则
- 只能以字母、下划线、$开头。
- 对大小写敏感。
- 不能使用
关键字
命名,例如:if,break,new,case,then,catch,class,continue,const,let,var等。
三. 变量类型
- 基本类型:
- number
- string
- 布尔值
- undefined
- null
- symbol(es6里面新增的)
- 引用类型:
- Array(数组)
- Object(对象)
- Function(函数)
四. 基本类型和引用类型的区别
- 基本类型:
- 占用空间固定,保存在
栈
中。 - 保存与复制的是值得本身,改变其中之一不会影响到另一个。
- 使用typeof检测数据类型
- 基本类型数据是值类型
- 占用空间固定,保存在
- 引用类型:
- 占用空间不固定,保存在
堆
中。 - 保存与复制是指向对象的一个指针。
- 使用instanceof检测数据类型。
- 使用new()方法构造出的对象是引用类型。
- 占用空间不固定,保存在
// 值类型:numbe、string、undefined
var a = 100
var b = a
a = 200
console.log(a) // 200
console.log(b) // 100,改变a不会影响到b
// 引用类型:对象、数组、函数
var arr1 = [1,2,3,4]
var arr2 = arr1
arr1[0] = 8
console.log(arr1) // [8,2,3,4]
console.log(arr2) // [8,2,3,4] 改变arr1会影响arr2
var obj1 = {name:'xiaoming'}
var obj2 = obj1
obj1.name = 'xiaohong'
console.log(obj1) // xiaohong
console.log(obj2) // xiaohong 改变obj1会影响obj2
// typeof 可以检测区分基本数据类型
typeof 123 // number
typeof 'gfsjhfgh' // string
typeof true // boolean
typeof undefined // undefined
// typeof 不可以区分引用数据类型
typeof {} // object
typeof [] // object
typeof null // object,注意null
typeof NaN //number
typeof isNaN //function
五. 字符串
- 字符串的长度:str.length
- 字符串的索引:str[number]
- 字符串的拼接:str1.cancat(str2),返回一个新的字符串str1和str2本身没有改变,也可以用于数组。
- 字符串的创建:str='h’或者str=new String(‘h’)
- 字符串的截取:
- str.substring(n1,n2) 从
n1位置截取到n2位置,包括n1不包括n2,两者之间可以互换位置
,返回一个新的被截断下来的字符串,不改变原来的字符串。 - str.substr(n1,n2)
从n1开始截取n2个元素
,返回一个新的被截断下来的字符串,不改变原来的字符串。 - str.slice(n1,n2) 和 str.substring(n1,n2) 一样只是
不能交换两者之间的位置
,返回一个新的被截断下来的字符串,不改变原来的字符串,也可以用于数组的截断。 - 注意:以上三个当只设置了一个值表示从该位置截取到最后一位。
- str.substring(n1,n2) 从
- 字符串的查找:str.indexOf(s,num):从str的num位置开始查找s这个字符,
如果有则返回s这个字符在str中第一次出现的位置,如果没有则返回-1
,不写num表示从头开始查找。str.lastIndexOf(s,num) 查到返回最后一次出现的位置 - 字符串的替换:str.replace(oldstr,newstr),
只替换第一次出现的位置
,生成一个新字符串,如果被替换的字符不存在则返回原字符串。不改变原字符串 - 删除字符串两端的空格: str.trim() 不会原字符串产生影响,生成一个去除空格后的新的字符串。不改变原字符串
- 字符串的大小写转换
- 转换为大写:str.toUpperCase() 不改变原字符串
- 转换为小写:str.toLowerCase() 不改变原字符串
- 字符串分割:str.split(‘指定分割的地方’),将一个字符串分割成指定形式的
数组
。
const str = 'studyStudent'
// 1. 字符串长度
str.length // 12
// 2.字符串的索引
str[5] // 'S'
// 3. 字符串的拼接
const str1 = 'happy'
str + str1 // 'studyStudenthappy'
str.concat(str1) // 'studyStudenthappy'
// 4. 字符串的截取:
str.substring(2,5) // 'udy' 等价于:str.substring(5,2)
str.substr(2,5) // 'udySt'
str.slice(2,5) // 'udy'
// 5. 字符串的查找
str.indexOf('t') // 1
str.lastIndexOf('t') // 11
// 6. 字符串的替换
str.replace('t','mm') // smmudyStudent
str.replace('w','mm') // w字符不存在,返回原字符串studyStudent
// 7.删除字符串两端的空格
const str2 = ' fjsdfh '
str2.trim() // fjsdfh
// 8.字符串的大小写转换
str.toUpperCase() // STUDYSTUDENT
str.toLowerCase() // studystudent
// 9.字符串分割
str.split('') // ['s', 't', 'u', 'd', 'y', 'S', 't', 'u', 'd', 'e', 'n', 't'] 分割每一个字符
六. 数组
- 数组的创建:arr=[] 或者arr=new Array()(不加new关键字也可以)
- 数组的删除:
- arr.pop() 删除数组中的最后一个元素
返回删除的元素
,会改变原数组 - arr.shfit() 删除数组中的第一个元素
返回删除的元素
,会改变原数组 - delete arr[] 返回一个布尔值,会改变原数组,
但是不改变原数组的长度,被删除的部分用empty来代替
。
- arr.pop() 删除数组中的最后一个元素
- 数组的添加:
- arr.push() 在数组的末尾添加一个元素,
返回新数组的长度
,会改变原数组 - arr.unshift() 在数组的首位添加一个元素,
返回新数组的长度
,会改变原数组
- arr.push() 在数组的末尾添加一个元素,
- 数组的截断:
- arr.slice(n1,n2) 从n1开始截断到n2,不包括n2,返回一个新的截断出来的数组,不改变原来的数组
- arr.splice(n1,n2,n3…) 从n1开始截取n2个元素,并用n3,…来代替被截取的部分 ,返回一个新的截断出来的数组,
会改变原数组
- 数组的排序:
arr.sort() 按照编码顺序
排序,例如arr=[1,2,12,4,25] arr.sort()=[1,12,2,25,4] - 数组的拼接:
- arr.concat(arr2) 生成一个新的数组,会改变原数组
- 扩展运算符:[…arr1,…arr2]
- 数组转字符串:arr.join(‘连接符’) 以规定的连接符将数组连接成字符串。
// 1.数组的删除
const arr = [1,2,3,4,5,6]
arr.pop() // 6
arr.shift() // 1
delete arr[2] // true
arr // [2,3,empty,5]
// 2. 数组的添加
const arr = [1,2,3,4,5,6]
arr.push(7) // 7
arr.unshift(-1) // 8
arr // [-1, 1, 2, 3, 4, 5, 6, 7]
// 3. 数组的截断
const arr = [1,2,3,4,5,6]
arr.slice(1,5) // [2, 3, 4, 5]
arr // [1, 2, 3, 4, 5, 6]
arr.splice(1,4) // [2, 3, 4, 5]
arr // [1,6]
// 4. 数组的排序(按编码)
arr = [1,2,12,4,25]
arr.sort() // [1, 12, 2, 25, 4]
// 5.数组的拼接
arr2 = [7,8,9]
arr.concat(arr2) // [1,2,3,4,5,6,7,8,9]
[...arr1,...arr2] // [1,2,3,4,5,6,7,8,9]
// 6.数组转字符串
arr3 = [2,3,1,5,6]
arr3.join(',') // 用逗号来连接'2,3,1,5,6'
七. 对象
- 对象创建
- const obj={}
- const obj=new Object()
- const obj=Object.create(null)
- 对象的读取
- obj.key
- obj[‘key’]
- 获取对象的键:Object.keys(obj)
- 获取对象的值:Object.value(value)
// 1.对象值得读取
obj = {name:'jiajia',age:18}
obj.name // jiajia
obj['name'] // jiajia
// 2. 获取对象的键
Object.keys(obj) // ['name', 'age']
// 3.获取对象的值
Object.values(obj) // ['jiajia', 18]
八. 函数
-
函数的声明
- function name(){} 具有隐式提升的效果,可以将调用放在定义之前
- var name=function(){} 不具有隐式提升的效果,只能先定义后调用(匿名函数)
- var name=new Function(){} 一般不用这种
-
函数作用域
- 全局作用域:作用于整个程序,会作为windows对象的属性和方法保存
- 局部作用域(块级作用域):作用于当前所在的{}内函数内部
-
变量类型
- 全局变量:在全局作用域中通过var申明的变量
- 局部变量:在块级作用域中申明的变量
-
变量提升(重点)
- 概念:无论在函数体的哪一个部位声明了变量,都相当于在函数的头部声明
- 条件:
通过var声明
- 例如:
console.log(num); // undefined
var num=1;
相当于:
var num;
console.log(num); // 1
num=1
九. DOM
- 定义:Document Object Modal 一套用来管理html文档的规则
- 节点属性:
document.getElementsByClassName('class')
返回指定类名的节点集合- document.getElementsByTagName() 返回指定标签属性的节点集合
- document.getElementsByName() 返回拥有name属性的html元素
document.getElementById()
返回指定id的节点document.querySelector('.class')
(最重要) 可以返回class属性节点,如果有多个则返回第一个,也可以返回 id属性节点- document.querySelectorAll() 返回具有某一属性的节点集合
- document.createElement(‘标签’) 创建一个标签,需要配合appendChild()使用
- document.body.removeChild(‘标签’) 从DOM中删除标签
例如:
var p=document.createElement(‘p’) // 创建一个p标签
p.innerHTML=‘内容’ // 往p标签里面添加内容
document.body.appendChild§ // 将p标签添加到htmlDOM结构中 - document.createAttribute(‘属性名’) 创建元素属性值
- document.getAttribute(‘属性名’) 获取元素属性值
- document.setAttribute(‘属性名’) 设置元素属性值
- document.removeAttribute(‘属性名’) 删除元素属性值
十. 事件
- 传递方式:
事件冒泡
:由最具体的元素开始,沿着DOM树逐级向上传递至最不具体的元素- 事件捕获:由最不具体的元素开始,沿着DOM树逐级向下传递至最具体的元素
- 事件冒泡和事件捕获是互逆的过程
事件委托
:将原本在子元素上面绑定的属性,现在绑定到他的父元素上面,通过父元素来监听子元素的变化,利用的原理:事件冒泡- 阻止事件冒泡:e.stopPropagation()
- 阻止事件默认行为:event.preventDefault()
- 事件绑定
- 直接绑定:
DOM0事件
var btn=document.querySelector(‘.btn’)
btn.οnclick=()=>{}DOM2事件
btn.addEventListener(‘click’,f1,布尔值);- click: 绑定的事件类型
- f1:监听函数
- 布尔值:
- true: 代表事件捕获
- false: 代表事件冒泡(默认取false)
- 鼠标事件
单击事件:btn.onclick=function(){}
- 双击事件:btn.οndblclick=function(){}
- 鼠标按下时触发:div.οnmοusedοwn=function(){}
- 鼠标抬起时触发:div.οnmοuseup=function(){}
- 鼠标移动时触发:div.οnmοusemοve=function(){}
- 鼠标移入时触发:
- div.οnmοuseenter=function(){} 不冒泡
- div.οnmοuseοver=function(){} 冒泡
- 鼠标移出时触发:
- div.οnmοuseleave=function(){} 不冒泡
- div.οnmοuseοut=function(){} 冒泡
十一. this指向
- 描述:指向当前对象的调用者
- 指向:
- 在html事件:指向window
- 在DOM0事件:指向函数的调用者,
- 在DOM2事件:指向函数的调用者
- 对象方法调用:指向该方法所属的对象
- 间隔调用 (setInterval)和延迟调用(setTimeout)指向window对象
- call/apply/bind: 第一个参数是什么就指向什么,如果是null就代表指向window
- 闭包:指向window
- 自执行函数:指向window
- 构造函数中:指向实例对象
- 箭头函数:本身不会创建自己的this指向外层作用域中的this
十二. 间隔调用和延迟调用
- var timer=
setInterval
(()=>{},time) 每隔一段时间调用一次,重复多次调用- 清除:clearInterval(timer)
- var timer=
setTimeout(
()=>{},time) 延迟一个时间调用一次,只会调用一次- 清除:clearTimeout(timer)
- 用setTimeout来实现setInterval的效果
var timeFun = function(){
var timer = setTimeout(()=>{
timeFun(); // 一定要调用外层函数
clearTimeout(timer)
},1000)
}
timeFun();
十三. 页面优化
- 将css放在html的头部,js代码放在尾部
- defer(推迟)
- 语法:
<script src='' defer>
- 作用:等待DOM加载完成之后才会去加载js脚本,避免js脚本过大或者网络卡顿造成的文件阻塞现象
- 语法:
- async(异步)
- 语法:
<script src='' async>
- 作用:异步执行,不必按照顺序等待上一个执行完毕再执行,提高程序的执行效率
- 语法:
- 尽量减少引起页面的回流和重绘
十四. 回流
- 回流:当页面中有元素的高度,宽度,位置,显示,隐藏发生变化或者增删了元素,
引起了页面重新渲染
的过程,称之为回流,代价高昂。 - 重绘:页面的背景颜色等属性发生改变,引起的页面重新渲染的过程。
- 回流必然会引起重绘,重绘不一定会引起回流。回流页面的结构发生了变化,重绘不会
- 如何减少页面的回流和重绘:
- 在改变样式的时候尽量一次性写完
- 读写的DOM尽量写在一块
- 使用文档碎片
十五.call()、apply()、bind()
作用:都是用来重新定义this的绑定对象
,动态的改变函数的运行环境
- call(参数一,参数列表) 立即执行
- 参数一:绑定给this的,如果为null或者undefined则this默认指向window
- 例子:求一个数组的最大值:
var arr=[1,4,3,5,78,65]
var max=Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5])
console.log(max); // 78
- apply(参数一,参数二) 立即执行
- 参数一:绑定给this的,如果为null或者undefined则this默认指向window
- 参数二:一个数组
- 例子:求一个数组的最大值:
var arr=[1,4,3,5,78,65]
var max=Math.max.apply(null,arr)
console.log(max); // 78
- bind(参数一,参数列表)(); 不会立即执行
- 和call非常相似,只是返回的是函数
- 例子:求一个数组的最大值:
var arr=[1,4,3,5,78,65]
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5])();
console.log(max); // 78
十六. 闭包
- 概念:在函数的内部定义一个函数,使其能够读取其他函数的局部变量
- 作用:读取其他函数的内部变量,是将函数的内部和外部连接起来的桥梁,可以用来实现模块化
- 形成条件:函数的嵌套
- 特性:
- 封闭性:外界无法访问闭包内的数据,除非闭包向外界主动提供接口
- 持久性:一般函数在被系统调用之后都会被注销掉,对于闭包而言,当外部函数被调用之后不会被立即注销
- 优缺点:
- 优点:
延长外部函数局部变量的生命周期
- 缺点:
过多的占用内存,造成内存泄漏
- 优点:
- 注意:所有闭包中的this都是指向window
- 语法:
var fun1 = () => {
var num = 999;
var fun2 = () => {
return num
}
return fun2;
}
fun1()();
十七. 类和对象
- 类的创建:通过构造函数加上new一个实例化的方式实现(es5中)
- 创建:
- 创建一个构造函数
- 通过new实例化
- 语法:
function Person(属性1,属性2,...){
// 公有属性
this.属性1=属性1;
this.属性2=属性2;
...
// 私有属性
var 私有属性1=属性值;
...
// 通过特权函数来调用私有属性
this.getFun=()=>{
}
// 通过原型的方式添加公有属性
Person.prototype.属性=属性值; // 属性值可以是一个函数
}
var people=new Person(具体的公有属性值);
// 例子
function People(pname,ability){
// 通过this添加公有属性
this.pname=pname;
this.ability=ability;
// 用局部变量方式添加私有属性
var secret = '梦开始的地方';
// 特权函数
this.getSecret=function (){
console.log(secret)
}
// 通过原型的方式添加一些公有属性
People.prototype.eyesNum=2
People.prototype.breathe=function(){
console.log('都要呼吸')
}
}
var fun=new People('汪小姐',function(){ console.log('要美丽!')});
fun.pname // 汪小姐
fun.ability() // 要美丽
fun.getSecret() // 梦开始的地方
fun.eyesNum // 2
fun.breathe() // 都要呼吸
十八. 原型概述
- 原型prototype
- 描述:是js为函数提供的一个对象类型属性,归函数所有
- 说明:向原型中添加的属性和方法能够被共同拥有
- 注意:如果是通过类创建的对象,当访问一个属性的时候,首先会在这个对象中寻找,如果没有就去创建这个对象的类的原型中寻找。
- 缺点:
原型中不能够保存数组这一引用类型数据
,因为地址的改变可能会导致出现修改的连锁变化。
- 原型属性:
- 构造器:constructor:该属性指向了这个类本身
原型指向__proto__: 该属性指向了原型本身
原型链:
- 每一个对象都有一个原型__proto__,这个原型还可以有自己的原型,以此形成一个原型链
- 在访问对象的属性和方法的时候,首先在对象本身中查找是否拥有这个属性,如果没有就沿着原型链向上逐级查找
到查找到顶端object为止
- 注意:
原型链的顶端是一个object
,没有__proto__属性了 - prototype和__proto__的区别
prototype是函数才具有的属性,__proto__是每一个对象都有的属性
十九. 继承
- 原型链继承
// 第一步创建父类并实例化
var Father=function(){
Father.prototype.money='有钱人'
}
var father=new Father()
// 第二步创建子类并实例化
var Son=function(){
}
Son.prototype=father // 必须要让子类的原型指向父类
var son=new Son()
console.log(son.money) // 有钱人
- 构造继承
- 特点:可以实现多继承
- 缺点:只能实现父类实例的属性和方法
- 实例继承:为父类实例添加新特性,作为子类实例返回
- 拷贝继承:拷贝父类元素上的属性和方法
- 组合继承:结合了原型继承和构造继承
- 既能实现父类实例的继承也能实现原型上的继承
- 缺点:生成两份实例
- 寄生组合继承
- 特点:解决组合继承中的弊端
- 思想:通过寄生的方式砍掉父类
- 在原型上添加属性和this添加属性有什么区别:给对象原型添加属性的话,则用new方法创建的对象也会自动具有新添加的属性。而只给对象添加属性的话则不会影响到新创建的对象。
var Father=function(){
Father.prototype.money=‘有钱人’
this.name = name
}
var father = new Father()
var father2 = new Father
二十. Json
- 概念:是js对象的字符串表达形式,本质上是一个字符串
- 特点:
- 一种轻量级的数据交换格式
- 是前后端数据交换的纽带
- Json方法:
- Json.parse(后台传过来的数据):把json数据格式转化为js数据类型
- Json.stringify(向后台传递的数据):把js数据类型转化为json数据格式。
二十一. 如何实现瀑布流
分析思路:
1. 定义一个数组用于存放第一列图片的高度(视口高度+图片高度)
2. 计算高度,将下一张图片放到高度最小的那一张图片下面。然后计算新的高度,再把下一张图片放到高度最小的图片下面以此类推。
二十一. 如何实现图片懒加载
- 分析思路:当视口高度加上鼠标滚动高度>图片距离顶端的高度的时候,请求这部分的图片数据。
- 实现
document.element.clientHeight + document.elment.scrollTop > element.offsetTop
二十二. 说一说按需加载和路由懒加载
按需加载:
- 说明:当一个文件或者模块只有当它需要用到的时候再去加载它,有利于前端性能的优化
- 例如:当点击按钮的时候加载文件
const oBtn = document.querySelector(‘#btn’)
oBtn.addEventListener(‘click’, () => {
import(‘./ajax’).then(mod => {
// console.log(mod)
mod.default(‘static/a.json’, res => {
console.log(res)
})
})
})
路由懒加载:
const Login=()=>import(/webpackChunkName:login_home_welcome/ ‘…/components/Login’)
import Login from ‘…/components/Login’(路由的一般写法,这个不是懒加载,上面的是路由懒加载)
二十三. 命令式编程,声明式编程,函数式编程
- 命令式编程:主要思想是关注计算机执行的步骤,一步步告诉计算机先做什么,在做什么。
- 声明式编程:告诉计算机应该做什么,但不指定具体怎么做,以数据结构的形式来表达程序执行的逻辑。不包含 for,if 代码
- 函数式编程:函数放在第一位,函数可以出现在任何地方,函数可以作为参数传递,函数可以作为返回值返回