点击前端充电营,关注我们
还是接着我们的上文,接下来谈谈js对于新手入门需要掌握哪些东西;
- 分清楚ECMAScript标准和W3C标准
ECMAScript是一种由Ecma国际 (前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言 。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript ,所以它可以理解为是JavaScript的一个标准,但实际上后两者是ECMA-262标准的实现和扩展。也就是说,ECMA标准主要是为了规范js语言,定义js语言是一种怎样的表现的一个标准; 再来看看W3C标准:
这是W3C标准里面的行为标准,这是根据DOM规范,制定了一套关于web设计师如何与浏览器打交道的标准; 简单点来说,也就是ECMA标准规定了js这门语言本身应该具有的形态,例如原型、闭包、作用域等特性,我们常说的es6特性就是ECMAScript特性; 而W3C标准则是规定了js可以如何去跟DOM节点打交道,例如我们常用的window、document等js页面常见的全局对象就是标准里面定义的。一、文档对象模型(外语缩写:DOM)根据W3C DOM规范,DOM是一种与浏览器,平台,语言的接口,使得你可以访问页面其他的标准组件。简单理解,DOM解决了Netscaped的Javascript和Microsoft的Jscript之间的冲突,给予web设计师和开发者一个标准的方法,让他们来访问他们站点中的数据、脚本和表现层对象。
- 了解js基本的语法;
简单而面试中又常见的知识点:JS执行机制
这里给小伙伴们详细讲解一下js的原型是怎么一回事,我会尽量用简短的篇幅去描述;
-
javascript原型
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的作用域与闭包
- 内层作用域可以访问到外层或者同层级的变量;
- 但是反过来外层作用域不能访问到内层作用域的变量;
// 全局作用域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(新节点,老节点) // 在父节点中,用新节点替换老节点
- ...
最后再提一下前端工程师必须掌握两点知识:Ajax和http协议;
- Ajax
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协议
-
客户端连接到Web服务器
-
发送HTTP请求
-
服务器接受请求并返回HTTP响应
-
释放连接TCP连接
- 客户端浏览器解析HTML内容
关注【前端充电营】
回复【电子书】
获取100+
技术书籍!
前端也能轻松年薪20w+?超详细前端入门攻略拿去!
都0202年了,你还不知道javascript有几种继承方式?
2019,这一年前端界又发生了哪些大事?前端人花几分钟看看吧!
点“在看”你懂得