什么是 Javascript
Javascript 最早问世于1995年,当时网景公司主要想通过 Javascript 代替 Perl 等服务端语言处理输入验证,以减少与服务端的通讯次数。随着互联网技术的发展,逐渐成为了一门脚本语言。红皮书对于 Javascript 的定义是:Javascript 是一门用来与网页交互的脚步语言,包含三个组成部分:
- ECMAScript:由 ECMA-262 定义并提供核心功能。
- DOM(文档对象模型):提供与网页内容较好的方法和接口。
- BOM(浏览器对象模型):提供和浏览器交互的方法和接口。
HTML 中的 Javascript
随着互联网应用的日益丰富,前端工程化也日趋完善,Angular、React、Vue等框架及其生态的先后出现给前端开发带来了翻天覆地的变化,但究其根本还是对于前端三大件 HTML、CSS 和 Javascript 的使用拓展和优化。早期网景公司创造了 <script> 标签将 Javascript 融入 HTML 使用,并为其设置了 8 个属性。
- async: 可选。表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载。只对外部脚本文件有效.
- charset:可选。使用src属性指定的代码字符集。这个属性很少使用,因为大多数浏览器不在乎它的值。
- crossorigin:可选。配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS。crossorigin="anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据标志,意味着出站请求会包含凭据。
- defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。在IE7及更早的版本中,对行内脚本也可以指定这个属性。
- integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI, Subresource Integrity)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN, Content Delivery Network)不会提供恶意内容。
- language:废弃。最初用于表示代码块中的脚本语言(如"JavaScript"、"JavaScript 1.2"或"VBScript")。大多数浏览器都会忽略这个属性,不应该再使用它。
- src:可选。表示包含要执行的代码的外部文件。
- type:可选。代替language,表示代码块中脚本语言的内容类型(也称MIME类型)。按照惯例,这个值始终都是 "text/javascript",尽管 "text/javascript" 和 "text/ecmascript" 都已经废弃了。JavaScript文件的MIME类型通常是 "application/x-javascript",不过给type属性这个值有可能导致脚本被忽略。在非IE的浏览器中有效的其他值还有 "application/javascript" 和 "application/ecmascript"。如果这个值是 module,则代码会被当成ES6模块,而且只有这时候代码中才能出现 import 和 export 关键字。
在 HTML 中插入 Javascript 的过程中需要主意一下几点:
- 要包含外部 JavaScript 文件,必须将 src 属性设置为要包含文件的 URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
- 所有
<script>元素会依照它们在网页中出现的次序被解释。在不使用 defer 和 async 属性的情况下,包含在<script>元素中的代码必须严格按次序解释。 - 对不推迟执行的脚本,浏览器必须解释完位于
<script>元素中的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。 - 可以使用 defer 属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。
- 可以使用 async 属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。
- 通过使用
<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。
作用域和作用域链
任何变量(不管包含的是原始值还是引用值)都存在于某个执行上下文中(也称为作用域)。这个上下文(作用域)决定了变量的生命周期,以及他们可以访问代码的哪些部分。
- 作用域分为全局作用域、函数作用域(局部作用域)和块级作用域。
上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain)。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。
在调用一个函数时,会为这个函数调用创建一个执行上下文,并创建一个作用域链。然后用arguments和其他命名参数来初始化这个函数的活动对象。外部函数的活动对象是内部函数作用域链上的第二个对象。这个作用域链一直向外串起了所有包含函数的活动对象,直到全局执行上下文才终止
变量定义
ECMAScript 变量是松散类型的,意思是变量可以用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符。有3个关键字可以声明变量:var、const 和 let。其中,var 在 ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。
- 使用 var 声明的变量,其作用域为函数作用域,且声明会自动提升到函数顶部,允许声明前使用,值为 undefined,允许重复声明。
- 使用 let 声明的便利,气作用域为块级作用域,不存在变量提升,在声明前执行的瞬间被称为‘暂时性死区’,不允许重复声明。
- 使用 const 的行为基本与 let 一致,不同在于 const 声明时必须初始化赋值,且尝试修改 const 声明的变量会导致运行时错误。
最佳实践:const 优先,let 次之,少用 var。
数据类型
ECMAScript 有 7 种简单数据类型,也称为元素类型:undefined、null、boolean、number、string、symbol、bigInt,还有一种复杂类型也称为引用类型 object。
- 使用 typeof 判断数据类型时会返回以下字符串:‘undefined’、‘boolean’、‘string’、‘number’、‘object’、‘function’、‘symbol’。其中 ‘object’表示为对象或 null。
- 原始值和引用值的特点:原始值大小固定,存储在栈内存中,复制变量时会创建该值的第二个副本;应用值是对象,存储在堆内存中,包含引用值的变量实际上是个指向相应对象的一个指针,而不是对象本身,复制变量时值复制了一个指向对象的指针。
- typeof 操作符可以确定值的原始类型,instanceof 操作符可以值的引用类型。
闭包
定义:闭包指的是那些引用了另一个函数作用域中变量的函数(内部函数的作用域链仍保持着对外部函数活动对象的引用,就是闭包)。
应用场景:封装私有变量、延迟执行、模块化开发...
缺点:内存泄漏、性能问题...