基本功考察
1.关于Html
1、html语义化标签的理解、结构化的理解;能否写出简洁的html结构;SEO优化。
2、h5中新增的属性,如自定义属性data、类名className等;新增表单元素;拖拽Drag。
3、h5中新增的API、修改的API、废弃的API稍作了解(离线存储、audio、video)。
2.关于CSS
1、CSS选择器(三大特性)。
2、BFC机制。
3、盒模型。
4、CSS模块化开发(封装);SCSS和LESS的使用。
5、屏幕适配以及页面自适应。
6、CSS3中新增的选择器。
7、CSS3中新增的属性,transform、trasition、animation等。
3.关于布局
1、标准文档流(padding + margin + 负margin)+ 浮动float + 定位 left + right + top + bottom。
2、百分比布局:px单位用%num代替,占父级元素的百分比。
3、flex弹性布局:主轴、辅助轴的几个属性。
4、grid栅格布局:使用框架中的类名来替代,本质上还是百分比布局。
4.关于JS基础
1、变量数据类型及检测:基本 + 引用。
2、运算符:算术 + 条件 + 逻辑 + 位 + 短路、隐式转换等。
3、条件、循环、异常处理if、switch(){case xxx:}、try、catch、finally、throw。
4、函数定义、调用方式(apply、call、直接调用);传参:实参给形参赋值。
5、字符串、数组、对象常用API。
6、正则表达式。
5.关于JS高级
1、作用域、作用域链、闭包。
2、原型、原型链、继承。
3、函数上下文、this指向。
4、js的运行机制、事件队列和循环。
5、Ajax原理、axios库。
6、同步、异步编程。
7、jQuery源码学习。
6.关于浏览器
1、浏览器的构成和运行机制。
2、浏览器内核。
3、浏览器交互:BOM和DOM相关webApi、监听事件。
4、浏览器缓存机制。
5、浏览器的渲染原理。
6、浏览器的安全性:跨域和攻击。
7.关于网络协议
1、HTTP协议。
2、cookie、session、token。
8.关于ES6语法
1、字符串、数组、对象扩展的api。
2、变量扩展:let、const解构赋值,块级作用域。
3、函数扩展:箭头函数默认参数、rest参数。
4、展开运算符、模板字符串。
5、set和map数据结构。
6、迭代器和生成器函数next和yield的理解。
7、proxy对象属性代理器:属性的读取(get)和设置(set)相关操作。
8、promise对象、异步编程的解决方案。
9、async + await:异步编程的终极方案promise + generator的语法糖。
10、class语法、构造函数的语法糖。
11、模块化编程export + import的导出和导入。
9.VUE基础
1、基本指令。
2、实例的属性和方法。
3、实例的生命周期。
4、组件基础:创建、注册、添加属性方法、套用等。
5、组件通信传值,父子、兄弟、跨级。
6、插槽slot等。
10.VUE高级
1、vue-router:搭建SPA
路由、组件的配置。
路由间的传值。
路由跳转。
路由的导航守卫。
记住在router.js和组件页面中的使用方式。
2、vuex:状态管理、数据仓库store
实例化仓库的5大属性的使用。
state、getters、mutations、actions、modules。
辅助函数mapState等,仓库中计算属性的映射、方便操作。
记住在store.js和组件中使用方式。
11.VUE深入、源码阅读
1、数据响应式原理。
2、virtual dom。
3、diff 算法。
4、nextTick等等。
-----------------分割线--------------------
工程能力考察
1.项目能力
1、vue-cli脚手架搭建和功能配置vue.config.js。
2、webpack的常用配置。
3、项目构建打包。
4、熟悉各类框架的文档。
5、UI框架:Bootstrap、MUI、Element-ui等。
6、常用的插件整理;整理一个自己插件库,封装自己的方法库、组件库。
7、常用的工具熟练度。
8、PC端和移动端开发注意事项。
9、经验总结:快速确定项目的技术选型。
10、坑点总结:项目遇到坑坑坑!
11、项目中的性能优化记录(都是细节点,多记录)。
12、需求文档的理解,可以结合项目流程图、UML图。
13、问题解决能力:bug定位调试、查找文档、寻求他人。
14、记录习惯养成。
2.模块化、组件化开发能力
1、项目分类;各类文件整理、分类。
2、各类功能封装。
3、组件和功能模块的抽离、解耦、复用。
-----------------分割线--------------------
内功考察
1.面向对象的编程思想
1、类的抽象。
2、对象的封装、继承。
3、为了更好的去管理数据、分类数据,实现高内聚、低耦合。
2.设计模式
设计模式感觉也是将面向对象思想再度抽象成现实中某些特定模式。
3.数据结构和算法
1、学习常用的排序搜索算法、顺序表、链表、栈、队列、树、堆等。
2、考验你的抽象思维和数学功底。
3、将现实需求抽象成计算机代码的思维能力。
-----------------分割线--------------------
附加技能考察
1.学习能力
1、持续学习的态度——博客、笔记记录。
2、技术论坛活跃度高、问答多。
3、GitHub开源项目参与。
2.了解一门后端语言
1、python、node.js、php等。
2、数据库mysql、redis、mongodb;sql的操作语句、mongodb的操作语句、redis的操作语句。
3、node + express搭建本地服务等。
4、python + django + request + scrapy。
3.系统编程
1、Linux命令行操作、系统文件管理。
2、多任务、多线程、多进程、协程、并发、并行、串行、同步、异步等概念的理解。
-----------------分割线--------------------
Vue双向绑定的原理:
利用Object.defineProperty() 劫持各个属性的setter/getter,只要数据有变化,就触发它的监听
<body>
<div id="app">
<input type="text" id="txt">
<p id="show"></p>
</div>
</body>
<script type="text/javascript">
var obj = {}
Object.defineProperty(obj, 'txt', {
get: function () {
return obj
},
set: function (newValue) {
document.getElementById('txt').value = newValue
document.getElementById('show').innerHTML = newValue
}
})
document.addEventListener('keyup', function (e) {
obj.txt = e.target.value
})
</script>
Promise ?
e.g
function test2(resolve,reject){
var timeOut = Math.random() * 2;
console.log('set timeout to:' + timeOut + 'seconds.')
setTimeout(function(){
if(timeOut < 1){
console.log('call resolve()...');
resolve('200 OK');
}else{
console.log('call reject()...');
reject('timeout in' + timeOut + 'seconds.')
}
},timeOut * 1000);
};
test2()
//输出call reject()...,test2()函数只关心自身的逻辑,并不关心具体的resolve()和reject()将如何处理结果
### Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:
![promise.png](https://img.haomeiwen.com/i7785764/bb52aedfae912853.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
地址栏url敲回车,会发生什么事情?
域名解析 -->
发起TCP的3次握手 -->
建立TCP连接后发起http请求 -->
服务器响应http请求,浏览器得到html代码 -->
浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) -->
浏览器对页面进行渲染呈现给用户
更多:https://www.cnblogs.com/wupeixuan/p/8747918.html
跨域问题如何解决
同源策略:只要协议、域名、端口有任何一个不同,都被当作是不同的域
js跨域是指通过js在不同的域之间进行数据传输或通信
···
- 通过jsonp跨域
jsonp在页面上引入不同域上的js脚本文件实现请求不同域上的数据
(1) 通过script标签引入一个js文件
(2) js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入
注:需要服务器端的页面进行相应的配合 - 通过修改document.domain来跨子域
- 使用window.name来进行跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置
···
v-if 和 v-show 的区别?
v-if 在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 <template> ,将提出它的内容作为条件块。
v-show 切换元素的 display CSS 属性。
javascript面向对象(opp)
1、计算机语言分为:面向对象、面向过程、面向机器
2、面向过程:注重解决一个问题的过程 步骤(例如c语言)
面向对象:注重哪个对象解决问题,类实例对象(例如js、java、c++)
3、但js与面向对象java相比,不能够实现函数的重载(因为函数名是指向函数地址的指针,重名会导致改变了函数的指向)
4、面向对象的三大特性:封装、继承、多态
js实现封装:
function Person(name,age){
this.name = name;
var age = age;
}
var p = new Person('韩娜',18)
console.log(p.name,p.age) //韩娜 undefined
使用原型添加函数节省内存,但这种方式不能去访问类的私有变量和方法。
function Person(name,age){
this.name=name;
var age=age;
}
Person.prototype.fun = function(){
console.log(this.name)
console.log(this.age)
}
var p = new Person('韩娜',18)
p.fun()
js实现继承:
(a) 对象冒充【this.子类变量名 = 父类】
function Stu(name, age){
this.name = name;
this.age = age;
this.show = function(){
window.alert(this.name + " " + this.age);
}
}
function MidStu(name, age) {
this.stu = Stu;
// 通过对象冒充来实现继承的
// 对象冒充的意思就是获取那个类的所有成员,因为js是谁调用那个成员就是谁的,这样MidStu就有了Stu的成员了
this.stu(name, age);
this.payFee = function(){
window.alert("缴费" + money * 0.8);
}
}
function Pupil(name, age) {
this.stu = Stu;
// 通过对象冒充来实现继承的
this.stu(name, age);
this.payFee = function(){
window.alert("缴费" + money * 0.5);
}
}
var midStu = new MidStu("zs", 13);
midStu.show();
var pupil = new Pupil("ls", 10);
pupil.show();
(b) 通过call或者apply实现(在子类中调用:【 父类.call( this,参数 ) 】 )
//1. 把子类中共有的属性和方法抽取出,定义一个父类Stu
function Stu(name,age){
// window.alert("确实被调用.");
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+"年龄是="+this.age);
}
}
//2.通过对象冒充来继承父类的属性的方法
function MidStu(name,age){
//这里这样理解: 通过call修改了Stu构造函数的this指向,
//让它指向了调用者本身.
Stu.call(this,name,age);
//如果用apply实现,则可以
//Stu.apply(this,[name,age]); //说明传入的参数是 数组方式
//可以写MidStu自己的方法.
this.pay=function(fee){
window.alert("你的学费是"+fee*0.8);
}
}
function Pupil(name,age){
Stu.call(this,name,age);//当我们创建Pupil对象实例,Stu的构造函数会被执行,当执行后,我们Pupil对象就获取从 Stu封装的属性和方法
//可以写Pupil自己的方法.
this.pay=function(fee){
window.alert("你的学费是"+fee*0.5);
}
}
//测试
var midstu=new MidStu("zs",15);
var pupil=new Pupil("ls",12);
midstu.show();
midstu.pay(100);
pupil.show();
pupil.pay(100);
(c) 原型prototype上添加属性方法实现【 子类.prototype = new 父类() 】
缺点:继承父类的引用类型,实例中有一个修改,会影响其他实例
实例见上述封装的第二个例子
js实现多态:
// Master类
function Master(name){
this.nam=name;
//方法[给动物喂食物]
}
//原型法添加成员函数
Master.prototype.feed=function (animal,food){
window.alert("给"+animal.name+" 喂"+ food.name);
}
function Food(name){
this.name=name;
}
//鱼类
function Fish(name){
this.food=Food;
this.food(name);
}
//骨头
function Bone(name){
this.food=Food;
this.food(name);
}
function Peach(name){
this.food=Food;
this.food(name);
}
//动物类
function Animal(name){
this.name=name;
}
//猫猫
function Cat(name){
this.animal=Animal;
this.animal(name);
}
//狗狗
function Dog(name){
this.animal=Animal;
this.animal(name);
}
//猴子
function Monkey(name){
this.animal=Animal;
this.animal(name);
}
var cat=new Cat("猫");
var fish=new Fish("鱼");
var dog=new Dog("狗");
var bone=new Bone("骨头");
var monkey=new Monkey("猴");
var peach=new Peach("桃");
//创建一个主人
var master=new Master("zs");
master.feed(dog,bone);
master.feed(cat,fish);
master.feed(monkey,peach);
ES6内容:
let/const/箭头函数/迭代器(解构、剩余|扩展运算符、生成器、for of循环)/数据结构(Map/Set)
1、iterator迭代器:
普通对象默认是没有iterator接口的(可以自己创建iterator接口让普通对象也可以迭代),默认具有iterator接口的数据结构有以下几个:
Array、 Map、 Set、 String、 TypedArray(类数组)、 函数的 arguments 对象、 NodeList 对象
2、剩余|扩展运算符:(...)
a)扩展
//demo 1 传递数据代替多个字符串的形式
function test(a,b,c){
console.log(a);
console.log(b);
console.log(c);
}
var arr = [1, 2, 3];
test(...arr);
//demo2 将一个数组插入到另一个数据中
var arr1 = [1, 2, 3,4];
var arr2 = [...arr1, 4, 5, 6];
console.log(arr2);
//demo3 字符串转数据
var str='loycoder';
var arr3= [...str];
console.log(arr3);
b)剩余
//demo4 当函数参数个数不确定时,用 rest运算符
function rest01(...arr) {
for (let item of arr) {
console.log(item);
}
}
rest01(1, 3, 5);
//demo5 当函数参数个数不确定时的第二种情况
function rest02(item, ...arr) {
console.log(item);
console.log(arr);
}
rest02(1, 2, 34);
//demo6 rest运算符配合 解构使用:
var [a,...temp]=[1, 2, 4];
console.log(a);
console.log(temp);
3、生成器:
4、for of循环:
数组怎么去重?ES6有专门数组去重的api,你了解过吗?
方法1:
var arr = [5,6,8,8,6,8,6];
var set = new Set(arr);
console.log(Array.from(set))
//Set()它类似于数组(伪数组),但是成员的值都是唯一的,没有重复的值。
//Array.from()将一个类数组对象或者可遍历对象转换成一个真正的数组。可用于字符串转成数组Array.from('foo');// ['f','f','o']
//Array.from() 方法从一个类似数组或可迭代的对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等) 中创建一个新的数组实例
// IE不支持
// https://www.imooc.com/article/262703
方法2:
function unique(arr) {
//定义常量 res,值为一个Map对象实例
const res = new Map();
//返回arr数组过滤后的结果,结果为一个数组
//过滤条件是,如果res中没有某个键,就设置这个键的值为1
return arr.filter((a) => !res.has(a) && res.set(a, 1))
}
方法3:
arr.filter(function (element, index, self) {
return self.indexOf(element) === index;
});
方法4:(算法)
function unique(arr){
var temp = [];
var len = arr.length;
for(var i = 0; i < len; i++){
if(temp.indexOf(arr[i]) === -1) temp.push(arr[i]);
}
return temp;
}
居中问题:
https://mp.weixin.qq.com/s/UxY7VWqMMOjvgE6L_dlixA
inline 和block的区别?
块级元素:会占领页面的一行,其后多个block元素自动换行、 可以设置width,height,设置了width后同样也占领一行、同样也可以设置 margin与padding属性。
行级元素:与其他元素在同一行上,高度,行高以及底边距不可改变,高度就是内容文字或者图片的宽度,不可以改变。
position了解过么?一般都怎么用?
relative: 相对于本身位置进行偏移
absolute:
fixed
static
浏览器兼容监听事件?
var x = document.getElementById("myBtn");
if (x.addEventListener)
{
x.addEventListener("click", myFunction);
} else if (x.attachEvent)
{
x.attachEvent("onclick", myFunction);
}
什么是webSocket?
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
允许服务端主动向客户端推送数据
绝对定位和相对定位?
你知道什么是跨域问题吗?怎么解决?
link 与 @import 的区别?
1、作用上:@import 引入样式表
link 加载css文件,定义RSS、rel连接等属性
2、加载顺序:@import 引入的 CSS 将在页面加载完毕后被加载
link 加载页面时被同时加载
3、可控性:@import 引入的样式不可以用js操控
link 引入的样式可以用js操控
4、兼容性:@import 只可在 IE5+ 才能识别;
link标签作为 HTML 元素,不存在兼容性问题
防抖与节流?
1、防抖:多次触发事件之后,事件执行函数只执行一次,并且是在触发操作结束时执行的
原理:对执行函数进行延时操作。如果设定的延时到来之前,再次触发事件,则清楚上一次延时的定时器,重新开始定时。
不使用:图片懒加载(lazyload)时,需要通过滚动位置,实时显示图片时,如果使用防抖函数,懒加载(lazyload)函数将会不断被延时,
e.g.: 以 onscroll 方法为例
window.onscroll = function(){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动位置:' + scrollTop);
}
防抖操作:(解决上面的eg)
let timer;
window.onscroll = function(){
// let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
// console.log('滚动位置:' + scrollTop);
// 滚动的防抖操作
if (timer) {
clearTimeout(timer)
}
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
timer = setTimeout(function(){
console.log('滚动位置:'+ scrollTop);
timer = undefined;
},200)
}
防抖函数的封装:
function debounce(fn,wait){
let timeout = 0;
return function(...args){
if(timeout){
clearTimeout(timeout)
}
timeout = setTImeout(() => {
fn.apply(this,args)
},wait)
}
}
引用封装的防抖函数:
window.onscroll = debounce(function(){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log("滚动条位置:"+ scrollTop)
//返回顶部等操作
})
2、节流:触发执行函数后,短时间间隔不能连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
let startTime = Date.now();
let time = 5000; //间隔时间,控制隔多长时间执行一次函数
let timer;
window.onscroll = function throttle(){
let currentTime = Date.now();
if(currentTime - startTime >= time){
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
console.log("滚动条位置:"+ scrollTop)
startTime = currentTime;
}else{
clearTimeout(timer);
timer = setTimeout(function(){
throttle();
},100)
}
}
JS优化?
1、事件委托,父类代替多个子类执行事件,只执行一次
2、函数防抖,节省Dom操作,防抖函数的封装使用
HTMl优化?
1* 、HTML标签有始终。 减少浏览器的判断时间
2* 、把script标签移到HTML文件末尾,因为JS会阻塞后面的页面的显示。
3* 、减少iframe的使用,因为iframe会增加一条http请求,阻止页面加载,即使内容为空,加载也需要时间
4、id和class,在能看明白的基础上,简化命名,在含有关键字的连接词中连接符号用'-',不要用'_'
5、保持统一大小写,统一大小写有利于浏览器缓存,虽然浏览器不区分大小写,但是w3c标准为小写
6、清除空格,虽然空格有助于我们查看代码,但是每个空格相当于一个字符,空格越多,页面体积越大,像google、baidu等搜索引擎的首页去掉了所有可以去掉的空格、回车等字符,这样可以加快web页面的传输。可以借助于DW软件进行批量删除 html内标签之间空格,sublime text中ctrl+a,然后长按shift+tab全部左对齐,清除行开头的空格
7* 、减少不必要的嵌套,尽量扁平化,因为当浏览器编译器遇到一个标签时就开始寻找它的结束标签,直到它匹配上才能显示它的内容,所以当嵌套很多时打开页面就会特别慢。
8、减少注释,因为过多注释不光占用空间,如果里面有大量关键词会影响搜索引擎的搜索
9** 、使用css+div代替table布局,去掉格式化控制标签如:strong,b,i等,使用css控制
10*、代码要结构化、语义化
11* 、css和javascript尽量全部分离到单独的文件中
12* 、除去无用的标签和空标签,空格,注释
13、尽量少使用废弃的标签,如b、i等,尽管高版本浏览器是向后兼容的
操作字符串和数组的常用的方法?
js里面的this的指向?
本地存储和webSocket了解过吗?
js创建对象有几种方式?
冒泡和捕获机制是什么?
// 冒泡
getEle("imgId").addEventListener('click',function(){
alert('你点击了内部')
},false)
getEle("mDiv").addEventListener('click',function(){
alert('你点击了外部')
},false)
// 捕获
getEle('imgId').addEventListener('click',function(){
alert('我是内部')
},true)
getEle('mDiv').addEventListener('click',function(){
alert('我是外部')
},true)
vue的侦听器?
method和计算属性的区别?什么时候用计算属性?
事件的修饰符你知道几个?比如click.stop是什么?
在一个页面,你知道为什么通常把css写在上面,把js脚本写在下面吗?
一个click事件,经历了哪几个过程
a:link是超级链接的初始状态
a:hover是把鼠标放上去时悬停的状况
a:active 是鼠标点击时
a:visited是访问过后的情况
-
onmousedown/onmousemove/onmouseup
onmouseout/onmouseover
我们经常遇到,比如在知乎复制一段文字,就会附着一些作者的信息之类的,如果是你,你怎么实现?你知道怎么操作剪贴板吗?
var和let的区别?
用过脚手架吗?
生命周期?
SASS与LASS包括什么?
结构化CSS
变量
嵌套样式表
Minxins & 函数
继承
js 异步加载的方式
渲染引擎遇到 script 标签会停下来,等到执行完脚本,继续向下渲染
defer 是“渲染完再执行”,async 是“下载完就执行”,defer 如果有多个脚本,会按照在页面中出现的顺序加载,多个async 脚本不能保证加载顺序
加载 es6模块的时候设置 type=module,异步加载不会造成阻塞浏览器,页面渲染完再执行,可以同时加上async属性,异步执行脚本(利用顶层的this等于undefined这个语法点,可以侦测当前代码是否在 ES6 模块之中)
JS如何实现类,继承?
JS有哪些数据类型?
Null和Undefined的区别?
判断时if是false的值?
isNaN()的作用?
JS对象中的Array对象和String对象的各种方法
this关键字在不同环境下的指向JS的作用域
setTimeout和setInterval
了解CSS3或HTML5吗,都用过哪些
排序!!
1、盒装模型,以及在不同标准下的表现。(问到什么程度?比如最近会问何时margin会重叠)
2、基本CSS的知识自行了解清楚(优先级、选择器、伪类、浮动元素、HACK等)
3、原型与实现继承(特别重要!!我手下面80%应届生不熟悉原型,也许学校没实际应用过,但是不知道原型基本可以枪毙了)
原型: https://www.jianshu.com/writer#/notebooks/16238368/notes/30930178/preview
闭包: https://www.jianshu.com/writer#/notebooks/16238368/notes/41663536
4、作用域、声明提前(特别喜欢拿这个做文章,分开出三道,第一道不会教你,剩下两道埋坑考察当场学习能力)
5、基本插件如JQ等的使用和部分代码分析或实现
6、原生JS的使用(创建、插入DOM,不同浏览器事件)
7、跨域实现
8、如何改善页面性能
9、事件代理
11、正则
12、布局,浮动布局,自适应布局,自适应左右分栏的实现(纯CSS)
1、AMD CMD 模块化JS
2、同步、异步、回调、promise实现
3、各种算法、数组去重等
4、前端开发框架、编译、打包(选择一家方案使用了解)
5、CSS3、HTML5常用方法
HTML新的api
history.pushState 和 history.replaceState,就是通过这个接口做到无刷新改变页面URL的
this、call、apply、callee 孰知应用
1)this
function a(){
console.log(this)
}
a(); //window
var name = 'window-name';
var obj = {
name: 'obj-name',
a:function(){
console.log(this.name);
},
b:{
name: 'b-name',
a:function(){
console.log(this.name);
}
}
}
obj.a(); //obj-name
obj.b.a(); //b-name
var winA = obj.b.a;
winA(); //window-name
2)call()
函数.call(对象) ---> 函数中的this指的是对象
函数1.call(函数2) ---> 函数1执行
function foo(){
console.log(this.x)
}
var fooObj = {x:1}
foo(); //undefined
foo.call(fooObj); //1
var a = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
var b = a.fn;
b(); //undefined
b.call(a); //‘追梦子’
function fun1(){
console.log(1)
}
function fun2(){
console.log(2)
}
fun1.call(fun2)//1
fun2.call(fun1)//2
带参数的:第一个参数是对象,后面的都是参数
function fooParams(a,b,c){
console.log(this.x + a + b + c)
}
var fooParamsObj = {x:1}
fooParams.call(fooParamsObj,2,3,4)
var obj1 = {
num : 20,
fn : function(n){
console.log(this.num+n);
}
};
var obj2 = {
num : 15,
fn : function(n){
console.log(this.num-n);
}
};
obj1.fn.call(obj2,10);//25
3)apply()
function foo1(){
console.log(this.x)
}
var foo1Obj = {x:1}
foo1() //undefined
foo1.apply(foo1Obj) //1
带参数的: 第一个参数是对象,第二个参数是数组,数组里全是参数
function fooParams1(a,b,c){
console.log(this.x + a + b + c)
}
var fooParamsObj1 = {x:1}
fooParams1.apply(fooParamsObj1,[2,3,4])
4)call()和apply()的区别:参数
- call()在第一个参数之后的 后续所有参数就是传入该函数的值。
- apply() 只有两个参数,第一个是对象,第二个是数组,这个数组就是该函数的参数。
- call和apply两个特殊情况就是:当这个obj参数为null或者undefined的时候,this会指向window。
- bind() 参数与call()相同
5)bind()
function bindFoo(){
console.log(this.x)
}
var bindFooObj = {x:1}
bindFoo.bind(bindFooObj) //没有打印,因为bind不会自动调用
var newBindFoo = bindFoo.bind(bindFooObj)
console.log(newBindFoo) //打印出函数bindFoo
newBindFoo() //结果是 1 因为手动执行了函数,this指向还是bindFooObj。
var a = {
user: 'hanna',
fn: function(){
console.log(this.user);
}
}
var b = a.fn;
b(); //undefined
b.bind(a); //不执行
b.bind(a)() //hanna
6)总结
- call和apply都是改变上下文中的this并立即执行这个函数。
- bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加
遍历
for...in(支持对象、数组)
var arr = [1,2,3,4,5,6]
for(let i in arr){
console.log(i) //索引 0,1,2,3,4,5
console.log(arr[i]) //数组 1,2,3,4,5,6
}
var obj = {a:1,b:2,c:3}
for(let key in obj){
console.log(key) //对象的key a,b,c
console.log(obj[key]) //对象的value 1,2,3
}
Object.keys(obj) //对象的key a,b,c
Object.values(obj) //对象的value 1,2,3
for...of(不支持普通对象)
var newArr = [2,4,6,8,10]
for(let i of newArr){
console.log(i) //数组本身2,4,6,8,10
}
forEach (使用break不能中断循环,使用return也不能返回到外层函数)
重绘与回流及相关性能
##重绘(redraw或repaint):
* 当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。
* 触发重绘的条件:改变元素外观属性。如:color,background-color等。
* 注意:table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是我们尽量避免使用table布局页面的原因之一。
##重排(重构/回流/reflow):
* 当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
* 触发重排的条件:任何页面布局和几何属性的改变都会触发重排,比如:
1、页面渲染初始化;(无法避免)
2、添加或删除可见的DOM元素;
3、元素位置的改变,或者使用动画;
4、元素尺寸的改变——大小,外边距,边框;
5、浏览器窗口尺寸的变化(resize事件发生时);
6、填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变;
7、读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )
##重绘和重排的关系:
重排必定会引发重绘,但重绘不一定会引发重排。
##重绘重排的代价:
耗时,导致浏览器卡慢。
##优化:
1、浏览器自己的优化:浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
2、我们要注意的优化:我们要减少重绘和重排就是要减少对渲染树的操作,则我们可以合并多次的DOM和样式的修改。并减少对style样式的请求。
(1)直接改变元素的className
(2)display:none;先设置元素为display:none;然后进行页面布局等操作;设置完成后将元素设置为display:block;这样的话就只引发两次重绘和重排;
(3)不要经常访问浏览器的flush队列属性;如果一定要访问,可以利用缓存。将访问的值存储起来,接下来使用就不会再引发回流;
(4)使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
(5)将需要多次重排的元素,position属性设为absolute或fixed,元素脱离了文档流,它的变化不会影响到其他元素;
(6)如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document;
(7)尽量不要使用table布局。
代码:
var fragment = document.createDocumentFragment();
var li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);
var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);
document.getElementById('fruit').appendChild(fragment);
7、webkit内核特有的一些API
8、MVC/JS面向对象思想
dom的操作,删除,移动,复制,插入,前插后插,指定插一类。
事件的处理,兼容性写法,参数作用,扑获冒泡,委派代理。
ie下的一些兼容性问题,js的,举例。
动画方面,加速度,重力模拟实现。
正则,基本的用法和相关函数作用考查。
闭包,原型链,作用域,变量引用,类继承方法。
内存泄露的原因和场景。
h5里一些新增api的了解。
性能优化和重构知识。
判断两个对象是否相等:
方法1:JSON.stringfy()
var obj = {a:'a'},
obj1 = {b:'b'},
obj2 = {a:'a'};
console.log(JSON.stringify(obj) == JSON.stringify(obj1)); //false
console.log(JSON.stringify(obj) == JSON.stringify(obj2)); //true
方法2:Object.getOwnPropertyNames()
先比较两个对象的getOwnPropertyNames长度,如果长度相等
var obj = {a:'a'},
obj1 = {b:'b'};
var props = Object.getOwnPropertyNames(obj)
var props1 = Object.getOwnPropertyNames(obj1)
if(props.length != props1.length){
console.log('不相等')
}
for(let i=0;i<props.length;i++){
var propName = props[i];
if( obj[propName] != obj1[propName] ){
console.log('不相等')
}else{
console.log('相等')
}
}
判断是否为数组:
方法1:使用 instanceof()【不能跨页面判断】
var arr = ['hanna','lsb','fff','xxx']
var obj = {'name':'hanna'}
console.log( arr instanceof Array ) //true
console.log( obj instanceof Array ) //false
方法2:使用 constructor【不能跨页面判断】
var arr = ['hanna','lsb','fff','xxx']
var obj = {'name':'hanna'}
console.log( arr.constructor === Array ) //true
console.log( obj.constructor === Array ) //false
方法3:使用 Array.isArray()【兼容问题】
var arr = ['hanna','lsb','fff','xxx']
var obj = {'name':'hanna'}
Array.isArray( arr ) //true
Array.isArray( obj ) //false
方法4:使用 Object.prototype.toString.call()
var arr = ['hanna','lsb','fff','xxx']
var obj = {'name':'hanna'}
Object.prototype.toString.call( arr ) //true
Object.prototype.toString.call( obj ) //false
兼容的封装方法:使用isArray和Object.prototype.toString.call()
function isArrayFun(arr){
if(typeof Array.isArray == 'function'){
return Array.isArray(arr)
}else{
return Object.prototype.toString.call(arr) === '[object Array]'
}
}
附加:
Array.prototype.slice.call() 将具有length属性的对象(key值为数字)转成数组
1、有length属性:
var obj = { 0:'hello',1:'word',length:2 };
console.log(Array.prototype.slice.call(obj,0)) // ['hello','word']
2、没有length属性:
var obj = {0:'hello',1:'world'};//没有length属性
console.log(Array.prototype.slice.call(obj,0));//[]
数组等操作方法:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
https://www.jb51.net/article/83607.htm
数组与字符串互转:
1、数组转字符串
var strArr = ['a','b','c']
console.log(strArr.join('')) //abc
2、字符串转数组
var str = 'abc'
console.log( [...str] )
js引擎注释:// , /* */ ( html的注释也可以 )
else代码块总是与离自己最近的那个if语句配对
case代码块之中没有break语句,导致不会跳出switch结构,而会一直执行下去。
switch语句后面的表达式,与case语句后面的表示式比较运行结果时,采用的是严格相等运算符(===),而不是相等运算符(==),这意味着比较时不会发生类型转换。
for ( ; ; ){
console.log('Hello World');
}
上面代码省略了for语句表达式的三个部分,结果就导致了一个无限循环。
不管条件是否为真,do...while循环至少运行一次,这是这种结构最大的特点。另外,while语句后面的分号注意不要省略。
break 和 continue
var i = 0;
while (i < 100){
I++;
if (i % 2 === 0) continue;
console.log('i 当前为:' + i);
}
上面代码只有在i为奇数时,才会输出i的值。如果i为偶数,则直接进入下一轮循环。
如果存在多重循环,不带参数的break语句和continue语句都只针对最内层循环。
var i = 0;
while(i < 100) {
console.log('i 当前为:' + i);
I++;
if (i === 10) break;
}
上面代码只会执行10次循环,一旦i等于10,就会跳出循环。
for循环也可以使用break语句跳出循环。
六种数据类型,Number/String/Boolean/null/undefined/Object
ES6加了第七种数据类型,Symbol类型
Symbol的目的就是为了实现一个唯一不重复不可变的值,任何一个Symbol都是唯一的,不会和其他任何Symbol相等。
如:我们给一个DOM节点做动画,那么我们需要判断动画是否正在执行。
这个时候一般的做法是给DOM节点加上一个属性(或者classname之类的)做一个标记
d.isMoving = true; //正在执行动画,这样做很容易产生冲突,万一你用了一个三方动画库,人家也是用 isMoving 来进行标记,或者万一DOM规范以后添加了一个 isMoving 接口。
用Symbol解决:var isMoving = Symbol("is moving");
d [ isMoving ] = true;
// 错误的写法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正确的写法
if (typeof v === "undefined") {
// ...
}
双等时,更偏向转化成Number
typeof null ------> "object"
typeof undefined ------> "undefined"
undefined == null ------> true
Number(undefined) ------> NaN
instanceof 运算符可以区分数组和对象
屏幕快照 2018-08-20 上午11.11.32.png
空数组([])和空对象({})对应的布尔值,都是true
空字符串,是false,转为0
Math.pow(x,y) ------> x 的 y 次幂。
element-ui upload使用经验总结:
https://blog.csdn.net/zfangls/article/details/79280418
上传二进制文件时,文件上传,文件名就不能够上传;文件名能上传,文件就不能上传。
解决:使用时间戳作为文件名上传即可.:
----------------------分割线---------------------------
push(),pop()顶部
堆:
栈:后进先出
队列:
charles 如何抓取 https的请求
抓包
状态码
打开URl后,一直到页面渲染出来,经经历的过程:
https://blog.csdn.net/jiao_0509/article/details/82491299
js单线程原理:
@全体成员 js是单线程的,如果要等待输入,会造成页面卡死,所以把哪些需要等待的任务(有回调函数的),放入任务队列, 不需要等待的任务就进入执行栈执行,当执行栈执行完成后,就去任务队列里面找
然后就推入执行栈中执行,js不停的重复上面的动作
数据结构,
https /http 区别,
写排序(数据结构),
post get 请求的深度区别,
https://www.cnblogs.com/mangoWeb/p/3517801.html
面试汇总!!!
http://mp.weixin.qq.com/s?__biz=MzI5ODM4NjQ5Mg==&mid=2247483846&idx=1&sn=cea4309794a3b16a3418630bb5e762e0&chksm=eca7d495dbd05d8332b5ddb9c07a3ce6595c92dabb32a3fd14b36a33900ddcfb2f9376438d6c&mpshare=1&scene=23&srcid=#rd
http://mp.weixin.qq.com/s?__biz=MzUxODI3Mjc5MQ==&mid=2247484104&idx=1&sn=45a03b93f4fdd14751af29055a1fb7b0&chksm=f98a20b0cefda9a6f895a2266e513f90d55add0da79ca13206130c4fd39a2c2b7669d4b692bf&mpshare=1&scene=23&srcid=0227k9tosdc8jAnESbdkmP5n#rd
https://mp.weixin.qq.com/s?__biz=MzIzNTU2ODM4Mw==&mid=2247487807&idx=1&sn=aaed585b91ddf49da34312fe1e718ecd&chksm=e8e47cafdf93f5b9394cff17b26ff7806bd03edbfc41596bf5c93c61a08ace6f4164fc118aff&mpshare=1&scene=23&srcid=%23rd
https://github.com/Advanced-Frontend/Daily-Interview-Question
https://www.cnblogs.com/autismtune/p/5210116.html
提高算法(乐扣):https://leetcode-cn.com/problems/two-sum/solution/
时间:格林威治时间与2018-02-28转换
https://blog.csdn.net/Dream_xun/article/details/83177926
https://blog.csdn.net/venus_j?t=1
重要的::http://www.runoob.com/w3cnote/front-end-interview-a-few-important-points-of-knowledge.html
DOM机制
DOM事件模型:捕获和冒泡
(DOM2)
DOM时间流:
捕获的流程:
Event对象的应用:
注册事件:
响应事件:
401事件:
自定义事件(!):
数组去重
深度克隆
原型
网友评论