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

还是接着我们的上文,接下来谈谈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属性指向函数本身;

来看一下图示:

image.png

上图很显然,Person是一个函数,函数里面有一个prototype属性指向了Person Prototype,这就是函数Person的原型;原型里面总会有一个constructor属性指向Person本身;

我们接着看更进一步的图:

image.png

注意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;

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

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

image.png

这幅图是经典原型图的简化版,可以很好的帮助我们理解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)和提交的url
send(content);
onreadystatechange(){
  if(xmlHttpRequest.readyState == 4){
    if(xmlHttpRequest.state == 200){
      //请求成功
    }
  } else{
    //请求失败
  }
}

不过很多时候你都不需要自己封装ajax的方法,也不需要兼容ie6+的浏览器(不排除有一些传统行业还需要)

  • Http协议

最后简单讲一下http协议;

所谓http协议,指的是我们平时上网的时候,客户端用来和服务端通信最常使用的协议之一;

http协议的步骤如下:

  • 客户端连接到Web服务器
  • 发送HTTP请求
  • 服务器接受请求并返回HTTP响应
  • 释放连接TCP连接
  • 客户端浏览器解析HTML内容

Http协议是存在于应用层,和用户打交道最多的协议;

这里面知识点超级多,每一项都可以作为一篇单独的文章来发布了,因此后续可能会专门做这一块的专栏;这里的话只是简单提醒一下,小白可以根据自己的情况去搜集更多的资料来进行学习;

最后,再次感谢大家的阅读,希望这篇教程能给你一些帮助;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355