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

什么是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。

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

posted @ 2020-06-04 18:37  cs_liwei  阅读(248)  评论(0编辑  收藏  举报