我是做前端工作的,我会把工作分为三个部分。
比如说:项目前、项目中期和项目后期。
这样的话,我们在前、中、后期三个节点上面的效率就会得到最大的提升。
注:你做自我介绍的时候,兴趣爱好、学历啥的简历上都有,不用拿来介绍。
我叫xxx,我掌握的技能有哪些?如:H5、C3、js、element-plus、node、vue等等。
在工作中我的打包工具用的是什么?如:webpack、vite。
我的版本控制工具(分布式)用的是什么?如:git
说完这些之后,最好加一些,在以前的工作当中,我们前端经常遇到的是什么问题?比如说接口安全的问题、常见的一些攻击的问题、适配的问题等等。
在这个时候,对于成熟的前端人员来说的话,想问的相对来说多一些:
个人信息:以简洁明了为主。姓名、学历、毕业院校、电话、邮箱,不要超过6项。
专业技能:以充实为主。把会的技能多写上一些。
过往的经历:过往的公司和时间要搭配,不要有空窗。
项目介绍:一到两年(包装2-3个项目)、三年(3-4个项目)。你工作3年就只有这3个项目吗?回答:我放到简历上的项目,是我认为比较好的,其实其他的一些小的项目,有一些雷同的地方,我没有往上写,所以从中挑选了基本较好的项目。
注意点:
自我评价:本人比较善于沟通,团队协作能力比较强,能够完成领导交待前端相关的工作任务。
注意:聊的时候,一定不要跟人家谈年限,最近两年要干什么。。。
回答:我作为一个前端来说,我近期的职业规划是把咱们公司的项目做好,另外呢,学无止境,把我的技术得以提升。多学一些组件、插件,多学一到两款框架。
对于中长期的规划来说的话,我打算呢将来我再研究一门后台语言,比如说像Java、PHP、Python这些我研究一门,争取研究一门之后,可以更加方便咱们前端跟后端去沟通,为咱们公司更好的去服务。另外呢,我也相信,咱们公司有合理的晋升机制和制度。所以呢,如果将来公司有这样的机会,这种机会放在我跟前,我也是会毛遂自荐,服务好公司。
这就是我近期、中期和长期的一个职业规划。
如果公司录用我了,我将会带着我以前的技术和经验,把这些东西带到咱们的项目中,让咱们的项目更好,更人性化。
我会快速的掌握咱们现在所写的项目。包括它的路由是怎么架构的,接口的请求是怎么来处理的,还有它里面的一些难点重点的技术,我以前有没有处理过。
这些都是我们前端人员在刚入职的时候要做的事情。以避免后边在开展工作中遇到这些问题,再去处理就比较难处理了。
要考虑我是不是需要后台或者其他的技术人员去配合,这个也要有一个正确的评估。为啥要评估这个呢?如果问题到了跟前再去跟后台沟通,这样的话,很可能会打乱后台的工作计划。
进入公司以后,我打算基于以上三个方面开展工作。
注意点:
回答:
我可以接受加班,不管是自己的原因还是其他的一些什么原因,都是可以免费接受的。
在我们公司以前技术部分这么几个角色:
产品经理、UI、前端人员、后台(后台是一个统称:Java、PHP、Android、iOS都是在写后台的业务逻辑),以上这些角色去进行项目开发。
前端在项目中的地位和工作流程:
产品经理: 当一个项目进来,最先跟这个项目客户去接触的一般是产品经理,产品经理的作用是:和客户进行聊天,聊天的过程中,他会做一个产品需求文档(说白了,就是客户想要什么?),在这里面有一个重要的职责,有时候客户很盲目,他不知道自己的需求到底是什么(比如说他想做一个卖菜的网站,他可能不知道什么是APP,但是他们会使用),这个时候产品经理要做的就是正确引导客户需求。然后,产品经理需要把这些需求跟UI、前端等技术人员去讲明白。
UI: 出了需求文档之后,产品经理会把文档给到UI、前端、后台各一份。UI 把需求文档做成原型图(黑白的,像黑白照片)和设计图,UI在整个工期里面大概要占到三分之一。当设计稿出来后,同时交给前端和后台,因为基本上前端和后端干活是并行的。
前端: 开始根据页面去制作各种各样的效果。或者是DIA(diagram 图表)
或者是小程序。在这个过程中后台也在干活。
后台: 后台就要开发它对应的数据管理部分。除此之外,后台还需要去做 API 接口的东西,这个接口是为前端去开发的。
等到前端的页面布局完了,后台的接口也写完了,剩下的就是前端去渲染数据,调用接口里面相对应的数据就可以了。这些完了之后,就是一个测试阶段。
测试阶段: 测试阶段是 UI、前端、后台都需要参与的,如果有专业的测试,他们的工作量就稍微会少一点。都参与可以保证出现问题可以及时得到处理。
部署: 测试完成之后,再把这个项目部署到客户的服务器上去。
基本上整个工作流程就是这样子的。
如:10k为例,我上家公司是这样发放的:
基本工资:5000
岗位工资:如前端 3000
绩效工资:2000左右(总工资的15%-20% )
绩效工资是一个考核标准,干得好才有,你负责的部分出了问题会扣一部分或者扣除全部。
补贴补助:1000以内(话补、餐补、车补等等)。
社保公积金:一般情况下公积金+社保占 10%左右。
扣税:5000以上需要交税
真正到手的大概是九千左右的一个范围
如果这个时候我走了,我会得到什么,我会失去什么?
我得到了:我得到的肯定是一份新工作,需要吃饭穿衣嘛这个很正常。
我失去了:我会失去老板和领导对我的信任,俗话说:“患难见真情”,如果我跟他们共渡难关,在工作中共同努力克服了困难,挺过这一关,那我在这个公司的价值会大大提升。而且我的口碑也会好很多。
每一个员工应该各司其职,尽职尽责把自己的工作做好,做好之后,才能够让公司踏踏实实,放心去解决问题。当然在自己的事情完成得很好的情况下,在力所能及的范围之内去帮助其他的同事。如果一个团队、一个公司的人都有这样的想法,我觉得老板和领导一定会想尽办法去解决公司的困难。
注:我说15000,HR压榨成9000
做两手准备:
这个时候跟 HR 去较劲,很大概率是会谈崩的。
Async:
async 用来定义函数的,异步函数,打印函数名会得到一个promise对象。可以使用函数名称来调用.then方法,如:函数名称.then
async 内部实现,有返回值。其实是内部调用了 promise.resolve()
,然后把它转换成一个promise对象。如果出错的话,调用的是promise.reject()
。它用catch捕获了一下
Await:
await 理论上来说后面可以跟任意的表达式。但是一般是跟promise的表达式
async function add() {
const res = await 123
console.log(res) // 123
return res
}
console.log(add()) // 成功的promise,值是123
await 等待后边的promise对象执行完毕,拿到了promise.resolve()
的返回值之后,在往后继续去执行后边的代码,所以await有一个等待的意思。
await关键字只能写在async的函数里。
await 后边的表达式可能是失败的,await 只能拿到成功的结果,如果失败会向浏览器控制台抛出错误。所以建议把await的代码放到try…catch语句中捕获错误会比较好。
async function test() {
const res = await Promise.reject(123)
return res
}
console.log(test()) // Uncaught (in promise) 123
async function test() {
try {
const res = await Promise.reject(123)
} catch (error) {
console.log('error', error) // 2. error 123
}
}
console.log(test())
console.log(111) // 1. 111
promise 和 async await 区别:
命令:npm run build
需要在vue.config.js
中配置 entry, output
处理方案:
打包后,会在dist下生成.map文件,那么这个文件其实是不必要的
解决:在vue.config.js中配置文件中:productionSourceMap: false
。这样就不会生成.map文件了。
使用组件和路由懒加载
组件和路由懒加载是按需加载的,这样会降低一些文件的大小。
对于文件和图片,最好压缩一下。可以使用这个组件(此组件需要安装):compression-webpack-plugin
导入组件:compression-webpack-plugin
配置:
安全问题是一个很宽泛的问题,如:xss和csrf攻击等等。
这里主要谈论的是接口的安全问题。
接口安全:防止传输过程中,数据被抓包。我们会在数据传输的时候(前台传给后台,后台传给前台)进行加密和解密。
常用的加密算法:
aes rsa SHA1 SHA256 md5 … 有很多的算法
胡哥用过的有 aes rsa
aes加密工具的使用:
安装:npm i crypto-js –save -dev
在utils工具文件夹下创建crypto.js文件
crypto.js中写入
import cryptojs from 'crypto-js'
export default {
encrypto(str) { // 加密
// 生成秘钥
// 秘钥是前端和后端都知道的,但是网络上是不知道的,所以他们截取去了也没有用。比如说我们前端生成秘钥是11111,那么后端也要用11111去解密
let key = crytojs.enc.utf8.parse('11111')
// 生成偏移量 --- 一般都是传进来的字符串
// 生成偏移量作用:如果字符串内容长度不够,会自动补齐
let srcs = cryptojs.enc.utf8.parse(str)
// 加密 --- 参数:偏移量,秘钥,配置加密的参数
let encrypted = cryptojs.AES.encrypt(str,key,{
mode: cryptojs.mode.ECB, // 加密模式
// ECB 表示等量加密,就是说长度跟你的str相同
padding: crytojs.pad.pkcs7 // 加密、解密的标准
})
return encrypted.toString()
},
decrypto(str) { // 解密
let key = crytojs.enc.utf8.parse('11111')
// 解密不需要偏移量
// 加密 --- 参数:偏移量,秘钥,配置加密的参数
let decrypted = cryptojs.AES.decrypt(str,key,{
mode: cryptojs.mode.ECB, // 加密模式
// ECB 表示等量加密,就是说长度跟你的str相同
padding: crytojs.pad.pkcs7 // 加密、解密的标准
})
return decrypted.toString()
}
}
注意:
padding: crytojs.pad.pkcs7
,而后端是padding: crytojs.pad.pkcs5
jsencrypt 算法是一种非对称加密算法,它得生成一对秘钥,即公钥和私钥。前后端一样的,加密的时候使用公钥,解密的时候使用私钥。
长度可以能是1024也可能是2048。已知破解的密码长度为:768位。
rsa加密工具的使用:
安装:npm i jsencrypt
在utils工具文件夹下创建jsencrypt.js文件
jsencrypt.js文件中写入:
这里是生成公钥 - 加密
function enjsencrypt(str) {
var jsObj = new jsencrypt()
var pubkey = ""
jsObj.setPublicKey(pubkey)
return jsObj.encrypt(str)
}
这里是生成私钥 - 解密
function denjsencrypt(str) {
var jsObj = new jsencrypt()
var prikey = ""
jsObj.setPublicKey(prikey)
return jsObj.dencrypt(str)
}
详解博客地址
keep-alive 组件缓存,刷新的时候保持状态。
keep-alive 缓存组件,避免组件内的数据重复渲染,直接可以在页面中调用。
注意看描述:我有一个导航栏,一级导航栏新闻、房产两个。二级导航栏,新闻下有体育、财经。我给整个一级导航栏新闻做了组件缓存。如:
。
问题:我先点击新闻,然后点击体育,我再点击房产。当我点击新闻的时候,我希望它能回到上一次的状态体育。但是它不会。直接停留到新闻页面了。
需求:点击新闻–》点击体育–》点击社会–》回到新闻下的体育页面
解决:
当点击新闻的时候,有两个方法会触发:activated 和 deactivated
在新闻组件中写:
let url;
beforeRouteLeave() {
url = this.$route.path
}
activated() {
this.$router.push(url)
}
胡哥当前视频地址
vuex存放数据的状态
需要安装:npm i vuex
state 公共数据 组件中this.$store.state.变量名
mutations 同步方法 更新state中的数据
actions 异步方法,组件通过this.$store.dispatch
(‘方法名’, 参数)
getters 读取state中的数据
commit 状态提交,对mutation进行提交
vuex页面刷新,数据会重置。这里涉及到持久化的问题
解决:
把vuex中的数据放到localStorage中
插件vuex-persistedstate 这个插件需要安装,然后在vuex中添加配置。
plugins: [createPersistedState({
storage: window.sessionStorage
})]
persistedstate 本质是使用了localStorage
返回顶部:到达一定距离才会出现。
监听浏览器的滚动时间,返回当前滚动条与顶部的距离。
<div>里面的内容足够多,让其有滚动条出现div>
<script>
function showTop() {
// 兼容获取滚动条位置
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop
console.log('滚动条位置', scrollTop)
}
window.onscroll = showTop
<script>
问题:滚动条滚动时,方法触发太频繁
防抖
第一次触发事件,不要立即执行,给出一个事件间隔,比如200ms
<= 200ms 大于等于200毫秒,没有触发,那就执行函数
<= 200ms 大于等于200毫秒,再次触发滚动,当前的计时取消,重新计时
思路:如果短时间内,大量执行事件,那就执行一次
实现:setTimeout + 闭包
<div>里面的内容足够多,让其有滚动条出现div>
<script>
function showTop() {
// 兼容获取滚动条位置
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop
console.log('滚动条位置', scrollTop)
}
function debounce(fnName, delay) { // 实现间隔调用showTop
let timer = null
return function() {
// 1000毫秒以内,这个timer存在了,那么就清除timer
if(timer) {
clearTimeout(timer)
}
// 1000毫秒以内,这个timer不存在。setTimeout 返回的是一个ID号,从1开始
timer = setTimeout(fnName, delay) // setTimeout(showTop, 1000)
}
}
window.onscroll = debounce(showTop, 1000)
script>
节流
个人感觉这里用节流会更好(沛华的代码)
原理:在一定时间内只执行一次,降低触发频率
实现:闭包
<div>里面的内容足够多,让其有滚动条出现</div>
<script>
function showTop() {
// 兼容获取滚动条位置
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop
console.log('滚动条位置', scrollTop)
}
function throttle(fnName, delay) { // 实现间隔调用showTop
let lastTime = 0
return function() {
// 获取当前时间
let nowTime = Date.now()
// 如果当前时间 - 上一次的时间 < 传进来的时间
// 如:100 - 0 < 1000 吗?如果小于1000,那就直接return了
if(nowTime - lastTime < time) {
return
}
// 大于传进来的时间就会执行下面的代码
fnName.call(this)
lastTime = nowTime
}
}
window.onscroll = throttle(showTop, 1000)
<script>
定义:
从入口文件开始出发,根据入口文件的依赖关系找到所有的模块
调用各种loader进行处理,如果遇到处理不了的调用babel进行语法转换。(babel-loader core preset)
如果一些功能性的,如压缩等这个时候就要调用plugins中相应的插件来进行处理
编辑阶段 —》根据出口的路径,打包多个chunk,如果把css和html等都摘出去了,那么就会打包多个chunk,最后统一生成一个bundle
loader plugin babel 的区别
babel
是一个独立的工具,可以不在webpack中使用。工程化:
狭义上的理解: 将开发阶段的代码发布到生产环境,包含:构建,分支管理,自动化测试,部署
广义上理解: 前端工程化应该包含从编码开始到发布,运行和维护阶段
什么是 webpack(熊键)
五大“护法”(熊键)
理解 Loader
loader常处理的文件类型(天禹)
常用的 loader 有(熊键):
标签的形式插入到 html 文件中。问题:
eslint-loader 配置:“0” “1” "2"代表什么?
.eslintrc.*
eslintConfig
.eslintrc.js
plugin常用插件
【extract-text-webpack-plugin】:用于提取项目中的css, 最终合并为一个单独的文件。
备注:上述插件需要配合:css-loader、less-loader两个loader使用,css-loader、less-loader处理之后,交给extract-text-webpack-plugin处理。
【html-webpack-plugin】:自动创建html文件,且自动引入外部资源。配置项如下:
title:"webpack",
filename:"index.html",
template:"./src/index.html"
//用于压缩html
minify: {
removeComments: true, //移除注释
collapseWhitespace: true
} //移除换行
【clean-webpack-plugin】:清空webpack的输出目录,防止其他文件“乱入”。
【MiniCssExtractPlugin 】:用于提取css为单独文件
如:let arr = [1, [2], [3], [4]]
多维数组转成一维数组,递归:逐层遍历数组,数组的每个元素取出,拼接成新数组
// 数组扁平化
let arr = [1, [2, [3, [4]]]]
// 方法一:使用es6的flat()
// console.log(arr.flat(Infinity))
// 方法二:使用递归
function flat(arr) {
let result = []
// 判断是否传进来是数组
if (!Array.isArray(arr)) {
// 不是数组,就把数据压入result中
result.push(arr)
} else {
for (let i = 0; i < arr.length; i++) {
// console.log(arr[i])
// 第一次进来这样写:result = result.concat(arr[0])
// 第二次进来,又是一个数组,那又得调用flat(),重新从上往下执行函数:result = result.concat(arr[1])
result = result.concat(flat(arr[i]))
}
}
return result
}
console.log(flat(arr))
视频链接
// setTimeout(fun, 时间)
setTimeout(() => {
console.log(11)
}, 0)
console.log(22)
分析:
事件轮询中有个重要模块:郎金杰
setTimeout(fun, 1000) 间隔1000毫秒执行
代码的执行:
同步代码执行时间:会先等待同步代码执行完成,开始执行异步代码。
异步代码执行时间:在执行异步代码的时候,会有等待的时间,因为要等前面队列中的代码都执行完成之后,才会执行这个setTimeout中的回调。
响应时间:比如你在美国访问了京东setTimeout的倒计时,那么美国看到的京东倒计时一定有问题,响应过去都得3秒至少,setTimeout没法1秒就执行。
在现实中setTimeout在执行的时候:等待时间 + 执行时间 + 响应时间。所以在现实中执行基本是大于1000毫秒的。
统计误差时间:
/*
获取时间戳的四种方式
let start = new Date().valueOf()
let start = new Date().getTime()
let start = Date.now()
let start = +new Date()
*/
setInterval(() => {
let n = 0
while (n++ <= 1000000) {}
}, 1000)
// 统计误差
// 开始时间
let start = new Date().getTime()
// 程序执行的秒数
let count = 0
// 间隔时间
let inits = 1000
let timer = setTimeout(fun, inits)
function fun() {
count++
// 误差时间 = 现在的时间 - (开始时间 + count * 1000)
// 如果 误差时间 = 计算出来的时间,那就没有误差。
let errorTime = new Date().getTime() - (start + count * 1000) + 'ms'
console.log(errorTime)
// 解决思路:误差时间累加(当误差达到1000ms之后,不要count++,而是+2)。
}
面向对象(Object Oriented Programming, OOP),是一种编程思想
创建对象:
function 函数名(){} ==》new 函数名 ==》得到对象(类的实例对象)
字面量 {}
new Object()
面型对象的三大特征:
封装:将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
继承:子类可以继承父类的属性和方法
多态:同一个方法,在子类和父类中都可以定义,只是内容不同。
由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
OOP的优势:
**遍历对象:**for … in
对象转化成字符串:
{} ==> string 使用 JSON.stringify()
string ==> {} 使用 JSON.parse()
继承:
构造函数继承(属性继承)
/*
属性继承:在子类调用父类函数,用call改变this指向
*/
function Father(uname, age){
this.uname = uname;
this.age = age;
console.log('Father-this',this);
}
// var o = new Father('张三丰', 22); // 这里的this是Father
// console.log('o', o);
// 继承
function Son(uname, age, score){
// Father(uname, age);这样写的this指向不同,此时Father里面的this指向的是window
// Father(uname, age);
// 如果调用Father函数,并且能够把Father里面的this指向儿子的实例对象,此时Father中的this指向的是Son
Father.call(this, uname, age);
this.score = score;
}
var obj = new Son('erzi', 19, 66);
console.log('obj', obj);
原型链继承(方法继承)
/*
原型链:Son.prototype -> Father.prototype -> Object.prorotype -> null
ES6中的extends关键字实现继承,底层仍然用的是原型
*/
// 方法继承 -- 就是原型继承
function Father() {
Father.prototype.say = function () {
console.log('say方法');
}
}
// 继承
function Son() { }
Son.prototype = new Father();
Son.prototype.eat = function () {
console.log('吃饭');
}
// 如果继承下来父类的方法,那么要把父类实例对象赋值给子类的原型对象,指回构造函数本身
Son.prototype.constructor = Son;
console.log(Son.prototype);
console.log(Father.prototype);
var obj = new Son();
obj.say();
obj.eat();
组合继承
/*
1. 原型继承:继承属性和方法,属性值会重复
2. 借用构造函数继承:继承属性,解决属性值重复的问题,但是父类的方法不会被继承
3. 组合继承:原型继承 + 借用构造函数继承
*/
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
};
Person.prototype.sayHi = function () {
console.log('啊捏哈赛有');
};
function Student(name, age, sex, score) {
// 借用构造函数
Person.call(this, name, age, sex);
this.score = score;
};
// 改变原型指向 --- 实现继承
Student.prototype = new Person(); // 不传值
Student.prototype.eat = function () {
console.log('吃东西');
};
// 如果继承下来父类的方法,那么要把父类实例对象赋值给子类的原型对象,指回构造函数本身
Student.prototype.constructor = Student;
var stu = new Student('小黑', 20, '男', 100);
console.log(stu.name, stu.age, stu.sex, stu.score);
stu.sayHi();
stu.eat();
var stu2 = new Student('小黑2', 20, '女', 1010);
console.log(stu2.name, stu2.age, stu2.sex, stu2.score);
stu.sayHi();
stu.eat();
// 这样就做到了属性和方法都被继承了
设计模式:
沿用了java中的设计模式,一共有23种。
用class作为类名称。主要是js向后台语言靠近。
static 定义静态属性
constructor 构造函数
super 父类构造函数,super必须写在子类的属性前面
extends 继承关键字
定义:指一个函数的参数是函数或者返回值是函数,满足其中一种情况就算是高阶函数。
funA可以接受funB为参数,那么funA就是一个高阶函数。
// add() 就是一个高阶函数
function add(x, y, fun) {
return fun(x) + fun(y)
}
function fun(x) {
return Math.abs(x)
}
console.log(add(-2, 3, fun))
常见的高阶函数:map, reduce, filter, sort
还有一个函数柯里化的问题:
定义:柯里化是把接收多个参数的函数转换成多个只接收一个参数的函数。
作用:参数复用
function add(a, b) {
return a + b;
}
add(1, 2) // 3 普通做法 一次传入两个参数
// 假设有一个 curring 函数可以做到柯里化
function curring(){}
curring(1)(2) // 我们通过这样的方式来接受参数,这样就实现了柯里化
function curring(x) {
return y => x + y // 返回一个函数,然后函数的x+y作为最终的返回值
}
curring(1)(2) // => 3
参数复用:
// 我们平时的写法 --- 非参数复用的写法
function myInfo(inf, name, age) {
return `${inf}:${name}${age}`
}
const myInfo1 = myInfo('个人信息', 'ljc', '19')
console.log(myInfo1); // 个人信息:ljc19
// 函数柯里化的写法 --- 参数复用的写法 复用了inf
function myInfoCurry(inf) {
return (name, age) => {
return `${inf}:${name}${age}`
}
}
let myInfoName = myInfoCurry('个人信息')
const myInfo1 = myInfoName('ljc', '19')
const myInfo2 = myInfoName('ljcc','19')
console.log(myInfo2); // 个人信息:ljcc119
console.log(myInfo1); // 个人信息:ljc19
博客地址
v8引擎对内存有限制:
nodejs中对v8引擎的内存限制
拿官方的一个案例为例,官方是以1.5G内存来进行参考的,1.5G如果要进行垃圾回收,大概是时间是50ms。
如果node要进行一些大内存对象的操作,可以使用buffer来缓冲对象的内存。因为buffer不受限制,因为buffer基于的逻辑是c++的,c++的内存是不受v8引擎限制的。
v8 如何来划分内存和垃圾回收的?
分代回收机制,新生代和老生代
新生代 | 老生代 | |
---|---|---|
32位 | 内存大小限制是16M | 内存大小限制是700M |
64位 | 内存大小限制是32M | 内存大小限制是1.4G |
适合 | 周期短的对象(如:操作某个DOM对象)。一般短期对象较多,占用80%以上 | 周期长的对象(如:new Vue() , document, window等,它就一直存在) |
垃圾回收 | 采用了Scavenge算法进行操作的。在算法实现时主要采用Cheney算法。Scavenge的缺点:可用内存只有一半,另一半永远是等待的。Scavenge的优点:只保留活跃的对象,不活跃的就消灭了。就是部分清空。 | 先用Mark-Sweep(标记清除,就是现在不清楚,等下一次进行扫描的时候发现还在,就会被清除掉,内容清除掉后,会留下一个空间),后用Mark-Compact(标记整理,就是把标记清楚后的空间合并起来。) |
cssom: Css Object Model 采用css代码,并将每个选择器呈现为树状结构,是对css样式表的对象化表示。同时还提供了api来操作css。
w3c标准中:
cssom 包括两个部分
下面是熊键的笔记
第一次握手:客户端发起,我将要发送请求了,你准备一下
第二次握手:服务端发起,我知道了,准备好了,放马过来
第三次握手:客户端发起,我也知道了,等着
为什么要三次握手?
客户端发送请求给服务器
请求报文
服务端返回响应给客户端
响应报文
外部js文件先加载还是window.onload先加载?
外部js文件与body的位置有关
如果js是放在body里,是按照body的先后顺序进行加载的。
如果js在body外(一般指head中),是在body加载完毕后,才加载js。
外部js文件不论是在head中还是在body中,都要优先于window.onload = function(){}
执行。如果外部js有定时器等异步代码,就会滞后执行。
vue-loader的用法:用来解析和转换vue文件,提取出其中的script、style、template,把他们交给对应的loader去处理。
vue-loader的特性:
热重载:"热重载"不是当你修改文件的时候简单重新加载页面。启用热重载后,当你修改 .vue
文件时,所有该组件的实例会被替换,并且不需要刷新页面。它甚至保持应用程序和被替换组件的当前状态!当你调整模版或者修改样式时,这极大的提高了开发体验。
使用场景:
node 速度比较快,node是单线程的,不稳定,不适合处理复杂业务。
单线程,产生未处理异常,会捯饬程序奔溃。
问题:
调用了req.params
let http = require('http')
let server = http.creawteServer(function(req, res){
let ok = req.params.ok; // params 是undefined。如果是未定义就会导致程序奔溃
res.writeHead(200,{'content-type': 'text/plain'})
res.end('hello world')
}).listen(8080, '127.0.0.1')
解决方案1:
uncaughtException 来全局捕获Error,捕获之后,可以防止node奔溃
process.on(‘uncaughtException’, function(err){
打印错误
})
解决方案2:加上try-catch
let http = require('http')
let server = http.creawteServer(function(req, res){
// let ok = req.params.ok; // 把这个未定义的代码拿到外面去
try {
handler(req, res)
} catch(e) {
console.log(e)
}
res.writeHead(200,{'content-type': 'text/plain'})
res.end('hello world')
}).listen(8080, '127.0.0.1')
let handler = function(req, res) {
let ok = req.params.ok; // 同样是未定义,会报错
}
http:
http(Hyper Text Transfer Protocol) 超文本传输协议,用于在浏览器和服务器之间传递信息的,http协议以明文的形式传输内容的,数据是不加密的。不适合传输敏感信息。比如:身份证、账号、密码等。
https:
https:(Hyper Text Transfer Protocol over Secure Socket Layer) 即基于SSL的HTTP协议,简单地说就是HTTP的安全版。https是在http的基础上加上了SSL协议。SSL是依靠证书来验证服务器的身份的,它对浏览器和服务器之间通信是加密的。
https协议是由SSL+ http构成的,是可加密的,身份认证的网络安全,比http更安全。
区别:
定义:
XSS攻击又叫CSS(Cross Site Script)跨站脚本攻击。恶意攻击者往web页面中插入html代码,用户请求该页面,嵌入其中的该代码将会被执行,从而达到攻击用户的目的。
一般有三种攻击类型:
解决:
博客地址
CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。
解决:
为了防止CSRF攻击,Token要求不能重复,需要含有时间戳信息、签名信息。
如:token = base64(msg)格式化…base64(sha256(“密锁”, msg))
token产生:
博客地址
条件Hack:用来调整页面的兼容性的。css hack 这个兼容性主要是针对IE来说的,因为IE一开始没有遵循W3C的标准。
// 条件Hack的写法
// if条件共包含6种选择方式:是否、大于、大于或等于、小于、小于或等于、非指定版本
<!--[if <keywords>? IE <version>?]>
HTML代码块
<![endif]-->
兼容性:浏览器品牌不同,在解释css的时候,解释方式不一样,所以样式不兼容的问题。
注意:尽可能减少对CSS Hack的使用。Hack有风险,使用需谨慎
博客地址
请求资源类型不同
作用结果不同
浏览器解析方式不同
function quickSort(arr) {
if (arr.length < 1) {
return arr
}
// 基准值(得到一个整数) --- 使用Math.floor是为了处理除不尽的情况
let provotIndex = Math.floor(arr.length / 2)
// 求得基准值对应的元素 --- 从基准下标开始截取,截取一个
var provot = arr.splice(provotIndex, 1)[0]
// 遍历数组和基准数进行对比
let left = []
let right = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] < provot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
// console.log(left, right)
return quickSort(left).concat([provot], quickSort(right))
}
let arr = [2, 3, 4, 5, 3, 2, 1, 5]
const result = quickSort(arr)
console.log(result)
同时给兄弟/父子设置上下边距,理论上是两者之和,实际上只有一半,这种现象叫作边界塌陷。
如:给box1的margin-bottom: 20px,给box2的margin-top: 20px; 理论上应该是40的边距,实际上只有20px的边距。
<head>
<style>
.box1 {
width: 100px;
height: 100px;
border: 1px solid red;
margin-bottom: 20px;
}
.box2 {
width: 100px;
height: 100px;
border: 1px solid green;
margin-top: 20px;
}
style>
head>
<body>
<div class="box1">div>
<div class="box2">div>
body>
注意:
浮动元素和定位元素是不会发生边界塌陷的。
这种现象一般发生在块级元素的垂直方向。
解决方案:
margin 同为正数或者同为负数的时候,取的是绝对值大的数。
如果一正一负的时候,求的是和,如给box1的margin-bottom: 20px,给box2的margin-top: -20px; 那么最终边界值为0。
2022年8月24日10: 17: 30