JS基础知识
一、组成部分
1、组成部分
① BOM
② DOM:js操作文档流变化的属性和方法
③ ECMAScript:js 的书写语法和书写规则
2、书写位置
① 行内式:书写在href属性上
<a href='javascript': 代码;></a>
非a标签--书写在行为属性上
<div onclick="alert('hello')">点我一下</div>
② 内嵌式:把代码书写在一个script标签上(不需要任何依赖行为,打开页面就会执行)
③ 外链式:把代码书写在一个 .js 文件中 (使用script的src属性来引入)
二、变量
1、显示方式
① 在浏览器弹窗显示 num 的值:alert(num)
② 在控制台打印 num 的值:console.log(num)
③ 直接在页面输出 num 的值:document.write(num)
2、变量类型
① 基本数据类型:String、Boolean、Number、Null、Undefined、Symbol、BigInt,存储在栈中,占据空间小,属于被频繁使用的数据,所有基本数据类型都占 8 个字节
② 引用数据类型:Array、Object、Function,存储在堆中,占据空间大,在栈中存储了引用数据类型的指针,指向堆中该实体的引用地址
3、数据类型的转换
① 转数值
(1)Number(): Number(要转换的内容)
(2)ParseInt(): ParseInt(要转换的内容)
(3)ParseFloat(): ParseFloat(要转换的内容)
- 不是数字的会转换成 NaN(Not a number)
② 转字符串
(1)String(): String(要转换的内容)
(2)toString(): toString(要转换的内容)
③ 转布尔值
(1)Boolean(): Boolean(要转换的内容)
4、运算符
① 等于: == (数值相等就可以)
② 全等于: === (数值和类型都必须相等)
三、函数
1、基础函数
定义
function fn(){
}
调用 fn()
2、递归函数
// 一个函数调用了自身,并说明终止条件
function(n){
if(n === 1) return 1;
return n * f(n-1);
}
3、作用域
① 全局作用域:一个页面就是一个作用域
② 局部作用域:只有函数,生成的私有作用域
4、对象数据类型
var obj = {}
5、数组
① 改变原数组的方法
1、push(): 末尾添加,返回长度,相当于进栈操作
2、unshift(): 首部添加,返回数组长度
3、pop() : 尾部删除,返回删除的元素
4、shift() : 首部删除,返回删除的元素
5、splice(index,length,新增元素1,新增元素2…) :表示从index开始删除length个元素,并从index开始新增元素1-N,返回被删除的元素 组成的数组
6、sort():返回排序后的数组,return a-b 是升序
7、reverse():返回颠倒后的数组
8、fill(value, start, end):用静态值填充数组指定元素,如果未指定开始和结束位置,则填充所有位置
② 返回新数组的方法
1、concat(): 合并两个或多个数组
2、slice(start,end): 剪切,不传参数相当于复制一份数组
3、filter(function(value,index,arr){}) :过滤,value是指,index表示索引
4、map() :格式化,返回的是布尔值
③ reduce方法
reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue
})
// filter 方法实例
var a = [1,2,3,4,11]
// 第一个参数为一个方法,有三个参数,current:当前值 index:当前值下标 array:这个数组对象
var b = a.filter(function(current,index,array){
return current < 10
})
console.log(b) // [1,2,3,4]
console.log(a) // [1,2,3,4,11]
6、字符串
1、charAt(): 按照索引获取字符
2、toUpperCase(): 转大写
3、split(): 切割字符串
4、trim(): 去掉首尾空格
5、slice(): 截取字符串子串
7、数字的常用方法
1、random(): 随机产生 0~1 之间的数组
2、round(): 四舍五入取整
8、forEach的用法
var arr = [1,2,3,4]
sum = 0
// value: 数组的内容
// index: 数组的索引
// arr: 数组本身
arr.forEach(function(value,index,arr){
arr[index] == value // true
sum += value
})
console.log(sum) // 10
四、BOM和DOM
1、BOM
① BOM 是浏览器对象模型
② window 是浏览器的内置中的全局对象,所学习的所有 web API 都是基于 window 对象实现的
③ window 对象下包含了 navigator、location、history、document、screen 五个属性
④ document 是实现 DOM 的基础,依附于 window 属性
注:依附于 window 对象所有的属性和方法,使用时可以省略 window
2、定时器
① 间隔定时器:没个一段时间重复执行
setInterval(函数,时间)
② 延时定时器:只执行一次
setTimeout(函数,时间)
③ 关闭定时器
// 关闭间隔定时器
clearInterval(定时器的返回值)
// 关闭延时定时器
clearTimeout(定时器的返回值)
3、DOM
① 获取元素的方式
1、根据选择器获取一个元素: document.querySelector(‘选择器’)
2、根据选择器获取多个元素: document.querySelectorAll(‘选择器’)
② 操作元素内容
1、获取元素文本内容:元素.innerText
2、设置元素文本内容:元素.innerText = “新内容”
3、获取元素超文本内容:元素.innerHTML
4、设置元素超文本内容:元素.innerHTML= “新内容”
③ 操作元素属性
1、获取属性:元素.getAttribute(‘属性名’)
2、设置属性:元素.setAttribute(‘属性名’,‘属性值’)
3、删除属性:元素.removeAttribute(‘属性名’)
④ 操作元素类名
1、获取类名:元素.className
2、设置类名:元素.className = “新类名”
⑤ 操作元素行内样式
1、获取样式:元素.style.样式
2、设置样式:元素.style.样式 = “样式值”
⑥ 操作节点
1、创建节点:document.createElement(“元素名称”)
2、插入节点:父节点.appendChild(子节点),把子节点插入在父节点的后面
父节点.insertBefore(子节点,哪一个子节点的前面),把子节点插入在某个子节点的前面
3、删除节点:父节点.removeChild(子节点),从父节点内删除子节点
节点.remove(),节点把自己删除
五、事件
1、事件绑定
事件绑定的三要素:① 事件源:和 谁做好约定
② 事件类型:约定一个什么样的行为
③ 事件处理函数: 当用户触发该行为时,执行什么代码
语法:事件源.on事件类型 = 事件处理函数
2、事件类型
3、事件对象
当事件触发的时候,描述该事件信息的对象数据类型
4、事件传播
① 捕获阶段:从 window 按照结构子级的顺序传递到 目标
② 目标阶段:准确触发的事件接收到行为
③ 冒泡阶段:从 目标 按照结构子级的顺序传递到 window
5、阻止事件传播
事件对象.stopPropogation()
6、事件委托
利用事件冒泡的机制,把自己的事件委托给父级的某一层
六、面向对象
1、自定义构造函数创建对象
// 构造函数会自动创建对象, 自动返回这个对象
// 我们只需要手动想里面添加内容就可以了
function createObj(name, age) {
// 自动创建对象
// 手动向对象里面添加成员
// 这里的 this 指向当前实例(new 前面的变量)
this.name = name
this.age = age
this.sayHi = function () { console.log('hello world') }
// 自动返回对象
}
// 构造函数在使用的时候, 需要和 new 关键字连用
// 函数内部的代码在执行的时候, 就是在向 obj1 添加了 name age 和 sayHi 三个成员
var obj1 = new createObj('Jack', 18)
2、构造函数的使用
① 构造函数和普通函数没有区别,只是在调用的时候需要和 new 关键字连用
② 书写构造函数时,函数首字母需要大写
③ 调用的时候需要和 new 关键字连用,这样才会有 自动创建和返回对象的能力
④ 当函数名和 new 关键字连用的时候, 函数内部的 this 指向的是当前实例对象
⑤ 构造函数内部不要随便写 return,当 return 了一个基本数据类型时,相当于没写
当 return 了一个复杂数据类型时,构造函数白写
七、原型
1、原型(prototype)
① 定义: 每一个函数天生自带一个原型(prototype),是一个对象
② 构造函数也是函数,所有也会自带一个 原型(prototype)
③ 既然 prototype 是一个对象,我们就可以以一个对象的方法往 prototype 上添加一些内容
2、对象
① 定义:每一个对象,当你访问它成员的时候,如果它身上此时没有这个属性,会自动往其所属构造函数的 prototype 上去查找
② 自定义构造函数创建的对象也是对象, 当你访问某一个成员的时候
=> 如果没有, 也会自动去所属构造函数的原型上查找
=> 哪一个构造函数创建的对象, 这个对象就属于哪一个构造函数
=> 因为构造函数在创建对象的过程, 我们起名为 实例化 的过程
-> 创建出来的对象叫做这个构造函数的一个 实例化对象
function Person() {}
Person.prototype.sayHi = function () { console.log('我是 Person 原型上的方法') }
console.log(Person.prototype)
// 创建一个实例化对象
// 因为 p1 是 Person 实例化出来的对象
// p1 就是属于 Person 这个构造函数的
// 当你访问 p1 的 sayHi 成员的时候, p1 自己是没有的
// 会自动去 Person 的 原型(prototype) 上查找
var p1 = new Person()
console.log(p1)
p1.sayHi()
// 创建第二个实例化对象
// 因为 p2 也是 Person 的实例化对象
// p2 没有 sayHi 成员, 也会自动去 Person 的原型上查找
var p2 = new Person()
console.log(p2)
p2.sayHi()
/*
p1 的 sayHi 方法和 p2 的 sayHi 方法都是使用的 Person 构造函数的原型上的方法
我只要向 Person 的原型上添加一些方法
所有的 Person 的每一个实例都可以使用
并且使用的都是同一个函数, 不会出现浪费空间的行为
*/
console.log(p1.sayHi === p2.sayHi) // true 说明是一个函数
注:原型对象就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
3、原型链
① 实例对象身上的 proto 指向谁?
所属构造函数的 prototype 对象
② Person.prototype 的 proto 指向谁?
1)Person.prototype的所属构造函数是谁
2)Person.prototype 是一个对象
3)在 js 中,所有对象的所属构造函数都是 Object
4)Person.prototype 的 proto 指向的是 Object 的 prototype 对象
③ Person 的 proto 指向谁?
1)函数本身也是一个对象,就会有 proto 属性
2)在 js 中,所有函数的所属构造函数都是 Function 的实例
3)所有指向的是 Function 的 prototype 对象
④ Object.prototype 的 proto 指向谁?
注意:Object.prototype 在 JS 内叫做顶级原型,不存在有 proto 了
Object.prototype 的 proto 指向 null
⑤ Object 的 proto 指向谁?
1)Object 是一个内置构造函数,同时也是一个函数,也是一个对象
2) 在 JS 内,所有的函数都是属于内置构造函数 Function 的实例
3)Object 也是 Function 的实例
4) Object.proto 指向的是 Function.prototype
⑥ Function.prototype 的 proto 指向谁?
1)在 JS 内所有的 Object 类型都是属于 Object 这个内置的构造函数
2)Function.prototype 是属于 Object 这个内置的构造函数的
3)Function.prototype 的 proto 属于 Object.prototype
⑦ Function 的 proto 指向谁?
1) Function 是一个内置构造函数,也是一个构造函数
2) 在 JS 内,所有的函数都是属于内置构造函数 Function 的实例
3) Function是自己的构造函数,也是自己的实例对象
4) Function 所属的构造函数是 Function
注:原型链,用下划线 proto 串起来的对象链装结构,每一个对象数据类型,都有一个属于自己的原型链
⑧ 对象访问机制:
1) 当你需要访问对象成员的时候,首先在自己身上查找,如果有则直接使用
2)如果没有,会自动去所属构造函数的原型对象上去查找
3)如果还没有,回去 proto 上查找
4)直到 Object.ptototype 都没有,那么返回 undefined
八、ES6
1、定义的变量
① var 可以进行预解析,let 和 const 不能
② var 可以重复变量名,let 和 const 不能
③ var 可以做越过块级作用域,而 let 和 const 不能
块级作用域:每一个 {} 都是一个代码块
④ let 定义时可以不赋值(块级作用域),而 const 必须赋值(块级作用域)
⑤ const 一旦定义好,不能被修改值
2、箭头函数
getName()=>{
// 函数体
}
① 当函数只有一个形参的时候,可以省略 ()
② 箭头函数某些时候可以省略 {}
1)当你的代码只有一句话的时候
2)并且自动会把这一句话当做返回值
③ 箭头函数之内没有 arguments(任意个参数)
④ 箭头函数没有 this ,它的 this 就是全局的 this
3、模板字符串
var str = `hello`
// 可以换行书写
// 可以直接在字符串内解析变量 ${变量}
4、展开运算符
/*
展开运算符:
① ...
② 作用:展开数组的 [],或者对象的 {}
*/
var arr = [10,2,3,5,2,3]
console.log(...arr)
// 作用1:合并数组
var arr1 = [1,2,3]
var arr2 = [4,5,6]
var arr3 = [7,8,9]
var arr4 = [10,20,30]
var arr5 = [...arr1,...arr2,...arr3,...arr4]
console.log(...arr5)
// 作用2:给函数传递参数
var max = Math.max(...arr5)
console.log(max)
// 展开对象
var obj = {name:'Rose',age:18}
console.log(obj)
// 作用一:用来复制对象,主要展开成员的顺序,在有相同成员的时候
var obj2 = {
gender:'女',
...obj
}
console.log(obj2)
5、类语法
类语法:
class 类名{
constructor(){
}
直接书写原型上的方法即可
}
1、必须和 new 关键字连用
*/
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.sayhi = function(){
console.log('hello')
}
// 书写静态属性和静态方法
Person.sex = '男'
Person.go = function(){
console.log('running...')
}
// 构造函数本质上还是一个函数,可以不和 new 连用
// 类的书写
class Animal{
constructor(name,age){
this.name = name
this.age = age
}
// 直接书写原型上的方法
sayhi(){
console.log('hello,world')
}
// 书写静态属性和方法必须加上 static,不能通过实例对象来访问
static gender = '女'
static gogo = function(){
console.log('跑起来')
}
}
var a1 = new Animal('dog',19)
console.log(a1)
Animal.gogo()
九、前后端交互
1、简单的 ajax 请求:实现网页与服务器的交互
/*
第一次尝试 ajax
*/
// 1. 创建一个 ajax 对象
var xhr = new XMLHttpRequest()
// 2. 配置本次的请求信息
// 请求方式: 按照接口文档来进行书写
// 请求地址: 按照接口文档来进行书写
// 是否异步: 默认是 true 表示异步请求, 选填为 false, 表示同步请求
xhr.open('GET', 'http://localhost:8888/test/first', true)
// 3. 配置一个请求完成后触发的事件
// 请求完整: 本次请求发送出去, 服务器接收到了我们的请求, 并且服务器返回的信息已经回到了浏览器
xhr.onload = function () {
// 如何拿到后端返回的信息
// 语法: xhr.responseText
console.log(xhr.responseText)
}
// 4. 把本次请求发送出去
xhr.send()
2、测试 ajax 请求
/*
第二次测试 ajax
*/
// 1. 创建ajax 对象
var xhr = new XMLHttpRequest()
// 2. 配置本次的请求信息
xhr.open('GET', 'http://localhost:8888/test/second', true)
// 3. 配置请求完成的事件
xhr.onload = function () {
// 当后端返回的是 json 格式字符串的时候, 我们需要进行单独的解析
// 语法: JSON.parse(json格式字符串)
// 返回值: 解析好的 js 格式的数据
var res = JSON.parse(xhr.responseText)
console.log(res)
}
// 4. 发送出去
xhr.send()
3、请求方式
① get: 通常是获取服务器资源,从服务器获取 HTML 文件等等
②post: 通常是向服务器提交资源,如注册用户等等
十、作用域
1、变量声明提前:使用 var 声明的变量,会在所有代码执行前声明(但不会被赋值)
2、函数声明提前:
① 使用函数声明创建的函数 function 函数(){},它会在所有的代码之前就被创建,所以我们可以在函数声明前调用函数
② 使用表达式创建的函数,不会声明提前,所以不能在声明前进行调用
3、函数作用域
① 调用函数时创建函数作用域,函数执行完毕以后,**函数作用域销毁**
② 每调用一次函数就会创建一个新的函数作用域,他们之间是**相互独立的**
③ 在函数作用域当中可以访问到全局作用域的变量,在全局作用域中访问不到函数作用作用域的变量
④ 当函数作用域操作一个变量时,如果自身作用域没有,则会在上一级寻找,有则直接使用,没有的话一级级往上找,找到不的话就 报错
⑤ 在函数中要访问全局变量可以使用 **Windows 对象**
4、在函数作用域也有声明提前的特性:
① 使用 var 关键字声明的变量,会在函数中所有的代表执行前被声明
② 函数声明也会在所有的代码执行前执行
③ 在函数中,不使用 var 声明的变量都会成为全局变量
5、静态成员与实例成员
① 静态成员:在构造函数本身上添加的成员,不能通过对象来访问
② 实例成员:通过构造函数内部 this 添加的成员,只能通过实例对象来访问
十一、this
1、this 的指向
① 以函数的形式调用时,this 永远指向的是 window
② 以方法的形式调用时,this 指向的就是调用方法的那个对象
③ 当以构造函数的形式调用时,this 就是新创建的对象
④ 对象不能形成自己的作用域,其作用域为全局作用域
2、使用工厂模式创建对象
function createPerson(name,age){
// 创建一个新对象
var obj = new Object()
// 向对象中添加属性
obj.name = name
obj.age = age
return obj
}
var obj1 = createPerson("林俊杰",'25')
var obj2 = createPerson("周杰伦",'28')
3、构造函数与普通函数
① 构造函数其实就是(首字母大写)一个普通函数,创建方式与普通函数没什么区别
② 普通函数直接调用,而构造函数需要使用 new 关键字来调用
③ 构造函数的执行流程:
1)立刻创建一个新的对象
2)将新创建的对象设置为函数中的 this,在构造函数中可以使用 this 来引用新建的对象
3)逐渐执行函数中的代码
4)将新建的对象作为返回值返回
4、call() 和 apply()
① 这两个方法都是函数对象的方法,需要通过函数对象来调用
② 当函数调用 call() 和 apply() 都会执行函数
③ 在调用 call() 和 apply() 可以将一个对象指定为第一个参数,此时这个对象会成为函数执行时的 this
④ call() 方法可以将实参在对象之后依次传递
⑤ apply() 方法需要将实参封装到一个数组中统一传递
5、JSON
① JS中的对象只有 JS 自己认识,其他语言都不认识
② JSON 就是一个特殊格式的字符串,这个字符串可以被任意语言所识别,并且可以转换为任意语言的对象
③ JSON在开发中主要做数据的交互
④ JSON 和 JS 的对象格式一样,只不过 JSON 字符串中的属性名必须加 **双引号**
⑤ JSON 分类:字符串、数值、布尔值、null、对象、数组
⑥ 将 JSON 字符串转换为 JS 中的对象,提供了一个工具类就叫 JSON
1) json ---> js: JSON.parse(json)
2) js ---> json: JSON.stringify(json)
十一、Promise
1、实现异步操作
const fs = require("fs")
const p = new Promise(function(resolve,reject){
fs.readFile("one.txt",(err,data) => {
if(err) reject(err)
resolve(data)
})
})
p.then(function(value){
// 成功时
console.log(value.toString())
},function(reason){
console.log(reason.toString())
})
2、Proxy 拦截器
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写
var proxy = new Proxy(target, handler);
Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
十二、深拷贝和浅拷贝
1、深拷贝:复制真正的值,相互之间不会有影响
var obj1 = {
a:1,
b:2,
arr:['暂时的记号','离开那一些','幸存者']
}
function copyObj(obj){
if(Array.isArray(obj)){
var new_obj = []
}else{
var new_obj = {}
}
for(var key in obj){
if(typeof obj[key] == 'object'){
new_obj[key] = copyObj(obj[key])
}else{
new_obj[key] = obj[key]
}
}
return new_obj
}
console.log(copyObj(obj1))
new_obj = copyObj(obj1)
new_obj.a = '我想睡觉'
obj1.b = '我要学习'
console.log(obj1)
console.log(new_obj)