写点什么

入门到放弃:理清前端技术概念

用户头像
大伟
关注
发布于: 2020 年 06 月 03 日
入门到放弃:理清前端技术概念

什么是JavaScript



JavaScript是一种脚本语言,1995年时,由Netscape公司在网景导航者浏览器上实现。浏览器内置JavaScript引擎来解释执行,用来给网页增加动态功能。Netscape希望它看起来像Java,因此取名为JavaScript,实际上毫无共通之处。Java和JavaScript的关系,就好比“老婆”和“老婆饼”的关系。



什么是ECMAScript



由于微软等公司也推出浏览器上运行的脚本语言进行竞争,1996 年Netscape 公司决定将 JavaScript 提交给标准化组织 ECMA(“European Computer Manufacturers Association”,欧洲计算机制造商协会),希望这种语言能够成为国际标准。次年,ECMA 基于JavaScript发布ECMA-262标准文件第一版,即ECMAScript 1.0 。为体现开放性和中立性,并避免侵犯Sun公司的商标权,该标准被称为ECMAScript而非JavaScript。



ECMAScript 和 JavaScript 的关系



ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的实现之一。通常下这两个词是可以互换。



ECMAScript 1.0 是 1997 年发布的,接下来的两年,连续发布了 ECMAScript 2.0(1998 年 6 月)和 ECMAScript 3.0(1999 年 12 月)。3.0 版在业界得到广泛支持,成为通行标准,奠定了 JavaScript 语言的基本语法并得到完全继承。今天学习 JavaScript,其实就是在学 3.0 版的语法。



什么是ES5



2009 年 12 月,ECMAScript 5.0 版(ES5)正式发布,2011 年 6 月,ECMAScript 5.1 版发布,并且成为 ISO 国际标准(ISO/IEC 16262:2011)。ES5 与 ES3 基本保持兼容。



什么是ES6



ES6即ECMAScript 6.0,是 2015 年 6 月正式发布JavaScript 语言标准,是继ES5之后的一次主要改进,增添了许多必要的特性,例如:模块和类,并且完全兼容以前的版本。目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

参考: https://es6.ruanyifeng.com



ES6 与 ECMAScript 2015 的关系



ES6 和 ES2015 实际上是同一个东西。 由于技术委员会规定ECMAScript 必须做到每年做一次更新。由此,这个版本被更名为 ES 2015,此后新版本(从 2015 年起) ES 命名也都是是根据年份来算的: ES2015、 ES2016、 ES2017... 目前最新的草稿已经到了ES2021( https://tc39.es/ecma262/



什么是Node.js



最初JavaScript只能运行于客户端的浏览器,依赖于浏览器上的引擎。2009年5月,Ryan Dahl发布了Node.js平台,对谷歌的Chrome V8引擎进行了封装,从而使JavaScript可以脱离浏览器,独立运行于服务端。



实质是:Node.js 是 JavaScript 的服务器运行环境(runtime),并且它对 ES6 的支持度很高。



什么是模块化



模块化是指把一个复杂的系统分解到一个一个的模块



模块化开发的优点



(1)代码复用,让我们更方便地进行代码管理、同时也便于后面代码的修改和维护。



(2)一个单独的文件就是一个模块,是一个单独的作用域,只向外暴露特定的变量和函数。这样可以避免污染全局变量,减少变量命名冲突。



早期的JavaScript缺乏对模块化的支持,后来发展出来的js模块化规范有:CommonJS、AMD、CMD、ES6的模块系统。



参考来源:https://zhuanlan.zhihu.com/p/53125734



什么是CommonJS模块化



服务器端模块的规范,由Node.js推广使用。该规范的核心思想是:允许模块通过require方法来同步加载所要依赖的其他模块,然后通过 exports 或module.exports 来导出需要暴露的接口。



实例:



//math.js
var num = 0;
function add(a, b) {
return a + b;
}
module.exports = {
//需要向外暴露的变量、函数
num: num,
add: add
}



可以这样加载:



//引入自定义的模块时,参数包含路径,可省略.js
//引入核心模块时,不需要带路径,如var http = require("http");
var math = require('./math');
math.add(1, 2)//3



实际上,从上面的例子就可以看出,math.add(1,2)必须要等待math.js加载完成,即require是同步的。



什么是AMD模块化



AMD:异步模块定义。上面已经介绍过,CommonJS是服务器端模块的规范,主要是为了JS在后端的表现制定的,不太适合前端。而AMD就是要为前端JS的表现制定规范。由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是require.js(还有个js库:curl.js)。实际上AMD 是 require.js在推广过程中对模块定义的规范化的产出。



math.js定义一个模块:



define('math', ['jquery'], function (jquery) {//引入jQuery模块
return {
add: function (x, y) {
return x + y;
}
};
});



导入和使用:



require(['math'], function (math) {
math.add(1, 2)
})



math.add()与加载math模块不是同步的,不会阻塞浏览器的加载。



什么是CMD模块化



CMD:通用模块定义。



国内的玉伯大佬写了sea.js,实际上CMD就是 sea.js在推广过程中对模块定义的规范化的产出。



define(function (require, exports, module) {
// 模块代码
});



说明:



require:可以把其他模块导入进来的一个参数;



exports:可以把模块内的一些属性和方法导出的;



module: 是一个对象,上面存储了与当前模块相关联的一些属性和方法。



上面示例中的代码改写成CMD形式:



define(function (require, exports, module) {
var add = function (a, b) {
return a + b;
}
exports.add = add;
})
//导入和使用
seajs.use(['math.js'], function (math) {
var sum = math.add(1, 2);
});



CMD与AMD的不同的在于:



(1)AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require:



//AMD推崇的依赖关系前置:在定义模块时就要声明要依赖的模块
define(['a', 'b', 'c', 'd'], function (a, b, c, d) { // 依赖必须一开始就写好
a.doSomething()
// 此处省略100行
...
b.doSomething()
...
})
//CMD推崇依赖就近,按需加载,只有在用到某个模块时再去require
define(function (require, exports, modules) {
var a = require('a');
a.doSomething();
// 此处省略100行
...
var b = require("b");//按需加载
b.doSomething();
...
})



(2)AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。



对于依赖的模块,AMD是提前执行,CMD是延迟执行。



具体细节可点击 参考



什么是ES5的模块化



其实就是指CommonJS(服务器端)和AMD(浏览器端,require.js)



CommonJS模块化和AMD模块化的区别



CommonJS服务器端,AMD浏览器端。



什么是ES6模块化



在ES6标准出来之前,大家都是commonJS或者AMD规范来模块化。ES6在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。



在 ES6 中,使用export关键字来导出模块,使用import关键字引用模块。但是浏览器还没有完全兼容,需要使用babel转换成ES5。



示例中的代码改写成ES6形式:



//math.js
var num = 0;
var add = function (a, b) {
return a + b;
};
export { num, add };
//导入
import { num, add } from './math';
function test(ele) {
ele.textContent = add(1 + num);
}



缺点



浏览器还没有完全兼容,必须通过工具转换成标准的 ES5 后才能正常运行。



为什么需要Babel和Webpack



ES6引入了模块化后,不同功能的代码可以分开写成module的形式。



但目前的浏览器环境,并不支持ES6 module写法, 所以我们需要借助webpack打包工具和babel转码器来生成可运行的代码。



什么是Babel 转码器



Babel 是 ES6 转码器或者说编译器,将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。



这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持...吗?



什么是Webpack



WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。



Webpack和Babel什么关系



参考来源:https://www.jianshu.com/p/c8b27e40d433



Webpack是打包工具,Bable是转码器,两者一起使用。我们只需要配置入口js文件,webpack会自动解析模块间的依赖关系,

通过babal-loader调用babel去转译相应的模块,最后打包成一个目标js文件。



有了Babel为什么还需要Webpack



babel承担了“翻译”的角色,把es6的写法转换成es5的写法。

但是有些人可能在一个项目中单独安装完babel,并成功生成了新的文件后,发现导入这个文件到浏览器中却报错了。其中很有可能被误导的是 import这个关键词。



实际上babel转换后的代码是遵循commonJS规范的,而这个规范,浏览器并不能识别。因此导入到浏览器中会报错,而nodeJS是commonJS的实现者,所以在babel转换后的代码是可以在node中运行的。



为了将babel生成的commonJS规范的es5写法能够在浏览器上直接运行,我们就借住了webpack这个打包工具来完成,因为webpack本身也是遵循commonJS这个规范的,从它的配置文件webpack.config.js中就可以看出来。



//module.exports是commonJS的接口输出规范,es6的规范是export
module.exports = {
entry: path.join(__dirname, 'index.js'),
output: {
path: path.join(__dirname, 'outs'),
filename: 'index.js'
},
};



Webpack的工作方式



参考来源:https://www.jianshu.com/p/42e11515c10f



把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。



Babel的局限性



参考来源:21 分钟精通前端 Polyfill 方案



即便使用了 Babel ,也做不到放心大胆的使用ES6,否则会被各种 undefined 的报错无情打脸。



const foo = (a, b) => {
return Object.assign(a, b);
};



上面这样的代码交给 babel 编译时,我们得到了:



"use strict";
var foo = function foo(a, b) {
return Object.assign(a, b);
};



可以看到,Babel只能进行语法转换,arrow function 被编译成了普通的函数形式,完美。

但是Object.assign作为 es2015 的新方法,没有可以被自动转换为的老函数。



一句话概括, babel 的编译不会做 polyfill。那么 polyfill 是指什么呢?



什么是Polyfill



polyfill

- n. 一种用于衣物、床具等的聚酯填充材料, 使这些物品更加温暖舒适。
- Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。



比如说 polyfill 可以让 IE7 使用 Silverlight 插件来模拟 HTML Canvas 元素的功能,或模拟 CSS 实现 rem 单位的支持,或 text-shadow,或其他任何你想要的功能。



Polyfill如何实现



1,分别引入替换插件babel-plugin-transform-xxx,比如替换Object.assign的babel-plugin-transform-object-assign



yarn add babel-plugin-transform-object-assign
# in .babelrc
{
"presets": ["latest"],
"plugins": ["transform-object-assign"]
}



2,babel 提供了 babel-plugin-transform-runtime,从一个统一的地方 core-js 自动引入对应的方法



yarn add -D babel-plugin-transform-runtime
yarn add babel-runtime
# .babelrc
{
"presets": ["latest"],
"plugins": ["transform-runtime"]
}



3,babel 直接提供了通过改变全局来兼容 es2015 所有方法的 babel-polyfill



import 'babel-polyfill';
export const foo = (a, b) => Object.assign(a, b);



三种方式各有优缺点和适用场景,而且使用不当会造成很难以发现的问题。参考:21 分钟精通前端 Polyfill 方案



4,babel-preset-env 支持针对指定目标环境选择需要的 polyfill 了,只需引入 babel-polyfill,并在 babelrc 中声明 useBuiltIns,babel 会将引入的 babel-polyfill 自动替换为所需的 polyfill。



5,polyfill.io 服务器会判断浏览器 UA 返回不同的 polyfill 文件,你所要做的仅仅是在页面上引入这个文件,polyfill 这件事就自动以最优雅的方式解决了。更加让人喜悦的是,polyfill.io 不旦提供了 cdn 的服务,也开源了自己的实现方案 polyfill-service。简单配置一下,便可拥有自己的 polyfill service 了。



上面两种方式也有缺陷,参考:21 分钟精通前端 Polyfill 方案 坑这么多,真替前端技术人员捂脸。



什么是npm



npm的出现,是为了解决前端开发中的代码复用问题,让全世界的前端开发人员可以互相分享并复用所有人的代码。



参考来源:https://www.jianshu.com/p/c36666b306aa



【node package management】,是nodejs内置的软件包管理器。毫无疑问,npm是用来管理软件包的。



它是世界上最大的软件注册表,每星期大约有30亿次的下载量,包含超过600000个包(包)(即,代码模块)。来自各大洲的开源软件开发者使用NPM互相分享和借鉴.包的结构使您能够轻松跟踪依赖项和版本。

npm由三大独立部分组成:

- 网站:开发者查找包(package)、设置参数以及管理 npm 使用体验的主要途径,网址为:https://www.npmjs.com/
- 注册表:是一个巨大的数据库,保存了每个包的基本信息。
- 命令行工具:开发者与npm包打交道的工具。



什么是yarn



yarn的出现,是为了解决npm的问题



参考来源:https://www.cnblogs.com/wendyw/p/11494036.html



Yarn:Yet Another Resource Negotiator,是一个快速、可靠、安全的依赖管理工具,一款新的JavaScript包管理工具。可以替代npm。



未完(写不下去了... 向勇于攀登的前端技术同学致敬)



用户头像

大伟

关注

码龙战BUG于野。 2020.05.21 加入

还未添加个人简介

评论

发布
暂无评论
入门到放弃:理清前端技术概念