JavaScript知识点总结
1.1 EC(G),VO,GO
- EC:执行上下文
- VO:变量对象
- GO:全局对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oyjPPv86-1617025064455)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227083525635.png)]
1.2 定义变量有var与没有var区别
- 在全局代码中,加var会提升,没有var的不会提升
- 不管加没加var的全局变量,都会作为window的属性
- 没有加var的只能作为全局对象,只要是全局对象,就是window的属性
- 加var的局部变量,不会作为window的属性
console.log(a,b) // undefined undefined
if(true) {
var a = 1
} else {
var b = 1
}
console.log(a,b) // 1 undefined
1.3 数据存储
- 内存
- 堆内存,保存基本数据类型
- 栈内存,保存引用数据类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0v4IiH3k-1617025064458)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227091934875.png)]
2 .1 练习题分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hoRvorRH-1617025064460)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227095820911.png)]
var a = b = 2 // 等价于 var a = 2 , b = 2
var a = 2, b = 2 // 等价于 var a = 2 , var b = 2
var a = 1
var b = 1
function f() {
console.log(a, b) // undefined 1
var a = b = 2
console.log(a, b) // 2, 2
}
f()
console.log(a, b) // 1,2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J80jcMRm-1617025064464)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227101317522.png)]
var a = 1
var obj = {
name: 'wangcai'
}
function f() {
var a2 = a
obj2 = obj
a2 = a
obj.name = "xiaoqiang"
}
f()
console.log(a) // 1
console.log(obj) // {name: "xiaoqiang"}
console.log(obj2) // {name: "xiaoqiang"}
var a = 12
var b = a
b = 13
console.log(a) // 12
var a = {n:12}
var b = a
b.n = 13
console.log(a.n) // 13
var a = {m:666}
var b = a
b = {m:888}
console.log(a.m) // 666
var a = {n:110}
var b = a
b.m = b = {n:666} // 同时进行 b={n:666}, b.m={n:666}
console.log(a) // {m:{n:666}, n:110}
console.log(b) // {n: 666}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3jZIvNq-1617025064466)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227111716646.png)]
2.2 使用let和const声明变量和常量
2.2.1:let
- let声明的变量没有提升(let声明的变量也提升,仅仅是没有初始化)
console.log(a) //Cannot access 'a' before initialization
let a = 110
- let 配合 { } 也可以形成块级作用域
if(true) {
var a = 110
let b = 666 // let + {} 形成块级作用域
}
console.log(a) // 110
console.log(b) // b is not defined
- 使用let声明的变量不会挂载到GO上
let a = 110
console.log(window.a) // undefined
- 使用let不能重复声明
let a = 1
let a = 2
console.log(a) //Identifier 'a' has already been declared
2.1.2const与let区别
- const 声明一个常量,不能改变
- const声明式必须赋值
2.3 函数当中的声明与赋值
console.log(fn) //undefined
// window.fn() //报错
console.log(window.fn) //undefined
// fn() // 报错
if('fn' in window) {
/**
* 在判断中,如果有函数,编译仅提升函数名
*
* 如果条件满足,进入条件第一件事就是给fn赋值
*/
fn() // fn...
function fn() {
console.log('fn...')
}
}
fn() // fn...
2.4 同名问题处理
fn()
function fn() {console.log(1)}
fn()
function fn() {console.log(2)}
fn()
var fn = function() {console.log(3)}
fn()
function fn() {console.log(4)}
fn()
function fn() {console.log(5)}
fn()
// 5 5 5 3 3 3
3.1 闭包
- 闭包作用
- 延长局部变量的声明周期
var i = 5
function fn(i) {
return function (n) {
console.log(n + (++i));
}
}
var f = fn(1)
f(2) // 4
fn(3)(4) // 8
fn(5)(6) // 12
f(7) // 10
console.log(i) // 5
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MNQoXZy5-1617025064468)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227162504544.png)]
3.2 作用域链
- 描述栈数据的链,先在自己的EC中找,如果找不到数据,就去父EC找,还找不到,去父EC的父EC中找,直到找到EC(G),如果还找不到就报错。数据查找机制。
- 练习题
let a= 0
b= 0
function A(a) {
A = function(b) {
alert(a+b++)
}
alert(a++)
}
A(1) // 1
A(2) // 4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjgkIh5l-1617025064469)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201227185105847.png)]
4.1相关概念
-
什么是代码段?
- 使用script标签包起来就是代码段
- 特点:上一个代码段定义的状态,在下一个代码段中可以使用
-
JS代码执行分几个阶段?
-
预编译
-
扫描代码段,如果代码段有语法错误,停止一切工作,立即报错
-
提升
A) 加var变量提升
全局代码:提升代码段最前面
局部代码:提升局部代码最前面
B) 函数定义提升
-
-
代码执行
- 一行一行执行代码
-
JS中的数据类型和数据存储
- 为什么需要数据类型?
- 为了更加合理的使用内存(堆内存、栈内存)
- 基本:
- number string boolean und null 存储在栈区 栈区保存了堆区的地址
- 引用:
- object array function 存储在堆区
- 为什么需要数据类型?
-
说出下面结果?
-
作用域链
- 数据的查找机制
-
EC
- 全局代码执行时产生全局的EC,调用一个函数时,就产生一个局部的EC。EC是放在栈结构中的,全局的EC,先入栈,调用一个函数,局部的EC也入栈,函数调用完毕,局部EC出栈,全局代码执行完毕,全局EC也出栈
-
closure
- 一个不能被销毁的执行上下文就是一个闭包
- low:函数嵌套,里面的函数使用外面的函数的数据,此时里面的函数也可以叫做闭包
- 作用:
- 保护,位于闭包中的数据 外界不能访问
- 保存 EC出栈了 数据是没有销毁 数据的生命周期延长
- 缺点:内存泄漏 合理使用闭包
-
在JS中,IIFE都有哪些写法?
-
立即函数调用表达式
(function(){})() (function(){}()) +function(){}{} -function(){}{} !function(){}{} setTimeout(() => { }, timeout);
-
-
EC,AO,GO,ECStack,Scope,ScopeChain
- EC:执行上下文
- AO:活动对象(存储了局部执行上下文中数据)
- VO:变量对象(存储全局执行上下文中的数据)
- GO:全局对象 window
- ECStack:执行上下文栈
- Scope:作用域
- ScopeChain: 作用域链
-
-
4.2 JS错误分类和异常处理
4.2.1 语法错误
let a = 1
let a = 1
// Uncaught SyntaxError: Identifier 'a' has already been declared
- JS在预编译时,就发现了错误
- 特点:
- 代码没有机会执行
- 错误最好找
- 特点:
4.4.2 引用错误
console.log(a)
// Uncaught ReferenceError: a is not defined
- 访问没有定义的变量
- 特点:JS代码在执行的时候,才发现引用错误,错误之后的不执行
4.4.3 类型错误
var f = 1
f()
// Uncaught TypeError: f is not a functio
- 使用类型不当
- 特点:JS代码在执行的时候,才发现引用错误,错误之后的不执行
4.4.4 范围错误
var arr = new Array(-5)
// Uncaught RangeError: Invalid array length
- 使用容器时,范围指定不当
4.4.5 逻辑错误
- 特点
- 控制台不报错
- 通过debug解决
4.4.6 异常处理
- 异常不是错误,异常是指可能出错的代码
- 语法:
try{
// 仿可能出错的代码
console.log(a)
}catch(e) {
// 如果上面的代码错误了,就在这里进行错误的处理,其中e表示错误对象
// 它里面包含了错误信息。通过查看e,可以知道他到底什么出了错误
console.log('有错误:',e)
}finally{
// 无论对错,代码都会执行到此处,在JS中用的不多
console.log("一定会执行")
}
- 抛出错误
try{
var a = 0
console.log(a)
if(a == 0){
// 程序员主动抛出错误
throw new Error('不能为0') // 抛出错误 catch会捕获到
}
}catch(e) {
console.log('友情提示:这里有点小问题,工程师正在解决中...',e)
// 友情提示:这里有点小问题,工程师正在解决中... Error: 不能为0
}
4.3 逻辑与、逻辑或
4.3.1 逻辑与
var a = 10
var b = 0
var c = b && a++ // && 左结合性 b = 0 , 不再执行&&后面的
var d = a++ && b
console.log(a) // 11
console.log(b) // 0
console.log(c) // 0
console.log(d) // 0
4.3.2 逻辑或
var a = 0
var b = 2
var c = b || a++
console.log(a) //0
console.log(b) //2
console.log(c) //2
var m = 1
var n = ""
var q = m || n
console.log(m) //1
console.log(n) //''
console.log(q) //0
4.3.3 优先级
let x = 1 || 2 && 3 || 4 && 0 || 5
// &&>||
console.log(x) // 1
4.4 同步代码与异步代码
- 三种方法实现
var btns = document.getElementsByTagName('button')
// for(var i = 0;i<btns.length;i++) {
// btns[i].onclick = function() {
// console.log(i)
// }
// }
// 3 3 3
// 使用闭包解决
// for (var i = 0; i < btns.length; i++) {
// btns[i].onclick = (function (i) {
// return function () {
// console.log(i)
// }
// })(i)
// }
// 0 1 2
// 给btns[i]添加属性
// for (var i = 0; i < btns.length; i++) {
// btns[i].index = i
// btns[i].onclick = function () {
// // 由于此函数是浏览器帮我们调用的,是得不到全局EC中的全局数据的
// // 解决办法:使用this this表示当前的事件源
// // 此处要使用this替换btns[i]
// console.log(this.index)
// }
// }
// 使用let + {} 形成块级作用域
// 相当于每次for循环,都会产生执行上下文
for(let i = 0;i<btns.length;i++) {
btns[i].onclick = function() {
console.log(i)
}
}
4.5 this 大总结
4.5.1 this几种身份
-
如果this出现在普通的函数中,this表示window,如果你通过window打点调用一个函数,这个函数中的this也是window
-
事件绑定,事件处理程序,事件发生时,浏览器帮我们调用这个函数,此函数中的this表示事件源
-
在一个对象中,如果有方法(函数),如果通过这个对象调用方法,方法中的this表示这个对象
-
在IIFE(立即调用函数表达式)中,this表示window
(function () { console.log(this) // window })()
-
前四点都是在非严格模式下,在严格模式下,调用一个普通函数,this表示undefined
"use strict"; (function () { console.log(this) // undefined })()
5.1 类和对象以及内置类
- 基本上所有的高级语言都是面向对象编程。面向对象是一种思想
- 常见几种思想?
- 面向过程:C语言 没有类 没有对象
- 面向对象:JAVA C++ JS()
- 特征:
-
- 抽象:把一个具体问题抽象化
- 封装:把属性和方法封装到类中,在JS中重点说对象
- 继承:一个类可以继承另一个类,在JS中,类是通过函数表达式
- 多态
-
- 面向对象中的类和对象
- 类: JS的类本质上还是一个函数 是抽象的,不具体
- 对象:是具体的
- 特征:
- 面向切片:Spring IOC AOP
- 常见几种思想?
5.1.1JS默认提供的类
- instanceof
- instance:实例
- 判断一个对象时否属于一个类
- 例如:n instanceof Number 返回true或false
- Number 类 或构造器
- String 类
- Boolean 类
- Object 类
- Date 类
- Math 类
- 不需要new 单体内置类
- 常驻内存不需要new
- Array 类
5.1.2 JS 中一切数据都是对象
-
HTML元素是一个对象
-
函数也是对象
-
基本数据类型在某些情况下也是对象
-
var a = 100; console.log(a.toFixed(3)); // 110.000 // 上面的a叫包装对象 // 上面调用toFixed时,他会把a瞬间包装成一个对象 var str = 'hello' console.log(str.length); // 5 console.log(str.toUpperCase); // HELLO
-
-
console、window等也是对象
5.1.3 操作对象集合
-
增删改查
- 访问对象
/** * 访问对象里面的属性 键可以用引号包起来,也可以省略 * 1)打点调用 * 2)通过[]来调用 */ var obj = { name: 'wangcai', 123: 456, '1+1': 2, 'a': 'hello', 'b': null, 'c': function () { console.log('c..') }, 'd':['1','2','3'], 'e':{x:'xxx'} } // console.log(obj.123) 语法错误 console.log(obj[123]); // 123 console.log(obj.a); // hello console.log(obj[1+1]); // undefined console.log(obj['1+1']) // 2 // 如果键是一个变量 我们需要通过变量去访问 必须使用[] var k = 'name' console.log(obj[k]) //wangcai // 访问对象里面保不存在的属性,结果为undefined
- 遍历对象 for in
// for in var obj = { name:'wangcai', age:100, say:function(){ console.log('say...') }, } for(var key in obj){ // key 是一个变量,要通过[]调用 console.log(key) // 属性 console.log(obj[key]) // 值 }
-
添加、修改属性
-
删除属性
// delete 是一个单目运算符 只有一个操作数 delete obj.age
var a = 100; console.log(window.a); //100 var 中的变量放进GO中。是不能删除的 delete window.a; console.log(window.a); //100 b = 666; console.log(window.b); // 666 delete window.b; console.log(window.b); //undefined
5.1.4 对象中的属性的四大特征
获取对象属性
- 获取对象属性:Object.getOwnPropertyDescriptor(window,‘a’)
- configurable 表示是否可以删除 true表示可以删除
- writable 修改 true可修改
- enumerable 枚举 true可枚举
- value 属性值 默认undefined
var a = 100;
b = 666;
// 获取属性特征
console.log(Object.getOwnPropertyDescriptor(window,'a'));
console.log(Object.getOwnPropertyDescriptor(window,'b'));
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61x99WKG-1617025064470)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201229144421589.png)]
设置对象属性
var obj = {}
// 定义属性
Object.defineProperty(obj, 'name', {
configurable: false,
writable: false,
enumerable: false,
value: 'wnagcai'
})
console.log(obj.name) // wangcai
obj.name = 'xing'
console.log(obj.name) // wangcai
5.1.5 属性分类
-
属性分为两类
// in 运算符 判断一个属性是否属于一个对象 // 不论私有还是公有
- 私有属性
- api:hasOwnProperty
- 共有属性
- __proto__里面的属性
- 私有属性
// hasOwnProperty 私有属性
var arr = [1, 2, 3]
console.log(arr)
console.log(arr.hasOwnProperty('length')) //true
console.log(arr.hasOwnProperty('__proto__')) //false
console.log(arr.hasOwnProperty('push')) //false
// 只能删除私有属性 不能删除公有属性
delete a[0]
// 如果一个私有属性和公有属性重名了,私有会覆盖公有
- 数组去重与统计数组
// 数组去重
var arr = [2, 4, 1, 2, 4, 5, 9, 5];
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
// delete arr[j]
arr.splice(j,1)
}
}
}
console.log(arr)
//-------------------------------------------------------
var arr = [2, 4, 1, 2, 4, 5, 9, 5];
var newArr = [];
var o = {};
for (let i = 0; i < arr.length; i++) {
let t = arr[i]
// if (o[t]) {
// } else {
// newArr.push(t)
// o[t] = true
// }
if(!o[t]) {
newArr.push(t)
o[t] = true
}
}
console.log(newArr)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
var arr = [2, 4, 1, 2, 4, 5, 9, 5];
var x = new Set(arr)
console.log([...x])
// 统计一个数组中元素出现的个数
var arr = [2, 4, 1, 2, 4, 5, 9, 5];
var obj = {}
for (var i = 0; i < arr.length; i++) {
if (!obj.hasOwnProperty(arr[i])) {
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
console.log(obj)
5.1.6 对象是函数创造的
-
在JS当中 ,一个函数是多个角色
- 普通函数
- 在对象中可以当成一个方法
- 类 构造器
- 对象
-
new 操作符干了几件事?
- 在构造器内部创建了一个空对象
- 让构造器中的this指向这个对象
- 返回这个对象
-
来踩new的坑?
function Fn(x) { let y = 20; this.total = x + y; this.say = function () { console.log(x + "+" + y + "=" + this.total) } } let f1 = Fn(10) console.log(f1) // undefined
function Fn(x) { let y = 20; this.total = x + y; this.say = function () { console.log(x + "+" + y + "=" + this.total) } } let f1 = new Fn(10) f1.say() // 10+20=30 console.log(f1.x) // undefined console.log(f1.y) // undefined
function Fn(x) { let y = 20; this.total = x + y; this.say = function () { console.log(x + "+" + y + "=" + this.total) } } let f1 = new Fn(10) let f2 = new Fn(10) console.log(f1 == f2) // false console.log(f1 === f2) // false
function Fn(x) { let y = 20; this.total = x + y; this.say = function () { console.log(x + "+" + y + "=" + this.total) } } let f1 = Fn(10); console.log(window.total); // 30
function F(num) { this.num = num; return 123; } let o = new F(100); console.log(o) // {num: 100}
function F(num) { // this 还是指向它内部创建出来的空对象 // 此时这个空对象,外界是引用不了的 this.num = num; // 如果类内部返回了一个对象,那么最终指向是你返回的对象 return { name:'xxx' }; } let o = new F(100); console.log(o) // {name: "xxx"}
6 .1 原型
6.1.1 原型对象和原型链
- 每一个对象上都有一个属性:_proto_ 它叫隐式原型
- 每个构造器(函数)上都有一个属性:prototype 它叫原型,是一个对象,这个对象我们叫原型对象
- 原型对象:构造器(函数)的一个属性——prototype,它的值是一个对象,这个对象我们叫原型对象
- 隐式原型:对象的一个属性——_proto_
- 原型链:是一个对象属性的查找机制
- 先在私有属性中找,如果找不到,就沿着__proto__去原型对象中找,如果还找不到,继续沿着__proto_去它原型对象中的原型对象中找,直到找到Object的原型对象(Object原型对象的__proto__指向了null),如果还找不到,结果就是undefined
- 作用域链:EC中数据的查找机制
- 先在自己EC中找数据,没有就去父函数所对应的的上下文中找,如果还找不到,就去父函数的父函数的EC中找,直到找到EC(G),如果还找不到,就报错。
6.1.2 练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pi3duIBs-1617025064471)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201229200312572.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eRKi55Uu-1617025064472)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201229204702817.png)]
- 私有属性、公有属性的坑
function C1(name) {
if (name) {
this.name = name
}
}
function C2(name) {
this.name = name
}
function C3(name) {
this.name = name || 'join'
}
C1.prototype.name = 'Tom'
C2.prototype.name = 'Tom'
C3.prototype.name = 'Tom'
console.log((new C1().name) + (new C2().name) + (new C3().name))
// Tomundefinedjoin
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nf1pFeeA-1617025064473)(C:\Users\尘寰\AppData\Roaming\Typora\typora-user-images\image-20201229210841542.png)]
7
7.1 面试坑
// let a = ?
let a = {
n: 0,
toString: function () {
return ++this.n
}
}
// == 进行比较时,浏览器默认调用toString()
if (a == 1 && a == 2 && a == 3) {
console.log('ok')
}
// let a = ?
// == 进行比较时,两边数据类型不一致时,浏览器默认调用toString()
let a = [1,2,3];
a.toString = a.shift; // 你调用了toString相当于调用了shift
if (a == 1 && a == 2 && a == 3) {
console.log('ok')
}
7.2 运算符优先级
7.3 call、apply、bind的使用
- typeof 可用于检测基本数据类型数据,对于复杂数据类型,返回Object
- Object.prototype.toString.call可以精准的检测数据类型
// 使用 Object.prototype.toString.call可以精准的检测数据类型
console.log(Object.prototype.toString.call(1))
console.log(Object.prototype.toString.call('hello'))
console.log(Object.prototype.toString.call(true))
var a;
console.log(Object.prototype.toString.call(a))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
function f(){}
console.log(Object.prototype.toString.call(f))
let d = new Date()
console.log(Object.prototype.toString.call(d))
let r = new RegExp()
console.log(Object.prototype.toString.call(r))
-
call的使用
// 封装返回类型 function getType(abc) { var rs = Object.prototype.toString.call(abc) rs = rs.substr(8) var len = rs.length rs = rs.substr(0, len - 1) rs = rs.toLocaleLowerCase() // rs = rs.toLocaleUpperCase() // console.dir(rs) } getType(123) console.dir(String.prototype)
// 数组中有一个翻转的方法 var arr = [1,2,3]; console.log(arr.reverse()) // [3, 2, 1] var str = '123456789'; // console.log(str.split('')) // //["1", "2", "3", "4", "5", "6", "7", "8", "9"] // str = str.split('').reverse().join('') // console.log(str) str = Array.prototype.reverse.call(str.split('')).join('') console.log(str)
call/apply/bind的使用
-
伪数组:本质是对象,没有数组的方法
- 通过document.getElementsByTagName获取的集合就是伪数组
- 函数内部的arguments
- 只能在函数内部访问arguments
// 将伪数组变为数组 var btns = document.getElementsByTagName('button') var arr = [] for (let i = 0; i < btns.length; i++) { arr[i] = btns[i] } console.dir(arr)
-
call- apply- bind区别
- call 改变了this指向 ,并让函数执行 ,传递参数一个个传递
- apply 改变了this指向 ,并让函数执行,传递参数必须是数组
- bind(绑定的意思)改变了this指向 函数不执行
// call与apply function F(a,b) { return a+b } var obj = {} console.log(F.call(obj,1,2)) // 3 // apply 接受一个数组 console.log(F.apply(obj,[1,2])) // 3
// bind function F(a,b) { console.log('F...') return a+b } var obj = {}; let k = F.bind(obj); console.log(k(1,2)) // 通过加()调用
7.4 ES6 入门(ES2015)
-
let与 const
-
变量的解构赋值
{res:data} =
-
模板字符串
-
let name = 'wangcai'; console.log(`${name}`) // wangcai // 可以拼接字符串
-
-
对象中的属性简写
- 键和值一样
-
rest参数 ,代替arguments的,用来收集实参的
function f() { console.log(arguments) } // 如果实参个数非常多,使用形参接受不方便了,此时可以使用arguments f(1,2,3,4,5,6,7,8,9); // 伪数组 [1, 2, 3, 4, 5, 6, 7, 8, 9, callee: ƒ, Symbol(Symbol.iterator): ƒ] function g(...rest) { console.log(rest); } g(1,2,3,4,5,6,7,8,9) // [1, 2, 3, 4, 5, 6, 7, 8, 9] // rest形参,我们使用是叫args function k(...args) { console.log(args); } g k(1,2,3,4,5,6,7,8,9) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
-
拓展运算符(扩展运算符)spread
- spread 也是… ,rest参数也是…
let arr = ['wc','xq','zs']
function f(...args) { //rest 参数
console.log(args) // ["wc", "xq", "zs"]
}
f(...arr) // 拓展运算符
- 类
class Player {
constructor() {
console.log('Player类中的constructor')
}
}
class NBAPlayer extends Player {
constructor(name) {
super(); // 调用父类中的构造方法
this.name = name; //设置私有属性
}
// NBAPlayer.prototype.say = function(){}
say() {
console.log('say...')
}
// NBAPlayer.play = function(){}
static play() { // 静态的 通过类进行调用
console.log('play...')
}
}
let n1 = new NBAPlayer('乔丹');
NBAPlayer.play()
8
8.1 创建对象的几种方式
- 字面量
- 工厂模式
- 构造函数
- 构造函数 + 原型
- ES6中通过class创建类 new对象
8.2 继承
- 子类去继承父类的公有属性和私有属性
8.2.1原型继承
// 原型继承
// Child.prototype = new Parent;
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function() {
return this.x;
}
function Child() {
this.y = 200;
}
// 原型继承
Child.prototype = new Parent;
Child.prototype.getY = function() {
return this.y
}
var c1 = new Child();
console.log(c1.x);
console.log(c1.getX());
console.log(c1.y);
console.log(c1.getY());
8.2.2 call继承
// call继承
// 特点:只能继承父的私有属性
// Parent.call(this)
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function() {
return this.x;
}
function Child() {
// 改变Parent的this指向
Parent.call(this);
this.y = 200;
}
var c1 = new Child();
console.log(c1.x)
8.2.3 组合式继承
// 组合继承
// 1)Parent.call(this);//继承父的私有属性
// 2)Child.prototype = Object.create(Parent.prototype); 继承公有属性
// Child.prototype.constructor = Child
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function() {
return this.x;
}
function Child() {
Parent.call(this);//继承父的私有属性
this.y = 200;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child
var c1 = new Child();
console.log(c1.x)
8.2.4 ES6继承
// ES6中的继承:
// super(); //类似call继承
// extends 类似原型继承 继承公有属性
class Parent{
constructor() {
this.x = 100;
}
getX() {
return this.x
}
}
class Child extends Parent{
constructor() {
super(); //类似call继承
this.y = 200;
}
getY() {
return this.y
}
}
var child = new Child();
console.log(child.x);
console.log(child.getX());
8.3 DOM
8.3.1 什么是DOM
- DOM Document Object Model文档对象模型
- 文档是有节点组成的
- 元素节点
- 属性节点
- 文本节点
- …
- Object
- 对象 标签对象 元素对象 ,每一个标签都是一个对象
- Model
- 模型 树模型 在树不会出现属性节点 会出现元素节点和文本节点
8.3.2 DOM版本
-
DOM0
-
DOM1:很多对象,方法
-
树模型:
- 元素节点 nodeType = 1
- 属性节点 nodeType = 2
- 文本节点 nodeType = 3
- 节点与节点之间的关系
- childNodes 所有的子节点 ==》children
- firstChild 有兼容性问题 ==》 firstElementChild (可以用)
- lastChild ==》 lastElementChild (可以用)
- nextSibling 下一个兄弟节点, ==》 nextElementSibling(可以用)
- previousSibling 上一个兄弟节点 ==》 previousElementSibling(可以用)
- parentNode(重要)
-
两个标准方法:
document.getElementById();
document.getElementsByTagName();
其他方法,有兼容性问题
-
html5中提出两个方法
document.querySelector();
document.querySelectorAll();
-
-
DOM2: 很多对象,方法
- 事件绑定
- 鼠标事件
- 键盘事件
- 焦点事件
- UI事件
- …
-
DOM3
8.3.3 操作节点
-
js操作样式
- 操作CSS类:calssName = ‘xxx’
- 操作CSS行内样式
-
操作元素节点
-
访问元素
document.getElementById(ID); document.getElementsByTagName(tagName)
-
遍历元素
使用 parentNode、nextSibling、previousSibling、firstChild 和 lastChild 属性可以遍历文档树中任意类型节点,包括空字符(文本节点)。HTML 5 新添加 5 个属性专门访问元素节点。
- childElementCount:返回子元素的个数,不包括文本节点和注释。
- firstElementChild:返回第一个子元素。
- lastElementChild:返回最后一个子元素。
- previousElementSibling:返回前一个相邻兄弟元素。
- nextElementSibling:返回后一个相邻兄弟元素。
-
创建元素
var element = document.createElement("tagName");
-
复制节点
var p1 = p.cloneNode(false); //复制节点 不包含子节点 var p1 = p.cloneNode(true); //复制节点 包含子节点
-
插入节点
document.body.appendChild(div) // 在节点后插入 box.insertBefore(h1,text) // 在box内,text节点之前插入h1节点
-
删除节点
nodeObject.removeChild(node) ul.removeChild(lis[0]) // 该节点所包含的所有子节点将同时被删除
-
替换节点
box.replaceChild(add,h1) // 在box内,将h1替换为add
-
添加:
-
创建元素节点:var div = document.createElement(“div”);
-
把节点挂到树上:
document.body.appendChild(div)
box.insertBefore(h1,text) 在box内,text节点之前插入h1节点
-
-
删除:父节点可以删除子节点(权限)
- ul.removeChild(lis[0])
-
-
操作文本节点
- div.innerHTML = “hello”
9
9.1 操作DOM
9.1.1 操作节点值操作元素节点
- 创建元素节点
- document.createElement(“ul”);
- 插入元素节点
- body.appendChild(ul);
- insertBefore();
- 删除元素节点
- div.remove(“ul”);
- 复制元素节点
- cloneNode();
- 深复制:包含子节点
- 浅复制:仅复制当前元素
- cloneNode();
- 替换(修改)元素节点
- replaceChild();
9.1.2 操作节点值操作属性节点
-
属性
- 标准属性
- 自定义属性
-
获取属性节点:
- div.title
- div.getAttribute(“title”)
-
设置属性节点:
- div.title = ‘yyyy’
- div.setAttribute(“title”,"ooo)
-
打点调用和api接口调用区别
- 打点方式不能操作自定义属性 ,操作指获取和设置
- 使用getAttribute和setAttribute可以操作自定义属性
- 通过打点方式设置的属性,后期还可以通过打点修改
9.1.3 操作节点值操作文本节点
- innerHTML()
- innerHTML(“xx”)
9.1.4 操作节点值操作CSS样式
-
通过类名
-
div.calssName
-
div.calssName()
-
-
行内样式表
9.1.5 操作节点——添加类、删除类
// 添加类
document.getElementsByClassName('myEL')[0].classList.add('checked');
// 删除类
document.getElementsByClassName('myEL')[0].classList.remove('checked');
// 包含类
document.getElementsByClassName('myEL')[0].classList.contains('checked');
//true or false
9.2 默认事件去除
-
html中有两个标签有默认事件
-
a
<a href="javascript:;"></a>
-
form
-
9.3 事件绑定
-
事件绑定有两种
-
btn.onclick = function(){} ,DOM1
-
btn.onclick = function(){} 写多个后面的会把前面的覆盖掉
- 原因:JS中对象如果有同名属性,后面的肯定会覆盖前面的
-
DOM2 的事件绑定
-
btn.addEventListener(‘click’,function() {})
-
可以写多个监听器
-
原理:不是基于属性绑定,是基于事件池机制(异步任务)
-
-
// 在一个事件源上绑定多个点击事件,只会执行最后一个
let btn1 = document.querySelector('.btn1');
btn1.onclick = function() { // DOM1
alert(123);
}
btn1.onclick = function() {
alert('abc');
}
9.4 进程-线程-任务
- JS是单线程,一次只能执行一个任务
- 进程:工厂 ,一个项目运行就会产生一个进程,进程与进程彼此独立
- 单进程:你把进程杀死了,这个软件就进行不了了
- 多进程:典型:浏览器;一个选项卡关闭,不会影响其他选项卡的使用
- 线程:工人
- 一个进程中可能有多个线程 ,JS是单线程
- 任务
- 进程:工厂 ,一个项目运行就会产生一个进程,进程与进程彼此独立
10
10.1 JS操作盒子模型的API
10.1.1 client(客户端)系列
-
注意:
- 以下几个都是只读属性,只能获取值,不能设置值
- 获取的值,是一个数字,并没有单位
- 获取的值是一个整数(小数会转换为整数)
- client系列不管内容是否溢出,得到的都是盒子的可视区域
-
clientWidth
- 获取box的内容区域width+左右padding(可视区域width的大小)
-
clientHeight
- 获取box的内容区域height+上下padding(可视区域height的大小)
-
clientTop
- 获取盒子的上边框大小
-
clientLeft
- 获取盒子的左边框大小
-
常用:获取当前页面一屏的高度
- document.body.clientHeight
- document.documentElement.clientHeight
10.1.2 offset(偏移量)系列
- offsetWidth
- box.offsetWidth ,在clientWidth的基础上加了border
- offsetHeight
- box.offsetHeight ,在clientHeight的基础上加了border
- offsetTop
- 获取一个绝对定位元素相对于参考点上面的距离
- offsetLeft
- 获取一个绝对定位元素相对于参考点左面的距离
- offsetParent
- 获取一个绝对定位元素的参考点
10.1.3 scroll系列
- scrollWidth
- 在没有内容溢出的情况下:scrollWidth = clientWidth
- 有内容溢出情况下:scrollWidth的值约等于真实内容的宽度,不同浏览器中得到的值可能不一样
- overflow属性会影响scrollWidth
- 只能获取值,不能设置值
- scrollHeight
- 在没有内容溢出的情况下:scrollHeight = clientHeight
- 有内容溢出情况下:scrollHeight的值约等于真实内容的高度,不同浏览器中得到的值可能不一样
- overflow属性会影响scrollHeight
- 只能获取值,不能设置值
- 常用:获取当前页面的真实内容的高度
- document.body.scrollHeight
- document.documentElement.scrollHeight
- scrollTop
- 获取垂直滚动条卷上去的高度
- 特点:可读可写
- 常用:
- 获取当前页面卷上去的高度
- document.body.scrollTop
- document.documentElement.scrollTop
- 一张网页卷上去的最大高度是?
- 内容真实高度scrollHeight - 可视区高度clientHeight
- 获取当前页面卷上去的高度
- scrollLeft
- 可读可写
- 获取水平滚动条卷去的距离
10.1.4 常用
- 获取一张网页可视区的高度
- document.body.clientHeight
- 获取一张网页真实的高度
- document.body.scrollHeight
- 获取一张网页卷去的高度
- document.body.scrollTop
10.2 定时器
10.2.1 一次性定时器
- window.setTimeout(()=>{},1000); // 1s后执行回调函数
- 关闭定时器:clearTimeout();
10.2.2 循环定时器
- window.setInterval(()=>{},1000); // 每隔1s执行里面的回调函数
- 循环定时器会产生很多EC,如果不用,一定要关闭定时器
- 关闭定时器:clearsInterval();
10.3 事件流与事件对象
10.3.1 事件流
-
事件会流动
- 默认情况下:从里向外流动,这种方式叫冒泡。
- 从外向里,叫捕获。
-
DOM0(例如onclick 事件),只能冒泡,不能捕获
-
DOM2 能够修改
// 第三个参数默认为false:冒泡,修改true:捕获 fa.addEventListener('click',fn,true);
10.3.2 事件对象(e)
-
事件本质是对象
-
能干啥:
-
阻止冒泡
son.onclick = function (e) { // 阻止冒泡 e.cancelBubble = true; console.log('son...'); }
-
阻止默认事件
<!-- 第一种方式 --> <!-- <a href="javascript:;">百度</a> -->
let link = document.querySelector('a'); link.onclick = function (e) { // 第二种方式 // 阻止默认事件 e.preventDefault() }
link.onclick = function (e) { // 第三种方式 在监听器后面写一个 return false; return false }
-
11 图片懒加载
-
图片延迟加载
- 一个网站上的图片,并不是一次加载所有的。
- 当图片冒尖的时候,再给图片的src赋值,给图片的src赋值,src会重新去请求服务器要资源
-
实现步骤:
1)不要直接写src
这样写直接显示
2)给src起一个别名,叫什么无所谓,通常叫data-src,就是一个自定义属性