一个普通全日制本科的普通应届毕业生逆向冲分的自述,希望各路大神勿喷(狗头)。
前言
在去年下半年寒冬将至之时,我还在深圳某间中大型公司的某个温暖的项目组做着前端实习。偶尔在掘金、简书上刷到互联网寒冬的消息也是大致浏览,丝毫没有放在心上。直到有天项目组组长约我谈话,说北京总部那边转正编制今年有改变,除了后端销售那边还有些岗位之外,其他的职位都可能转正不了,特别是前端(我是除了后端实习生之外最后一个离职实习生在2月尾巴)。说实话,当时我的内心除了离开一群可爱的同事感觉有点失落其他感觉没多大,因为导师的信任把很多需求、bug修复任务分到我身上让我成长了很多。在那4个多月的实习中,我深刻理解了Javascript的闭包、原型、继承、预编译过程的函数声明整体提升,变量声明提升、this指向、json数据处理、也独立解决过深拷贝,浅拷贝、防抖节流的问题、ES6常用的新语法也经常使用,对宏观任务和微观任务以及同步异步也有着清晰的理解、能熟练的使用Vue框架和less预编译器独立开发、对组件化和模块化开发也有清晰的理解、熟悉使用git版本管理。所以通俗的说:那时候的我飘了。
金3银4绝望季
作为一个标准90后,崇尚着“只要心够大,天天是暑假”的理念,刚离职当然先放松放松,于是花一个星期把星耀5的号打上了王者。在那之后,正式开始了我的寒冬之旅,直至今日收到4个offer,虽然没有一个薪资和我预期的一样,但为了生活还是选择了一个周三入职。在求职这个过程过于曲折,总结了一下:菜是原罪。
在这个求职过程中,我遇到过招前端开发工程师却面试Java、计算机原理、数据结构,理由是面试成功后不一定做前端开发,可能分配后台开发、测试岗位,因为他觉得前端技能去培训班培训6个月出来前端技术栈你可以掌握很多,Vue你也可以用得很6,但是计算机原理那些学校教的基础知识才是区分你与培训班出来的不同。虽然我很认同他说的,奈何嘴上回答不出答案,只能回去等通知了;我也面试过和技术面试官聊了差不多一个多钟的前端技术后(基本可以回答出来)问我php后台开发,因为公司是初创公司,必要时需要进行后台开发,岗位需求有写,最后也只能收获回去等通知;我还面试过需要1-3年工作经验的前端工程师,前端基础都回答上了,却因VueX的问题表述不清晰和未接触webpack提取公共模块问题回答不出,再加上问题的不断挖掘导致自身紧张,最终面试官加了我微信,让我做候选人,这几天没遇到合适就录用我...但是最常见的情形还是简历投递石沉大海,绝大部分的简历投递只有已到达、已查阅和不适合三个阶段,明明职位要求和自己技术栈匹配却依然回馈不适合的情况司空常见,而更常见的是永远是已到达状态。一次又一次的打击让我都不再相信自己,期望薪资也心中一次次下降,以至于现在和hr谈薪资都相当佛性,听从安排,只要还是正常的薪酬范围点头就完事了。
初级前端工程师需具备的javascript基础(导师讲的,甩锅先)
预编译
预编译—发生在函数执行的前一刻,它在函数执行时总得来说做了两件事:一函数声明整体提升;二变量 声明提升。那么预编译具体是做了什么事情呢?
从整体页面来看,当script内代码块执行时,预编译做了三件事。
第一件事情是创建GO(Global Object)对象,也就是我们熟悉的全局对象
第二件事是查找变量声明作为GO属性,值赋予undefined
第三件事是查找函数声明作为GO属性,如果属性名存在,直接把值赋予函数体。
当我们调用一个函数时,在执行前一刻,预编译做了四件事情。
第一件事情是生成一个AO(Actived Object)对象,也就是我们平时所说的函数作用域对象,保存函数调用时的局部变量。
第二件事情是查找函数形参以及函数内部变量声明,形参名以及变量名作为AO对象的属性,值为undefined。
第三件事情是实参形参相统一,把实参的值赋给形参。
第四件事情是查找函数声明,如果AO对象中属性名与函数名一样,把值赋予函数体。
当代码在执行时,创建出的变量对象的一条作用域链,[[scope]](作用域)存储着一层层的AO与GO的集合,集合呈链式链接就是作用域链,用来指定所有变量和函数的访问顺序,作用域链最顶端始终是当前代码正在执行的变量对象的AO。
闭包
闭包—是指有权访问另一个函数作用域变量的函数。
创建闭包的常用方法就是函数里面再创建函数,然后把创建的函数的结果return出去保存到外部。所以当script代码块执行时,先生成GO,然后代码由上到下执行,当执行到外部函数执行前一刻时生成该函数的AO,同时当外部函数执行产生内部函数的定义,所以当内部函数被创建时保存了外部函数的执行环境(AO、GO),而且还未执行就把内部函数被return到外部时,从而导致外部函数释放不了自己的作用域,形成闭包。而当接收了return的内部函数的函数执行时(即 var test = 外部函数();test();),内部函数才生成自己的AO再作用域顶端,同时作用域链上还有外部函数的AO以及GO。
原型链
原型链-由原型组成的链叫做原型链。而对象的__proto__就是它的是原型,原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样根据对象的__proto__向上查找,这就是原型链。
原型链继承
原型链继承就是每一个构造函数都有一个prototype属性指向该构造函数的父类,当实例对象通过new一个构造函数生成,该实例对象隐性执行了四步。
第一步 var 中间变量 = {}
第二步 将构造函数中的this指向新创建的中间变量。
第三步 中间变量.__proto__ = 构造函数.prototype
第三步 return 实例
所以当一个构造函数的prototype等于另一个实例对象,而这个实例对象是通过new另一个构造函数生成的,而另一个构造函数的prototype.xxx=xxx,通过这种方式第一个构造函数的实例对象就可以访问到另一个构造函数的父类,这也就实现原型链继承。
构造函数继承、借用构造函数继承、组合继承
下回分解
圣杯模式继承
理论:函数声明空构造函数做中间层(function F(){}),F.prototype属性等于Father.prototype,然后Son.prototype = new F();但是有个继承混乱问题,所以需要把Son的constuctor归位,即Son.prototype.constuctor = Father;(前提声明了Son、Father构造函数)
经典圣杯模式实现继承代码封装:
function inherit(Target,Origin){
function F(){};
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
}
复制代码
this指向
this指向只有在函数执行的时候才能确定this到底指向谁。this指向有三种情况
第一种情况:如果一个函数没有被上一级的对象所调用,那么this指向GO,反之即指向上一级对象的AO。
第二种情况:作为构造函数调用,this指向new出的对象的AO。(其中涉及到new操作符调用构造函数时隐式三步骤以及原型链继承概念)
第三种情况:箭头函数没有自己的this,它的this指向上下文的this
说到this指向,又不得不说三个改变this指向的方法—call、apply、bind。它们都是从Function.prototype继承来的(下篇再写具体用法)
深拷贝和浅拷贝
数据类型分为基本数据类型(undefined、null、布尔、string、number、symbol(es6新增))和复杂数据类型(object),基本数据类型存储在栈上,存储的是值,而复杂数据类型存储在堆上,存储的是地址。深拷贝和浅拷贝只适用于复杂数据类型,因为当object赋值给另一个变量其实拷贝的是地址,指向同一块存储空间,当拷贝对象改变原对象跟着改变就是浅拷贝,反之就是深拷贝。简单的数组存储值时可用concat()和slice()实现深拷贝,如果数组存储对象或者数组时可用josn.parse(josn.stringify(obj))。如果是对象通过递归把每个对象的值赋值给新定义的对象。
事件循环机制
javascript拥有一个基于事件循环机制的并发模型。js引擎把任务分成宏观任务(setTimeout、script)和微观任务(promise、process.nextTick)
,先执行宏观任务,再执行微观任务,任务又分同步任务和异步任务,所有同步任务在主线程上执行形成一个“执行栈”
,而异步任务只要有了运行结果就会在任务队列之中放置一个事件,当执行栈里的所有同步任务执行完,系统就会读取
队列任务,查看事件里相对应的异步任务,结束等待状态,进入执行栈开始执行。主线程不断重复这样的操作叫做事件循环机制。
ES6新特征
promise
ajax
状态码的区别
http1.0、http1.1、http2.0的区别
http缓存策略
性能优化(包括回流和重绘)
网络安全(XSS、CSRF 薄弱点)
Vue全家桶(Vue+Vue-Router+Vuex)
less或sass预编译器
flex布局
函数柯里化(薄弱点)
webpack(薄弱点)
...
感谢阅读,由于时间关系技术点没有一一根据自己的理解去细说,希望能够对正面努力迈向前端大门的你们给予帮助。只能说前端技术栈太多了,还是需要不断的学习,紧跟前端潮流,在前端这条路上也还有很长的路要走。坚持!加油!共勉!