web前端知识点(JavaScript篇)
call,apply,bind
call,apply,bind这三者的区别,及内部实现原理,点这里
promise
promise函数的内部实现原理,点这里
闭包
闭包就是能够读取其他函数内部变量的函数。形式上,就是一个函数返回一个内部函数到函数外,内部函数引用外部函数的局部变量。本质上,闭包是将函数内部和函数外部连接起来的桥梁。
原型链
JavaScript中每一个对象都有一个__proto__和constructor属性,每一个函数都有一个prototype属性,因函数也是对象,所以函数也拥有__proto__和constructor属性。
__proto__指向的是它们的原型对象,也可以理解为父对象。如果访问本身一个不存在的属性,那么没有获取之后会去它的原型对象去获取,而原型对象本身也是一个普通对象,如果在它的原型对象中同样没有获取到,那么就会往原型对象的原型对象去获取,直到顶层对象null(原型链终点,一个没有任何属性的对象),返回undefined。这就形成了一条原型链。
prototype属性是函数独有的,是从一个函数指向一个对象,称之为函数的原型对象。原型对象内包含特定类型所有实例共享的属性和方法,作用为被该函数实例化出来的对象找到共用的属性和方法。
constructor是从一个对象指向一个函数,称之为该对象的构造函数。每个对象都有对应的构造函数,因为对象的建立前提是需要有constructor。
节流与防抖
节流:
节流是在规定的时间内只执行一次,稀释函数执行频率。比如规定时间2s内执行了一次函数,那么在这2s内再次触发将不会执行。
function throttle(time, fn) {
let isRun = false
return function () {
if (isRun) return
isRun = true
let arg = [...arguments]
setTimeout(() => {
fn.apply(null, arg)
isRun = false
}, time * 1000)
}
}
防抖:
防抖是在等待的时间内不断触发函数,但函数真正执行的将是最后触发的那次。比如规定时间为2s,如果第二次与第一次的触发的时间间隔小于2s,那么第一次将会被清除,留第二次触发的函数继续等待,如果2s内没有第三次触发,将执行第二次触发的函数,如果2s内又触发了第三次,那么第二次触发的函数也将被清除,留第三次触发的函数继续等待。
function debounce(time, fn) {
let timer = null
return function () {
let arg = [...arguments]
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(null, arg)
clearTimeout(timer)
timer = null
}, time * 1000)
}
}
斐波那契数列、快排、冒泡排序
斐波那契数列:1、1、2、3、5、8、13、21、……
// 递归
function fibonacci(num) {
if (num === 1 || num === 2) {
return 1
}
return fibonacci(num - 2) + fibonacci(num - 1)
}
// 循环
function fibonacci1(n) {
var n1 = 1, n2 = 1, sum;
for (let i = 2; i < n; i++) {
sum = n1 + n2
n1 = n2
n2 = sum
}
return sum
}
快速排序:
function quickSortFn(_arr) {
let arr = [..._arr]
if (arr.length <= 1) {
return arr
}
let left = []
let right = []
let item = arr.pop()
for (let i = 0, len = arr.length; i < len; i++) {
let val = arr[i]
if (val >= item) {
right.push(val)
} else {
left.push(val)
}
}
return [...quickSortFn(left), item, ...quickSortFn(right)]
}
冒泡排序:
function bubbleSort(_arr) {
let arr = [..._arr]
let len = arr.length
for (let i = 0; i < len - 1; i++) {
for (let k = i + 1; k < len; k++) {
if (arr[i] > arr[k]) {
[arr[i], arr[k]] = [arr[k], arr[i]]
}
}
}
return arr
}
多维数组转一维数组
// 第一种
let a = [1,2,[3,4],[5,[6,[7,8]],9]]
a.join(',').split(',') // 第二种
function unid1(arr) {
for (let item of arr) {
if (Object.prototype.toString.call(item).slice(8, -1) === 'Array') {
unid1(item);
} else {
result.push(item);
}
}
return result;
}
js流程控制
function LazyMan(name) {
this.task = []
let self = this
let fn = (name => {
return () => {
console.log(name)
self.next()
}
})(name)
self.task.push(fn)
setTimeout(() => {
console.log(222)
self.next()
})
}
LazyMan.prototype = {
constructor: LazyMan,
next() {
let fn = this.task.shift()
fn && fn()
},
eat(val) {
let self = this
self.task.push((val => {
return () => {
console.log(val)
self.next()
}
})(val))
return this
},
sleep(num) {
let self = this
self.task.push((num => {
return () => {
setTimeout(() => {
console.log(num)
self.next()
}, +num * 1000)
}
})(num))
return this
}
}
function lazyMan(name) {
return new LazyMan(name)
} lazyMan('zz').eat('lunch').sleep('3').eat('dinner')
对象深拷贝与浅拷贝
深拷贝与浅拷贝的区别本质是被复制出来的值的内存地址是否有改变,内存地址没变就是浅拷贝,有变就是深拷贝。这里涉及到了JavaScript的引用数据类型,引用数据类型的复制,复制的不是对象本身,而是一个指向该对象的指针,当这个对象本身的值改变,那么所有引用这个对象的变量都会改变。
浅拷贝:
Object.assign()
深拷贝:
JSON.parse(JSON.stringify(object)):
这个能够拷贝除Function、RegExp与undefined等类型之外的值,如果遇到这种类型,将会被自动忽略。
循环递归拷贝:
function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1)
}
function deepClone(obj) {
if (obj && typeof obj === 'object') {
let returnObj = getType(obj) === 'Array' ? [] : {}
let item = ''
for (let key in obj) {
item = obj[key]
if (key === "__proto__") {
continue;
}
if (getType(item) === 'Array' || getType(item) === 'Object') {
returnObj[key] = deepClone(item)
} else {
returnObj[key] = item
}
}
return returnObj
}
}
异步与事件轮询机制
JavaScript语言的核心特点就是单线程,单线程的原因主要是对DOM的操作,多线程操作DOM会引起冲突。为了利用多核CPU的计算能力,HTML5提出了web worker标准,允许JavaScript创建多线程,且创建线程完全受主线程控制,且不得操作DOM。
js的异步是通过回调函数实现的,即任务队列。虽然js是单线程的,但浏览器的多线程的,则js的执行遇到异步任务都会调用浏览器的多线程去执行,当异步任务有了结果,则会将异步任务的回调函数放入异步任务队列。
任务队列分为两种:宏任务队列与微任务队列。
当js从上往下执行时,如遇到异步任务,浏览器则用其他线程去执行,当异步任务有了结果,则将回调函数放到任务队列中,当主执行栈执行完后,会去查询微任务队列,如果有则执行,微任务队列执行完后,则将宏任务队列放入主执行栈重新开始下一轮循环。
不同的js异步API的回调函数放入不同的任务队列。
宏任务(macrotask)队列API:
- setTimeout
- setInterval
- setImmediate(node)
- requestAnimationFrame(js)
微任务(microtask)队列API:
- process.nextTick(node)
- MutationObserver(node)
- Promise.then catch finally
注意的一点:微任务队列中的微任务回调函数是放入当前微任务队列中,而不是下轮循环队列。
浏览器垃圾回收机制
- 标记清除
垃圾收集器给内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记。在此之后再被加上的标记的变量即为需要回收的变量,因为环境中的变量已经无法访问到这些变量。
- 引用计数
js执行上下文和执行栈
该点的解释则是表明JavaScript程序内部的执行机制。
执行上下文,简而言之,就是当前JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript任何代码都是在执行上下文中运行。
三种类型:
- 全局执行上下文:不在任何函数内的代码都处于全局执行上下文,一个程序只能有一个全局执行上下文。做了两件事:1、创建了一个全局对象,浏览器则是window;2、将this指向这个全局对象。
- 函数执行上下文:每个函数都有自己的执行上下文。调用函数时,都会为这个函数创建一个新的执行上下文,也只在函数被调用时才会被创建。一个程序内的函数执行上下文没有数量限制,每当一个函数执行上下文被创建,则会执行一系列操作。
- eval函数执行上下文:不常用,略。
生命周期:
- 创建:创建变量对象,创建作用域链,确定this指向(this的赋值是在执行的时候确定的)。
- 执行:变量赋值,代码执行。
- 回收:执行完成,执行上下文出栈,等待回收。
管理执行上下文:
所有的执行上下文采用的是栈结构来管理,遵循先进后出。全局JavaScript代码在浏览器执行时,实现创建一个全局执行上下文,压入执行栈的底端,每创建一个函数执行上下文,则把它压入执行栈的顶端,等待函数执行完,该函数的执行上下文出栈等待回收。
JavaScript解析引擎总是访问执行栈的顶端,当浏览器关闭,则全局执行上下文出栈。
url输入到页面显示之间的过程
- 用户输入的url作DNS解析,获取IP地址
- 建立TCP连接
- 发送HTTP请求,获取html文件
- 解析HTML文件,构建DOM树及CSSOM规则树,然后合并渲染树,绘制界面。
- 发送HTTP获取HTML文件内其他资源。
new操作符中的执行过程
- 创建一个新对象 newObject
- 将新对象 newObject 的 __proto__ 指向原函数 fn 的 prototype
- 执行原函数 result = fn.call(newObject)
- 判断返回类型,如果是值就返回这个result,如果是引用类型,返回这个引用对象
async/await的实现原理
async/await的作用为阻塞异步执行任务,等待异步任务执行完返回,再执行下面任务,异步任务返回的是一个Promise对象。
实现原理为generator + yield + promise:generator自动执行且返回一个promise对象。
let test = function () {
// ret 为一个Promise对象,因为ES6语法规定 async 函数的返回值必须是一个 promise 对象
let ret = _asyncToGenerator(function* () {
for (let i = 0; i < 10; i++) {
let result = yield sleep(1000);
console.log(result);
}
});
return ret;
}(); // generator 自执行器
function _asyncToGenerator(genFn) {
return new Promise((resolve, reject) => {
let gen = genFn();
function step(key, arg) {
let info = {};
try {
info = gen[key](arg);
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(info.value);
} else {
return Promise.resolve(info.value).then((v) => {
return step('next', v);
}, (error) => {
return step('throw', error);
});
}
}
step('next');
});
}
跨域问题的产生及解决方案与原理
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。
而狭义的跨域是指:当浏览器与服务器通信的两个地址的协议、域名、端口,这三者任意一个不同,都会导致跨域问题的产生,这是基于浏览器的同源策略限制。
限制的行为:
- cookie,localstorage和IndexDB无法读取
- DOM无法获取
- Ajax请求不能发送
解决方案:
- jsonp跨域通信:只能用于get请求,基于浏览器允许HTML标签加载不同域名下的静态资源,通过script动态加载一个带参网址实现跨域通信实现跨域。
- postMessage跨域:postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一。
- nginx代理:服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
- 跨域资源共享(CORS):只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
- nodejs中间件代理跨域:node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入。
- WebSocket协议跨域:WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
- document.domain + iframe跨域:此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域
- location.hash + iframe跨域:a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
- window.name + iframe跨域:window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
正向代理与反向代理的区别:
正向代理与反向代理并没有形式上的区别,只是一个认知的问题。比如a请求b有跨域问题,正向代理与反向代理都可以通过中介c来实现,a -> c -> b -> c -> a这样完成了一次跨域通信,如果a请求c,知道c会去请求b再返回,则是一个正向代理,如果a不知道请求c,c最终去请求了b,那这就是一个反向代理。最终目的地址以IP为准。
es6新特性
- 字符串扩展:includes、startsWith、endsWith等新API及模板字符串。
- 对象扩展:keys、values、entries、assian等。
- 数组扩展:find、findIndex、includes等。
- 新的变量声明:let、const。
- 解构表达式:数组解构与对象解构。
- 函数优化:函数参数默认值、箭头函数、对象的函数属性简写。
- 数组优化:map与reduce等API的增加。
- Promise:异步微任务API的增加。
- 新数据结构:set、map。
- 模块化:export、import。
- 二进制与八进制字面量:数字前面添加0o/0O和0b/0B可将其转化为二进制和八进制。
- 类class:原型链的语法糖表现形式。
- for...of/for...in:新的遍历方式。
- async/await:同步异步任务。
- Symbol:新的数据类型,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
未完待续......
web前端知识点(JavaScript篇)的更多相关文章
- web前端分享JavaScript到底是什么?特点有哪些?
web前端分享JavaScript到底是什么?特点有哪些?这也是成为web前端工程师必学的内容.今天为大家分享了这篇关于JavaScript的文章,我们一起来看看. 一.JavaScript是什么? ...
- 好程序员web前端分享javascript关联数组用法总结
好程序员web前端分享javascript关联数组用法总结,有需要的朋友可以参考下. Hash关联数组定义 代码如下 // 定义空数组 myhash = { } // 直接定义数组 myhash = ...
- Python web前端 05 JavaScript
Python web前端 05 JavaScript 一.获取元素 1.初识JavaScript /* .. */ #这是多行注释 // #这是单行注释 #JavaScript是一种脚本语言,是一种动 ...
- 我的前端规范——JavaScript篇
相关文章 简书原文:https://www.jianshu.com/p/5918c283cdc3 我的前端规范——开篇:http://www.cnblogs.com/shcrk/p/9271561.h ...
- 1+x 证书 Web 前端开发 JavaScript 专项练习
官方QQ群 1+x 证书 Web 前端开发 JavaScript 专项练习 http://blog.zh66.club/index.php/archives/198/
- [总结]web前端常用JavaScript代码段及知识点集锦
DOM相关 判断浏览器是否支持placeholder属性 function placeholderSupport() { return 'placeholder' in document.create ...
- web前端知识点(webpack篇)
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency gr ...
- 25、前端知识点--webpack篇之面试考点
前端面试之webpack篇 https://blog.csdn.net/sinat_17775997/article/details/78122999 关于webpack的面试题 随着现代前端开发的复 ...
- WEB前端常用JavaScript代码整理
文章目录 html代码用JS动态加载进页面 JS判断用户访问的是PC还是mobile或者微信浏览器 判断浏览器的简单有效方法 点击某个div区域之外,隐藏该div 如何在手机上禁止浏览器的网页滚动 改 ...
随机推荐
- MongoDB知识点总结
一:MongoDB 概述 一.NoSQL 简介 1. 概念:NoSQL(Not Only SQL的缩写),指的是非关系型数据库,是对不同于传统的关系型数据库的数据库管理系统的统称.用于超大规模数 ...
- vue2.0+Element UI 表格前端分页和后端分页
之前写过一篇博客,当时对element ui框架还不太了解,分页组件用 html + css 自己写的,比较麻烦,而且只提到了后端分页 (见 https://www.cnblogs.com/zdd20 ...
- 【 哈希和哈希表】Three Friends【进制哈希】
Three Friends 传送门:链接 (UPC)或 链接(大视野) 题目描述 Three friends like to play the following game. The first f ...
- Visible Lattice Points(规律题)【数学规律】
Visible Lattice Points 题目链接(点击) Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9031 ...
- Mac搭建Fluter应用环境
1.创建一个路径.例如我创建是: /Users/chenghui/ 然后创建一个文件夹: development 把下载好的Fluter 解压到当前目录下: development /Users/ch ...
- 有没有人想和我一起编写 Clear Writer 的?
合作内容 程序编写 了解 JS.HTML.CSS 等基础前端技能,了解 Electron 开发. 翻译 熟练运用一门外语(中文英文除外),书面表达过关. 报酬 在 Github 上本项目里面的 REA ...
- mysql小数类型
原文链接:https://blog.csdn.net/weixin_42047611/article/details/81449663 MySQL 中使用浮点数和定点数来表示小数. 浮点类型有两种,分 ...
- json 拼装空list、object
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; public class FastJson ...
- 使用Vim写LaTeX代码(Vim+Vimtex+Skim)
最近在写博客的时候发现对数学公式的支持并不好,于是就想寻找一个解决方案.我本身是一个爱折腾的人,有时尽管有现成的解决方案我有事也不愿意去用.于是多方查找资料,想寻求一个自定义的解决方案,最终把自己的目 ...
- 囚徒问题(100 prisoners problem)的python验证
密码学课上老师介绍了这样一个问题,囚徒问题(100 prisoners problem):一百个囚徒被关在牢房里,典狱长给他们最后一次机会,100人依次进入一个有100个抽屉的牢房,每个抽屉置乱放入1 ...