什么是闭包? 闭包是指能在函数外部获取到声明在函数内部变量的函数
闭包的作用
闭包可以储存变量,一般在函数体内声明的变量,在使用完后会被释放,但闭包的外部函数中的变量一直是引用状态,不会被释放。闭包可以用来操作私有变量。例如:
function A() { let num = 10 return function () { return num } }
作用域链保证了执行环境里有权访问的变量和函数时有序的,作用域链中的变量只能向上访问,直到访问到 window 对象
每个对象中都有一个内部属性,就是 prototype(原型),每个对象声明的实例中也都含有一个属性,就是 __proto__ (原型)
关系: instance.__proto__ == instance.constructor.prototype
特点: 当我们访问一个对象的属性时,如果在对象上找不到,就会沿着原型链向上层寻找,直到 Object
父类(构造函数):
function Animal(name) { this.name = name } Animal.prototype.eat = function () { console.log('吃肉..') } 原型链继承 function Dog() {} Dog.prototype = new Animal() let dog = new Dog() console.log(dog.name) // undefined dog.eat() // 吃肉..重点: 让子构造函数的原型指向父构造函数的实例 优点: 可以继承父构造函数原型中的属性和方法 缺点: 新实例无法向父类构造函数传参,无法继承构造函数实例中的属性和方法
构造函数继承 function Cat() { Animal.call(this, '猫') } let cat = new Cat() console.log(cat.name) // 猫 cat.eat() // cat.eat is not a function重点: 子构造函数中调用父构造函数并改变 this 指向 优点: 可以继承父构造函数中的属性和方法 缺点: 无法继承构造函数原型中的属性和方法
组合继承(常用) function Cat(name) { Animal.call(this, name) } Cat.prototype = new Animal() let cat = new Cat('猫') console.log(cat.name) cat.eat()重点: 结合构造函数继承和原型链继承的特点 优点: 可以继承父构造函数及其原型中的属性和方法 缺点: 代码复杂
class 关键字继承父类:
class Animal { constructor(name) { this.name = name } eat() { console.log(this.name + '吃吃吃') } }子类:
class Cat extends Animal { constructor(name) { super(name) } } let cat = new Cat('猫') console.log(cat.name) // 猫 cat.eat() // 猫吃吃吃重点: 子类的 constructor 方法中要调用 super 方法,表示调用父类的 constructor 方法 优点: 可以继承父类中的属性和方法,代码简单
事件代理又叫事件委托,是把原本要监听的事件绑定给父元素,原理是利用了事件冒泡,使用事件委托的优点是:
节省大量内存,减少时间注册新增子节点时无需重新绑定事件
创建 Ajax 过程:
let xhr = new XMLHttpRequest() xhr.open(method, url, asynchronous) xhr.send() xhr.onreadystatechange = function () { if (readyState == 4) { if (xhr.status == 200) { success(xhr.responseText) } else { fail(xhr.status) } } }readyState:
0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪
同源策略: 协议名、域名、端口号都相同的两个URL地址叫做同源,非同源的地址间交互会产生跨域。 解决跨域:
通过 JSONP 解决跨域通过 CORS 解决跨域(跨域资源共享)node.js 中间件代理跨域WebSocket协议跨域详细情况:https://segmentfault.com/a/1190000011145364
传参方式: get 传参会拼接到URL地址后,形式是 ? 后面以 & 分割,post 传参是将参数放到请求体里 数据大小: get 传参有数据大小的限制,一般参照浏览器地址栏支持的最大字节长度,post 传参没有参数数据大小要求 安全性: post 的安全性相对较高。 使用: get 和 post 都可以用来获取或更新数据,只是一般用 get 来获取数据,post 来存储数据
立即执行函数,不暴露私有成员
let module = (() => { let num = 0 let f1 = () => {} let f2 = () => {} return { f1, f2 } })()
共同点
不会阻塞文档元素的加载使用这两个属性的脚本中不能使用 document.write允许不定义属性值,直接使用属性值只适用于外部脚本
元素视图属性
offsetWidth :元素 content 宽度 + 左右 border + 左右 paddingoffsetHeight :元素 content 高度 + 上下 border + 上下 paddingclientWidth :元素 content 宽度 + 左右 paddingclientHeight :元素 content 高度 + 上下 paddingscrollWidth :元素内容真实宽度,内容不超出盒子宽度时为 clientWidthscrollHeight :元素内容真实高度,内容不超出盒子宽度时为 clientHeightwindow 视图属性
innerWidth :浏览器窗口可视区宽度innerHeight :浏览器窗口可视区高度
Promise 主要用于异步操作,可以将异步操作队列化。新建实例时,传入一个无名函数并且具有两个参数;参数一是成功后调用的函数名,函数体当做参数传入 then() 中,参数二是失败后调用的函数名,函数体当做参数传入 catch() 中
let promise = new Promise((resolve, reject) => { if (true) { resolve('成功') } else { reject('失败') } }) promise.then(res => console.log(res)).catch(err => console.log(err))补充:Promise 有三个状态:进行中、成功后、失败后,且状态一旦从进行中变为成功或失败后,状态就不能再发生变化。所以每次在调用 then() 或 catch() 后,都会返回一个新的实例,以保证 Promise 的链式操作。
基本数据类型: Number 、String 、Boolean 、Null 、Undefined ----- 不能拥有属性和方法 引用数据类型: Function 、Array 、Object ----- 拥有属性和方法(对象) 基本包装类型: Number 、String 、Boolean 、Null 、Undefined ----- 属于特殊的引用类型,与基本类型对应
每当声明一个基本数据类型(Number 、String 、Boolean)的变量,后台都会声明一个同名的与之对应的引用类型(基本包装类型)的变量,从而使基本类型的变量可以调用一些属性和方法
如果声明的是基本类型(Number 、String 、Boolean),此时在实例上新增的属性或方法只存在一瞬间(一行代码内); 如果声明的是引用类型(Number 、String 、Boolean),此时在实例上新增的属性或方法长久存在;
例:
// 声明基本类型,代码 // 后台对应代码 const str1 = 'hello world' // const str1 = new String('hello world') str1.color = 'red' // str1.color = 'red' // str1.color = null (属性消除) console.log(str1.color) // undefined // 声明引用类型,代码 // 后台对应代码 const str2 = new String('hello world') // const str2 = new String('hello world') str2.color = 'red' // str2.color = 'red' console.log(str2.color) // red
undefined 是声明了变量但没有赋值,null 是声明了变量并且赋值为 null 判断 undefined 和 null 时,必须用 === / !== ,因为 == 和 != 无法区分 undefined 和 null
在 js 脚本开头使用 use strict
严格模式的限制:
变量必须先声明,再使用函数的参数不能有同名属性,否则报错不能使用 with禁止 this 指向全局变量
attribute 是 DOM 元素在 html 文档中作为标签拥有的属性 property 是 DOM 元素在 JS 中作为对象拥有的属性 对于标准属性来说,attribute 和 property 是同步的,但是自定义属性不同步
Vue 是采用数据劫持结合订阅者-发布者模式,通过 Object.defineProperty() 来劫持各个属性的 setter 和 getter ,数据变动时发布消息给订阅者,触发响应的监听回调
不能一次性将几万条数据都渲染出来,可以分批渲染,每次规定渲染条数 利用 window.requestAnimationFrame 来进行页面刷新
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <ol id="olObj"></ol> </body> <script> let total = 10000 let each = 23 let loopCount = Math.ceil(total / each) let count = 0 const olObj = document.getElementById('olObj') function appendObj() { let fragment = document.createDocumentFragment() for (let i = 0; i < each; i++) { let totalObj = count * each + i + 1 if (totalObj > total) { break } const liObj = document.createElement('li') liObj.innerHTML = 'item' + totalObj fragment.appendChild(liObj) } olObj.appendChild(fragment) count++ loop() } function loop() { if (count < loopCount) { window.requestAnimationFrame(appendObj) } } loop() </script> </html>window.requestAnimationFrame
window.requestAnimationFrame() 告诉浏览器,希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
document.createDocumentFragment
createDocumentFragment() 方法,是用来创建一个虚拟的节点对象,或者说,是用来创建文档碎片节点。它可以包含各种类型的节点,在创建之初是空的。 DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null 。它有一个很实用的特点,当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点,即插入的是括号里的节点。这个特性使得 DocumentFragment 成了占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。 另外,当需要添加多个 dom 元素时,如果先将这些元素添加到 DocumentFragment 中,再统一将 DocumentFragment 添加到页面,会减少页面渲染 dom 的次数,效率会明显提升。 如果使用 appendChid 方法将原 dom 树中的节点添加到 DocumentFragment 中时,会删除原来的节点。
创建新节点
createElement() 传入标签名称,创建元素节点createTextNode() 创建文本节点createDocumentFragment() 创建一个空的 DOM 片段添加、移除、替换、插入
appendChild() 末尾添加节点removeChild() 移除节点,传入要被移除的节点,返回被移除的节点insertBefore() 插入节点,传入新插入的节点和在哪个节点之前插入replaceChild() 替换节点,传入要被替换的节点查找
getElementById()getElementsByClssName()getElementsByTagName()getElementsByName()querySelector()querySelectorAll()