前端也能轻松年薪20w+?超详细攻略下篇来了!

194 阅读11分钟
原文链接: mp.weixin.qq.com

点击前端充电营,关注我们

还是接着我们的上文,接下来谈谈js对于新手入门需要掌握哪些东西;

  • 分清楚ECMAScript标准和W3C标准
所谓的ECMA,我们看百度百科的定义:
ECMAScript是一种由Ecma国际 (前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言 。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript ,所以它可以理解为是JavaScript的一个标准,但实际上后两者是ECMA-262标准的实现和扩展。
也就是说,ECMA标准主要是为了规范js语言,定义js语言是一种怎样的表现的一个标准; 再来看看W3C标准:

一、文档对象模型(外语缩写:DOM)根据W3C DOM规范,DOM是一种与浏览器,平台,语言的接口,使得你可以访问页面其他的标准组件。简单理解,DOM解决了Netscaped的Javascript和Microsoft的Jscript之间的冲突,给予web设计师和开发者一个标准的方法,让他们来访问他们站点中的数据、脚本和表现层对象。

这是W3C标准里面的行为标准,这是根据DOM规范,制定了一套关于web设计师如何与浏览器打交道的标准; 简单点来说,也就是ECMA标准规定了js这门语言本身应该具有的形态,例如原型、闭包、作用域等特性,我们常说的es6特性就是ECMAScript特性; 而W3C标准则是规定了js可以如何去跟DOM节点打交道,例如我们常用的window、document等js页面常见的全局对象就是标准里面定义的。
  • 了解js基本的语法;
首先js语法拥有很多的特性,例如原型链、作用域链、闭包和事件循环,还有不断加入的es6、es7新特性; 事件循环机制我之前有专门写过一篇文章来讲解是怎么一回事,有兴趣的同学可以去看看,这里附上原文链接:

简单而面试中又常见的知识点:JS执行机制

这里给小伙伴们详细讲解一下js的原型是怎么一回事,我会尽量用简短的篇幅去描述;

  • javascript原型

首先请大家先想一下什么是原型?什么是js的原型? js中关于原型的定义其实很明确: js的所有函数,都有一个prototype属性,这个属性本身是一个对象,对象里面又有一个constructor属性指向函数本身; 来看一下图示: 上图很显然,Person是一个函数,函数里面有一个prototype属性指向了Person Prototype,这就是函数Person的原型;原型里面总会有一个constructor属性指向Person本身; 我们接着看更进一步的图: 注意Student不是一个函数,而是一个实例对象,是通过
var Student = new Person()
实例化出来的; 我们可以看到上图的Student有一个__proto__属性,这就是我要讲的第二点: 每一个对象都会有一个叫做__proto__的属性,称为隐式原型; 它指向的是函数的prototype对象,也就是函数的原型; 那么这个属性有什么作用呢,或者说js的原型有什么作用呢? 只要记住,当一个对象的某一个属性或者方法找不到的时候,它会沿着自身的原型往上寻找,直到找到该属性或者方法为止,当然,如果找到尽头还找不到的话,会返回xx is undefined; 什么时候才是它的尽头呢?null,null是一切的终点,所以说js万物皆对象,万物皆空; 我们接着来更深入一下原型,首先我们直到一个事实:函数是对象; 我们可以通过这种方式创建函数:
var Person = new Function('console.log(1)')Person() // 1

上面代码中可以看出,函数也是可以通过new语法来创建的,new的是什么,new的是Function这个函数;

也就是说,所有的函数,都是由Function函数实例化而来的;

那么回到我们上面所讲的,既然函数是对象,那么对象就都有__proto__属性指向其原型,那么Person同样也应该有__proto__属性,这个属性指向的是Function.prototype,所以所有函数实例的原型都是Function.prototype;

那么问题来了,我前面说过万物皆对象,那么Function.prototype自然也是一个对象,所有对象都有__protp__属性,所以Function.prototype是不是也有这个属性呢?

答案是肯定的,Function.prototype里面有__proto__属性,并且这个属性指向的是Object.prototype;

如果你听到这里觉得已经蒙了,那么恭喜你,这是很正常的现象;

为了方便小伙伴理解我刚才讲的话,特意画了一个草图把刚才的逻辑理了出来,看下方的图:

这幅图是经典原型图的简化版,可以很好的帮助我们理解js的原型关系; 从左到右分成三块:Person函数、Function函数与Object函数、Function.prototype和Object.prototype; 我们一块块来看;
  • 第一块
首先是Person函数,函数都有prototype属性,指向其原型,所以指向的是Person.prototype; 同时函数也是对象,对象都有__proto__属性,因为Person原型是函数,所以其隐式原型指向的是Function.prototype
  • 第二块
然后是中间的Function和Object,可以看到两个都是函数,所以都有其自身的prototype指向 自身的原型对象; 这里提一下,Function的__proto__属性,指向的也是Function.prototype,和prototype属性一样;
  • 第三块
然后第三块,可以看到所有的prototype对象都指向同一个地方:Object.prototype,这表示所有的原型都是对象; 然后Object.prototype总不能指向自己吧,所以js设计者将其指向了null,所以js最后是万物皆空; 最后总结一下的话,只要记住,凡是函数都有prototype属性指向函数.prototype,这就叫做该函数的原型; 原型是一个对象,所以所有原型最终指向的是Object.prototype,同时因为Object.prototype不可能再指向自身,所以它指向的是Null; 然后所有的对象都有__proto__属性,指向的是生成该对象的函数的prototype属性; 关于函数的原型,暂时就只讲到这里了,希望你看了之后,能对js的原型有更深的理解~
  • js的作用域与闭包
这块我会讲得更加通俗点; js的作用域分为两个:全局作用域和函数作用域(暂时不包括es6之后的块级作用域); 作用域有内层外层的概念,也就是全局作用域是外层,定义在全局的函数是内层,定义在函数内部的函数是更内层;
  • 内层作用域可以访问到外层或者同层级的变量;
  • 但是反过来外层作用域不能访问到内层作用域的变量;
看下代码:
// 全局作用域var a = '这里是最外层'function foo() {  var f = '这里是同层级'console.log(a)  console.log(f)}foo()// 这里是最外层 // 这里是同层级
定义在全局的foo函数内部可以访问到外部变量a和同层级的变量f;
// 全局作用域var a = '这里是最外层'function foo() {  var f = '这里是同层级'  console.log(a)}console.log(f)// f is not defined
而全局作用域没办法访问到函数foo内部的变量f; 其实这也是符合我们的认知习惯的,js中还有个作用域链的概念,也就是一旦在函数内部作用域没有找到的变量,将会从内向外一层层寻找,直到找到为止; 说完了作用域,我们再来讲讲闭包; 为什么要有闭包? 我们知道外部没办法访问函数内部的变量,当我确实想要访问的时候怎么办呢?闭包就是用来干这个的,在函数内部返回另一个函数,使得外部可以访问到函数内部的变量;来看代码:
function foo() {  var a = 2  return function(b) {    return a + b  }}var closureFn = foo()console.log(closureFn(1)) // 3
函数foo返回了一个function,function里面引用了foo函数的a变量,最后成功计算得出了3; 这就是闭包最基本的使用了,至于它的原理,这里我不做太细的展开。 只提一点就是:由于返回的函数内部引用了变量a,所以foo会一直留在内存中,a变量也会一直存在内存中,直到closureFn这个引用不再使用; 闭包还有什么其他的应用场景吗? 我们经典的一个for循环大坑,代码如下:
var arr = []for(var i = 0;i < 5;i++) {  setTimeout(function() {    arr.push(i)  }, 0)}console.log(arr)// [ 5, 5, 5, 5, 5]
这里输出的都是5,因为setTimeout是在js事件循环最后才执行的(有关于js事件循环机制的请参考文章前面提到的往期文章),所以最后i已经变成了5,arr.push(i)实际上等同于arr.push(5); 那么如何利用闭包解决这个事情呢?我们直接看解决代码:
var arr = []for(var i = 0;i < 5;i++) {  (function(i){    setTimeout(function() {      arr.push(i)    }, 0)  }(i))}console.log(arr) // 0, 1, 2, 3, 4
我们看到上面最大的不同,就仅仅是给setTimeout函数外层包了一层自执行函数(也就是该函数会立刻执行),并且将i作为变量传入了该函数; 为什么这样的输出反而就变正常了呢? 我们改下代码相信你就一目了然了:
var arr = []for(var i = 0;i < 5;i++) {  (function(any){    setTimeout(function() {      arr.push(any)    }, 0)  }(i))}console.log(arr) // 0, 1, 2, 3, 4
明白了吗?我们将i当前的值传给了函数,函数拿到的是值本身,并不是i这个索引; 所以即使最后i变成了5,对传给函数的参数(any)并不会有任何的影响,因为参数的值从for循环的时候就已经决定了,而不是for循环结束后再去拿当前的i的值; 以上就是作用域跟闭包的一些知识点了;
  • 了解一些常用的浏览器操作DOM节点的API

虽然有了vue、react等框架,现在使用原生js或者jq直接操作dom节点的情况已经很少了,但是我们还是要了解一些基本的api的使用;

常见的有如下api:

  • document.getElementById('id') // 根据元素id获取节点
  • document.getElementsByClassName('class') // 根据元素类名获取节点
  • document.getElementsByName('name') // 根据元素name属性获取节点
  • document.getElementsByTagName('div') // 根据元素标签名称属性获取节点
  • document.createElement('div') // 创建新的DOM节点
  • parentNode.insertBefore(新节点,目标节点) // 在父节点中,将新节点插入到目标节点之前
  • parentNode.appendChild(新节点) // 在父节点的最后插入一个新节点
  • parentNode.removeChild(子节点)  // 删除父节点中指定的子节点
  • parentNode.replaceChild(新节点,老节点) // 在父节点中,用新节点替换老节点
  • ...
还有很多很多基础的api,这里不再一一列举; 那么关于javascript的必须掌握点,我们先总结到这里;

最后再提一下前端工程师必须掌握两点知识:Ajax和http协议;

  • Ajax
我们知道,ajax的出现改变了前后端的开发方式,后端能从渲染页面数据的工作中解脱出来,前端能做到更多的事情; 基本的ajax分为get请求和post请求, 我们来看下原生js实现一个ajax get请求:
var xmlHttpRequest;function createXmlHttpRequest() {  if(window.XMLHttpRequest) {    // 非IE    xmlHttpRequest = new XMLHttpRequest();  } else if(window.ActiveObject) {    //IE6+    xmlHttpRequest = new ActiveObject("Msxml2.XMLHTTP");  } else {    // IE6-    xmlHttpRequest = new ActiveObject("Microsoft.XMLHTTP");  }open('GET', url);//分别为提交的方法(GET或者POST)和提交的urlsend(content);onreadystatechange(){  if(xmlHttpRequest.readyState == 4){    if(xmlHttpRequest.state == 200){      //请求成功    }  } else{    //请求失败  }}
不过很多时候你都不需要自己封装ajax的方法,也不需要兼容ie6+的浏览器(不排除有一些传统行业还需要)
  • Http协议
最后简单讲一下http协议; 所谓http协议,指的是我们平时上网的时候,客户端用来和服务端通信最常使用的协议之一; http协议的步骤如下:
  1. 客户端连接到Web服务器

  2. 发送HTTP请求

  3. 服务器接受请求并返回HTTP响应

  4. 释放连接TCP连接

  5. 客户端浏览器解析HTML内容
Http协议是存在于应用层,和用户打交道最多的协议; 这里面知识点超级多,每一项都可以作为一篇单独的文章来发布了,因此后续可能会专门做这一块的专栏;这里的话只是简单提醒一下,小白可以根据自己的情况去搜集更多的资料来进行学习; 最后,再次感谢大家的阅读,希望这篇教程能给你一些帮助;

关注【前端充电营】

回复【电子书】

获取100+

技术书籍!

前端也能轻松年薪20w+?超详细前端入门攻略拿去!

都0202年了,你还不知道javascript有几种继承方式?

2019,这一年前端界又发生了哪些大事?前端人花几分钟看看吧!

点“在看”你懂得