一、数据类型
1、基本数据类型:Number,String,Boolean,Null,Undefined。
2、引用类型:Object。
1)Number.MAX_VALUE:Number所能表示的最大值:1.7976931348623157e+308;
2)Number.MIN_VALUE:大于0的最小值: 5e-324 ;
3)Null的值只有一个:null;用来表示一个空的对象,用typeof检查其类型,返回的是object ;
4)用typeof检查NaN,返回的是number;判断一个变量是不是NaN,使用isNaN()函数
二、强制类型转换
主要是指其他类型转换为String,Number,Boolean
1、其他类型转换为String
1)调用toString()。但Null和Undefined没有toString()方法;
2)调用String函数,对于Number和Boolean实际上是调用toString(),对于Null和Undefined,则是直接将unll转换为"null",将undefined转化为"undefined";
3)隐式转化:+ “”
2、其他类型转换为Number
–使用Number()函数
1)String—>Number
---- a、如果字符串是纯数字,则直接转换:“123”–>123 ;
-----b、如果字符串中有非数字内容,转换为NaN ;
-----c、字符串为空串或者只有空格,转换为0 ;
2)Boolean—>Number: true–>1 ;false—>0;
3)Null—>Number:转换为0 ;
4)Object—>Number:转化为NaN ;
5)undefined–>Number:转化为NaN
–使用parseInt()和parseFloat() :仅用于字符串
可以在parseInt()中传入第二个参数,来指定数字的进制,如parseInt(a, 10),表示十进制
3、其他类型转换为Boolean
调用Boolean()函数
1)Number—>Boolean :除了0和NaN,其他全为true;
2)String—>Boolean :除了空串,其他全为true;
3)Null—>Boolean : false;
4)Undefined—>Boolean : false;
5)Object—>Boolean : true;
三、JS的三种逻辑运算:&&;||;!
对于非布尔类型的,先将其转换为布尔类型;但是结果返回的是原类型,而非布尔类型;
1、&&
1)true&&true:结果返回后面一个;
2)false&&true:结果返回false的那个;
3)false&&false:结果返回前面那一个;
2、||
1)true||true:结果返回前面一个;
2)false||false:结果返回后面一个;
优先级:!、&&、||
四、JS的if、switch、while、for
与其他语言类似
五、对象
1、对象的分类
1)内建对象:由ES标准中定义的对象,在任何的ES实现中都可以使用;
如:Math,String,Number。。。
2)宿主对象:由JS的运行环境提供的对象,目前一般指由浏览器提供的对象
如:BOM(浏览器对象模型),DOM(文档对象模型)
3)自定义对象:由JS开发人员创建的对象
2、创建对象的两种方式
1)使用new关键字:var obj=new Object();
2)使用字面量:var obj={};
使用in 可以判断对象中是否有某个属性,语法:“属性名” in 对象
枚举对象使用for…in;语法:for(var key in 对象){}
3、基本数据类型和引用类型的内存分析
JS的变量都是保存在栈内存中的
1)基本数据类型的值直接在栈内存中保存,值与值之间相互独立;
2)对象是保存在堆内存中的,每当创建一个对象,就会在堆内存中开辟一个新的内存区域;而变量保存的是对象的地址(对象的引用);
六、函数
1、创建函数
1)使用函数声明创建函数: function 函数名([形参1,形参2…]){}
2)使用函数表达式创建函数:var 函数名=function([形参1,形参2…]){}
1.return后的代码不会执行,return后不跟任何值或不写return,函数的返回值相当于undefined
2.使用函数声明形式创建的函数,它会在所有代码执行前被创建,所以我们可以在函数声明前调用函数,而使用函数表达式形式创建函数不会被声明提前
2、立即执行函数
有些函数只想执行一次,不需要使用var创建,使用匿名函数:(function(){})();
3、枚举对象中的属性
使用for…in语句:for(var 变量名 in 对象){};
对象有几个属性,循环体就执行几次,每次将一个对象的属性名赋给变量
4、作用域
JS有两种作用域
1)全局作用域
a、直接编写在script标签中的JS代码,都是全局作用域;
b、全局作用域在页面打开时创建,在页面关闭时销毁;
c、在全局作用域中有一个全局对象window:它代表的是一个浏览器窗口,它由浏览器创建,我们可以直接使用;
d、在全局作用域中,创建的对象都会作为window对象的属性保存;创建的函数都会作为window对象的方法;
e、全局作用域中的变量都是全局变量:在页面中的任何部分的可以访问得到;
2)函数作用域
a、调用函数时创建函数作用域,函数执行结束时函数作用域销毁;
b、在函数作用域中可以访问到全局变量,但在全局作用域不能访问到函数作用域中的变量;
c、在函数作用域中操作一个变量,它会现在自身查找,有则直接使用;没有就到它的上一级去查找,直到全局作用域;
d、在函数中要访问全局变量的,则使用window.全局变量名;
e、在函数中,不使用var声明的变量都会变成全局变量
5、函数的方法:call()和apply()
当对函数调用call()和apply()时,都会调用函数执行;
在调用call()和apply()时,可以将一个对象指定为第一个参数,此时这个对象将会成为函数的this;
1)fun.call(对象,实参1,实参2…):实参在对象之后依次传递;
2)fun.apply(对象,[实参1,实参2]):将实参封装到一个数组中传递;
6、this情况
1)以函数形式调用,this永远指向window;
2)以方法形式调用,this指向调用它的那个,谁调指谁;
3)以构造函数形式调用,this指向新创建的那个对象;
4)使用call()和apply()调用时,this是指定的那个对象;
7、arguments
在调用函数时,浏览器传递两个隐含的参数:一个是函数上下文this,一个是封装实参的对象arguments;
1)arguments是一个类数组对象,也可以通过索引来操作,也可以获取长度;
2)在调用函数时我们传递的实参都会在arguments中保存;
3)arguments.length可以用来获取实参的长度(个数);
4)arguments有一个属性:callee-----对应一个函数对象,就是正在执行的函数对象
8、构造函数
构造函数与普通函数的区别就是调用方式的不同,构造函数使用new 关键字来调用
构造函数的执行流程
1)立即创建一个新的对象
2)将新建的对象设置为函数的this
3)逐行执行函数中的代码
4)将新建的对象返回
可以使用instanceof来检查一个对象是否是一个类的实例;语法:对象 instanceof 构造函数
七、原型:prototype
1、 我们所创建的每一个函数,解析器的会向函数添加一个属性:prototype, 这个属性对应着一个对象,这个对象就是我们的原型
2、当函数以构造函数调用时,它所创建的对象中都有一个隐含的属性, 指向该构造函数的原型对象,可以用__proto__访问;
实例对象.__proto__ == 构造函数.prototype
3、用in检查一个对象是否含有某个属性时,如果对象中没有,而原型中有,也会返回true;可以使用hasOwnProperty()来检查对象自身中是否含有某个属性,只有当对象自身中含有时才会返回true;语法:对象.hasOwnProperty(‘属性名’)
3、原型对象也是对象,所以它也有原型;当我们使用一个对象的属性或方法时,它会先在自身查找,如果有,则直接使用;如果没有,就去它的原型中找,如果有则使用;如果没有,就再去它的原型的原型中找,直到找到Object的原型。Object对象的原型没有原型,如果在Object对象的原型中还没有找到,则返回Undefined。这样一层一层地查找,就构成了原型链;
八、垃圾回收
当一个对象没有任何变量或属性对它进行引用时,这个对象就成了垃圾;JS中有自动的垃圾回收机制,我们只须将对象设置成null即可。
var obj=new Object();
obj=null;
九、数组
使用typeof检查一个数组返回的是object
1、数组的长度length属性
a、对于连续的数组,返回数组的长度;对于非连续性的数组,长度为最大索引值+1;
b、 设置数组的长度length
当设置的length大于数组有的元素时,其他会留出内存
当设置的length小于数组有的元素时,多出的元素会被直接删掉
c、向数组的最后添加元素:数组[数组.length] = 元素值
d、使用数组字面量和Array构造函数创建数组时的区别:
var arr = [10] //表示创建一个数组并且数组中只有一个元素10
var arr = new Array(10) //表示创建一个长度是10的数组
2、数组的常用方法
1)push():向数组的末尾添加一个或多个元素,并将新数组的长度返回;
2)pop():删除数组最后一个元素,并将被删除的元素作为返回值返回;
3)unshift():向数组的开头添加一个或多个元素,并将新数组的长度返回;
4)shift():删除数组的第一个元素,并将被删除元素作为返回值返回;
5)slice():从数组中提取指定元素;该方法不会改变原数组,只是将提取出来的元素封装到一个新数组中返回;
参数:
----第1个参数:截取开始位置的索引,包括开始索引
----第2个参数截取结束位置的索引,不包括结束索引
----参数可以是负值,-1代表倒数第一个,-2表示倒数第二个。。。。
----第二个参数可不写,表示从开始位置往后全部截取
6)splice():用来删除指定数组元素,还可以向数组中插入新元素;
该方法会影响原数组,将指定元素从原数组中删除,并将删除的元素返回
参数:
— 第一个参数:开始删除位置的索引
----第二个参数:删除的数量~~~
— 第三个参数及以后。。。: 可以传递一些新的元素,这些元素将在删除位置索引前插入
7)concat():连接两个或多个数组,并将新的数组返回;不影响原数组,只是将结果返回;
8)join():将数组以字符串形式返回,不影响原数组;
参数作为字符串连接的连接符,如果没有指定,则使用逗号(,)连接;
9)reverse():将数组反转,会影响原数组;
10)sort():将数组进行排序,按照Unicode编码排序;会影响原数组;
注:但对于纯数字也是按照 Unicode编码排序,可能会出错;如[2,3,11,5]
所以我们可以自定义排序规则:在sort()中定义一个回调函数,来指定排序规则
sort(function(a,b){}:需要两个参数,浏览器会将数组中 元素作为实参调用回调函数;浏览器会根据回调函数的返回值来进行排序:
----a、返回值大于0;则元素交换位置;
----b、返回值大于0;则元素位置不变;
----c、返回值大于0;认为两个元素相等也不交换位置;
return a-b:升序
return b-a:降序
3、数组的forEach()
我们一般用for循环来遍历数组,但也可以使用数组提供的forEach方法
forEach()需要一个函数作为参数:这种函数由我们创建的但不由我们调用的,我们称作回调函数,数组中有几个元素,就回调几次; 每次执行时,浏览器会将遍历到的元素以实参的形式传递进来;
- 浏览器会传给这个函数 三个参数:
第一个参数:正在遍历的数组的元素;
第二个参数:正在遍历的数组元素的索引;
第三个参数:正在遍历的数组;
十、Date对象
var d = new Date() // 创建一个Date对象,表示当前日期时间
方法:
1)getTime():返回1970/1/1至今的毫秒数
2)getDate():返回一个月中的某一天(几号)
3)getDay():返回一周中的星期几
4)getFullYear():返回Date对象的年份
5)getMouth():返回月份
6)getHours():小时
7)getMinutes():分
8)getSeconds():秒
获取当前时间戳:Date.now()
十一、包装类
JS提供了三个包装类:String,Number,Boolean;
1、String()可以将基本数据类型的字符串转换成String对象;
2、Number()可以将基本数据类型的数字转化为Number对象;
3、Boolean()可以将基本数据类型的布尔值转化为Boolean对象;
开发者不用,只是浏览器底层自己用,临时封装;
十二、字符串的一些常用方法
length属性:获取字符串的长度
1、charAt():返回指定位置的字符;
2、charCodeAt():返回指定位置字符的Unicode编码;
3、String.fromCharCode();返回指定Unicode编码的字符;值得注意的是,这里使用String调用;
4、slice(start, end):用来截取字符串,不会影响原字符串;与数组的slice()类似;
5、substring();也是截取字符串,与slice()不同的是,substring()不能传递负数,如果传递负数,则认为是0; 如果第二个参数比第一个参数大,它会自动交换位置;
substr(start,截取的长度):也是截取字符串
6、split():将字符串拆分为数组;需要一个字符串作为参数,这个参数就是拆分的条件:如果参数为空串,则将每一个字符都拆分为一个数组元素;
7、concat():连接字符串
8、indexOf():检索一个字符串中是否含有指定字符;如果有,返回第一次出现的索引,没有就返回-1
可以指定第二个参数,指定开始查找的位置
9、lastIndexOf():用法与indexOf一样,不同的是lastIndexOf是从后往前找
10、toUpperCase():将字符串转化为大写并返回
11、toLowerCase():将字符串转化为小写并返回
十三、闭包
1、如何产生闭包
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数中的变量时,就形成了闭包。
闭包存在于嵌套的内部函数中
产生闭包的的条件:1.函数的嵌套;2.内部函数引用外部函数的数据(变量/函数)
function fn1(){
var a = 1
function fn2(){
console.log(a)
}
}
fn1()
2、常见的闭包
1、将函数作为另一个函数的返回值
function fn1(){
//闭包产生:在嵌套内部函数定义执行完就产生
var a = 2
function fn2(){
a++
console.log(a)
}
return fn2
}
var f = fn1() // 调用fn1时,闭包产生
f() //输出3
f() //输出4
//闭包死亡(包含闭包的函数对象成为垃圾对象)
f = null
3、闭包的作用
1、使函数内部的变量在函数执行完后仍然存活在内存中
2、让函数外部可以操作到函数内部的数据(变量/函数 )
十四、继承
1、原型链继承
步骤:
1、定义父类型的构造函数
2、给父类型的原型添加方法
3、定义子类型的构造函数
4、设置子类型的原型为父类型的一个实例对象
5、将子类型原型的构造属性设置为子类型
6、给子类型原型添加方法
7、创建子类型的实例对象,可以调用父类型的方法
//父类型
function Supper(){
this.supProp = 'supper property'
}
Supper.property.showSupperProp = function(){
console.log(this.supProp)
}
//子类型
function Sub(){
this.subProp = 'sub property'
}
//子类型的原型为父类型的一个实例对象
Sub.property = new Supper()
//让子类型的原型的constructor指向子类
Sub.property.constructor = Sub
Sub.property.showSubProp = function(){
console.log(this.subProp)
}
var sub = new Sub()
sub.showSupperProp() // 子类型的实例可以调用父类型的方法了
2、组合继承
原型链+借用构造函数的组合继承
1、利用原型链实现对父类型对象的方法继承
2、利用call()借用父类型构造函数初始化相同属性
//父类型
function Persion(name, age){
this.name = name
this.age = age
}
Persion.property.setName = function(name){
this.name = name
}
//子类型
function Student(name, age, price){
Persion.call(this, name ,age) // 为了得到name,age属性
this.price = price
}
//子类型的原型为父类型的一个实例对象
Student.property = new Persion() // 为了能够看到父类型的方法
//让子类型的原型的constructor指向子类
Student.property.constructor = Student //修正constructor属性
Student.property.setPrice = function(price){
this.price = price
}
var stu= new Student('Tom', 24, 15000)
stu.setName('Bob')
stu.setPrice(16000)
console.log(stu.name, stu.age, stu.price) //输出Bob,24,16000
十五、线程机制和事件机制
1、浏览器内核
浏览器内核由很多模块组成:
1.js引擎模块:负责js程序的编译与运行
2.html,css文档解析模块:负责页面文本的解析
3.DOM/CSS模块:负责DOM/CSS在内存中的相关处理
4.布局与渲染模块:负责页面的布局和效果的绘制(内存中的对象)
前4个是主线程
5.定时器模块:负责定时器的管理
6.事件响应模块:负责事件的管理
7.网络请求模块:负责ajax请求
分线程
2、js是单线程的
setTimeout()的回调函数是在主线程中执行的,只有当运行栈中的代码全部执行完,才开始执行定时器的回调函数
1、js引擎执行代码的基本流程:
1)先执行初始化代码
2)设置定时器
3)绑定监听
4)发送ajax请求
5)后面在某个时刻才会执行回调函数
3、事件循环模型
1、模型的两个重要组成部分:事件(定时器/DOM/Ajax)管理模块、回调队列
2、模型的运转流程:
1)执行初始化代码,将事件回调函数交给对应模块管理
2)当事件发生时,管理模块会将回调函数及其数据添加到回调队列中
3)当初始化代码执行完后,才会遍历读取回调队列中的回调函数执行 (放到执行栈中执行)
十六、ES6及后面的新特性
1、let和const、模板字符串、Symbol数据类型、promise
2、结构赋值
从一定的模式从数组或对象中提取值,对变量进行赋值(对象的解构赋值用的多)
如:const obj = {name: ‘张三’, age: 10}
let {name, age} = obj
3、箭头函数
特性:
1、this是静态的,this始终指向函数声明时所在作用域下的this值;
2、不能作为构造函数使用
3、不能使用arguments变量(因为箭头函数没有arguments)
4、rest参数
用于获取函数的实参,用于替代arguments
区别:arguments是一个类数组对象,rest参数返回的是一个数组,可以使用数组的方法更方便操作参数
function fn(a, ...args){
console.log(args)
}
如果函数中还有其他参数,rest参数要放在最后
5、扩展运算符…
可以将数组转为参数序列
应用:
1)数组合并
2)数组克隆
3)将伪数组转为真正的数组
const arr1 = ['赵', '钱']
const arr2 = ['孙', '李']
const arr = [...arr1, ...arr2] //['赵', '钱', '孙', '李']
const copyArr = [...arr] //浅拷贝
const divs = document.querySelectorAll('div')
const divArr = [...divs]
6、迭代器
迭代器是一种借口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator接口,就可以使用for…of遍历
1)原生具备Iterator接口的数据:Array、Arguments、Set、Map、String、TypedArray、NodeList
2)工作原理:
a.创建一个指针对象,指向当前数据结构的起始位置;
b.第一次调用对象的next()方法,指针自动指向数据结构的第一个成员;
c.接下来不断调用next()方法,指针不断向后移动,直到指向最后一个成员;
d.每调用next()方法,返回一个包含value和done属性的对象
3)应用:自定义遍历数据
7、生成器
其实是一个特殊的函数,用于异步编程
//实例:模拟获取数据:先获取用户数据,再获取订单数据,再是商品数据
function getUser(){
setTimeout(()=>{
let data = '用户数据'
//调用next()可传递参数,第二次调用next()传递的参数将作为第一次yield语句的结果
iterator.next(data)
},1000)
}
function getOrder(){
setTimeout(()=>{
let data = '订单数据'
//第三次调用next()传递的参数将作为第二次yield语句的结果
iterator.next(data)
},1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据'
//第四次调用next()传递的参数将作为第三次yield语句的结果
iterator.next(data)
},1000)
}
//定义一个生成器
function * gen(){
let user = yield getUser()
let order = yield getOrder()
let goods = yield getGoods()
}
//调用生成器函数
let iterator = gen()
iterator.next() // 要调用next()才是调用生成器函数
8、Set(集合)
类似于数组,但成员的值都是唯一的
1、属性和方法:
1)size:属性,返回集合中元素的个数
2)add():添加新元素,返回当前集合
3)delete():删除元素,返回布尔值
4)has():检查集合中是否有某个元素,返回布尔值
5)clear():清空集合
1、Set作用:
1)数组去重
let arr = [1,2,1,3,4,2,5,1,3]
let result = [... new Set(arr)]
2)求交集
let arr = [1,2,1,3,4,2,5,1,3]
let arr2 = [4,5,4,6,4,5]
let result = [... new Set(arr)].filter(item => new Set(arr2).has(item))
3)并集
let arr = [1,2,1,3,4,2,5,1,3]
let arr2 = [4,5,4,6,4,5]
let result = [... new Set([...arr, ...arr2])]
9、Map
类似于对象,也是键值对的集合,但键可以是任意类型的
属性和方法:
1)size:返回Map的元素个数
2)set(key, value):增加元素,返回当前的Map
3)get(key):根据键名获取键值
4)has(key):检查Map中是否含有某个元素,返回布尔值
5)clear():清空Map
10、class 类
类的继承
//父类
class Persion{
//构造函数
constructor(name, age){
this.name = name
this.age = age
}
//方法
setName(name){
this.name = name
}
//get和set,当读取属性时,get会被触发;设置属性时,set被触发
get age(){
//
}
set age(newValue){
//
}
}
//子类型
class Student extends Persion{
constructor(name, age, price){
super(name, age) //就是ES5构造函数方法中的:Persion.call(this, name ,age)
this.price = price
}
setPrice(price){
this.price = price
}
//子类对父类方法的重新
setName(name){
//...
this.name = name
}
}
var stu= new Student('Tom', 24, 15000)
stu.setName('Bob')
stu.setPrice(16000)
console.log(stu.name, stu.age, stu.price) //输出Bob,24,16000
11、模块化
1、export的几种写法
1)分别暴露,export function xx1(){}; export let xx2 = ‘xxx’
2)统一暴露,export {xx1, xx2}
3)默认暴露,export default {xxx1, xxx2}
2、import的几种写法
1)通用方式(不管哪种暴露方式都可用)
import * as xxx from ‘xxx/xxx’
2)解构赋值形式(分别暴露和统一暴露用的多)
import {xx1, xx2} from ‘xxx/xxx’
3)简易写法(只适用于默认暴露)
import xxx from ‘xxx/xxx’
12、async和await
async和await结合可以让异步代码像同步代码一样
1、async函数
1)async函数的返回值是promise对象
2、await表达式
1)await必须写在async函数中
2)await右侧的表达式一般为promise对象
3)await返回的是promise成功的值
4)await的promise失败了就抛出异常,有try…catch捕获