ThinkingLink 2020-05-11
1995 年 2 月,Netscape 公司发布 Netscape Navigator 2 浏览器,并在这个浏览器中免费提供了一个开发工具——LiveScript。由于当时 Java 比较流行,Netscape 便把 LiveScript 改名为 JavaScript,这也是最初的 JavaScript 1.0 版本。
1997 年,欧洲计算机制造商协会(ECMA)以 JavaScript 1.1 为基础制订了脚本语言标准——ECMA-262,并命名为 ECMAScript。
简单概括,ECMAScript 是 JavaScript 语言的规范标准,JavaScript 是 ECMAScript 的一种实现。注意,这两个词在一般语境中是可以互换的。
2009 年 12 月,ECMAScript 5.0 版正式发布。
2015 年 6 月,ECMAScript 6 发布正式版本,并更名为 ECMAScript 2015 。Mozilla 在这个标准的基础上推出了 JavaScript 2.0。
从此以后,JavaScript 开始以年份命名,新版本将按照 “ECMAScript+年份” 的形式发布。目前最新版本为 ECMAScript 2019,于 2019 年 6 月正式发布。
JavaScript 遵循 ECMA-262 规范,目前其最新版是 ECMAScript 2019,而获得所有主流浏览器完全支持的则是 ECMAScript 5。以ECMAScript 5版本为基础,兼顾 ECMAScript 6 版本 中获得较大支持的新特性进行介绍。
https://kangax.github.io/compat-table/es5/
IE9 不支持严格模式,直到 IE 10 才开始;Safari 5.1 仍不支持 Function.prototype.bind,尽管 Function.prototype.bind 已经被 Webkit 所支持。
核心(ECMAScript):语言核心部分。
文档对象模型(Document Object Model,DOM):网页文档操作标准。
文档对象模型是 HTML 的应用程序编程接口(API)。DOM 把整个文档映射为一个树形节点结构,以方便 JavaScript 脚本快速访问和操作。
浏览器对象模型(BOM):客户端和浏览器窗口操作基础。
https://www.jianshu.com/p/0c8b34111e95
—般情况下,在文档的
标签中包含 JavaScript 脚本,或者导入的 JavaScript 文件。这意味着必须等到全部 JavaScript 代码都被加载、解析和执行完以后,才能继续解析后面的 HTML 部分。如果加载的 JavaScript 文件很大, HTML 文档解析就容易出现延迟。为了避免这个问题,在开发 Web 应用程序时,建议把导入 JavaScript 文件的操作放在 后面,让浏览器先 将网页内容解析并呈现出来后,再去加载 JavaScript 文件,以便加快网页响应速度。
script标签有一个布尔型属性 defer,设置该属性能够将 JavaScript 文件延迟到页面解析完毕后再运行。
该属性适用于外部JavaScript文件,不适用于script签包含的 JavaScript 脚本.
<script type="text/javascript" defer src="test.js"></script>
async 属性,让浏览器异步加载 JavaScript 文件,即在加载 JavaScript 文件时,浏览器不会暂停,而是继续解析。这样能节省时间,提升响应速度。
<script type="text/javascript" async src="test.js"></script>
温馨提示
JavaScript 是按块执行的,但是不同块都属于同一个作用域(全局作用域),下面块中的代码可以访问上面块中的变量。
如果以下代码块调换顺序会显示a undefined
<script> //JavaScript 代码块 2 var a = 1; </script> <script> //JavaScript 代码块 1 alert(a); </script>
JavaScript 遵循 Unicode 字符编码规则。Unicode 字符集中每个字符使用 2 个字节来表示,这意味着用户可以使用中文来命名 JavaScript 变量。
由于 JavaScript 脚本一般都嵌入在网页中,并最终由浏览器来解释,因此在考虑到 JavaScript 字符编码的同时, 还要兼顾 HTML 文档的字符编码,以及浏览器支持的编码。一般建议保持 HTML 文档的字符编码与 JavaScript 字符编码一致,以免出现乱码。
JavaScript 语法就是指构成合法的 JavaScript 程序的所有规则和特征的集合,包括词法和句法。简单描述如下:
词法定义了 JavaScript的基本名词规范,包括字符编码、命名规则、标识符、关键字、注释规则、 运算符和分隔符等。
句法定义了 JavaScript的基本运算逻辑和程序结构,包括短语、句子和代码段的基本规则,如表达式、语句和程序结构等。
JavaScript 严格区分大小写。
直接量(Literal)就是具体的值,即能够直接参与运算或显示的值,如字符串、数值、布尔值、正则表达式、对象直接量、数组直接量、函数直接量等。
//空字符串直接量 1 //数值直接量 true //布尔值直接量 /a/g //正则表达式直接量 null //特殊值直接量 {} //空对象直接量 [] //空数组直接量 function(){} //空函数直接量,也就是函数表达式
转义序列就是字符的一种表示方式(映射)。由于各种原因,很多字符无法直接在代码中输入或输出,只能通过转义序列间接表示。
特殊字符 ?
document.write("\xa9"); //显示字符? document.write("\u00a9"); //显示字符?
标识符(Identifier)就是名称的专业术语。JavaScript 标识符包括变量名、函数名、参数名和属性名。
合法的标识符应该注意以下强制规则:
一般常用转义序列表示特殊字符或名称,如 JavaScript 关键字、程序脚本等
break delete if this while
case do in throw with
catch else instanceof try
continue finally new typeof
debugger(ECMAScript 5 新增) for return var
default function switch void
abstract double goto native static
boolean enum implements package super
byte export import private synchronized
char extends int protected throws
class final interface public transient
const float long short volatile
arguments encodeURL Infinity Number RegExp
Array encodeURLComponent isFinite Object String
Boolean Error isNaN parseFloat SyntaxError
Date eval JSON parseInt TypeError
decodeURL EvalError Math RangeError undefined
decodeURLComponent Function NaN ReferenceError URLError
无论是在严格模式下还是在非严格模式下,都不要在定义变量名、函数名或者属性名时使用上面列举出的保留字,以免同学们入坑。
总体来说,注意代码规范,该空格的地就空格,也别瞎空格。。
在字符串或者正则表达式内,分隔符是有意义的,不能够随意省略或替换。
如果命名、空格、注释能做好,后面的维护人员会感激不尽!!!
1.在非严格模式下,JavaScript 允许不声明变量就直接为其赋值,这是因为 JavaScript 解释器能够自动隐式声明变量。隐式声明的变量总是作为全局变量使用。在严格模式下,变量必须先声明,然后才能使用。
2.JavaScript 在预编译期会先预处理声明的变量,但是变量的赋值操作发生在 JavaScript 执行期,而不是预编译期。
3.JavaScript 引擎的解析方式是:先解析代码,获取所有被声明的变量,然后再一行一行地运行。 这样,所有声明的变量都会被提升到代码的头部,这就叫作变量提升(Hoisting)。
4.变量作用域
变量作用域(Scope)是指变量在程序中可以访问的有效范围,也称为变量的可见性。
JavaScript 变量可以分为全局变量和局部变量:
5.变量污染
全局变量在全局作用域内都是可见的,因此具有污染性。大量使用全局变量会降低程序的可靠性,用户应该避免使用全局变量。
减少使用全局变量有两种方式:
var MyAPP = {}; //定义 APP 访问接口 MyAPP.name = { //定义APP配置变量 "id" : "应用程序的ID编号" };
在 JavaScript 函数体内,所有声明的私有变量、参数、内部函数对外都是不可见的,如果不主动开放,外界是无法访问内部数据的,因此使用函数体封装应用程序是最佳实践。
(function(window){ var MyAPP = {}; //定义 APP 访问接口 MyAPP.name = { //定义APP配置变量 "id" : "应用程序的ID编号" }; MyAPP.work = { num : 123, //APP计数器等内部属性 sub : { name : "sub_id"}, //APP 应用分支 doing : function(){ //具体方法 //执行代码 } }; window.MyAPP; //对外开放应用程序接口 })(window)
数据类型 | 说明 |
---|---|
null | 空值,表示非对象 |
undefined | 未定义的值,表示未赋值的初始化值 |
number | 数字,数学运算的值 |
string | 字符串,表示信息流 |
boolean | 布尔值,逻辑运算的值 |
object | 对象,表示复合结构的数据集 |
在 JavaScript 中,undefined、null、""、0、NaN 和 false 这 6 个特殊值转换为布尔值时为 false,被称为假值。除了假值以外,其他任何类型的数据转换为布尔值时都是 true。
包括狭义的对象、数组和函数。
console.log(typeof 1); //返回字符串"number" console.log(typeof "1"); //返回字符串"string" console.log(typeof true); //返回字符串"boolean" console.log(typeof {}); //返回字符串"object" console.log(typeof []); //返回字符串"object" console.log(typeof function(){}); //返回字符串"function" console.log(typeof null); //返回字符串"object" console.log(typeof undefined) ; //返回字符串"undefined"
typeof 运算符以字符串的形式返回 6 种基本类型之一,不过通过比较可以发现,typeof 返回值与上表存在两点差异,简单说明如下:
这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。
那么如何判断Null类型??
function typeOf(o){ return (o === null) ? "null" : (typeof o); }
在 ECMAScript 5 中,字符串允许多行表示。实现方法:在换行结尾处添加反斜杠\。反斜杠和换行符不作为字符串直接量的内容。
var str1 = "学而不思则罔", str2 = "思而不学则殆", string = str1 + "," + str2; document.write(string); //显示“学而不思则罔,思而不学则殆” document.write(string.length); //显示 13
在 ECMAScript 5 中,字符串可以作为只读数组使用。除了使用 charAt() 访问其中的字符外,还可以使用中括号运算符来访问。位置下标从 0 开始,最大位置下标为 length-1。
var str = "学而不思则罔,思而不学则殆"; for(var i=0; i<str.length; i++){ console.log(str[i]); }
JavaScript 中的所有数字都是以 64 位浮点数形式存储,包括整数。例如,2 与 2.0 是同一个数。
0.1+0.2 并不等于 0.3???
num = 0.1+0.2; //0.30000000000000004
这是因为 JavaScript 遵循二进制浮点数算术标准(IEEE 754)而导致的问题。这个标准适合很多应用,但它违背了数字基本常识。
解决方法:浮点数中的整数运算是精确的,所以小数表现出来的问题可以通过指定精度来避免。例如,针对上面的相加可以这样进行处理。
a = (1+2)/10; //0.3
NaN是一个特殊数值.
当试图将非数字形式的字符串转换为数字时,就会生成 NaN。
当 NaN 参与数学运算时,运算结果也是 NaN。因此,如果表达式的运算值为 NaN,那么可以推断其中至少一个运算数是 NaN。
typeof 不能分辨数字和 NaN,并且 NaN 不等同于它自己。
使用 isNaN() 全局函数可以判断 NaN。
toString() 方法可以根据所传递的参数把数值转换为对应进制的数字字符串
undefined 是 Undefined 类型的唯一值,它表示未定义的值。当声明变量未赋值时,或者定义属性未设置值时,默认值都为 undefined。
不管是声明的变量,还是未声明的变量,都可以通过 typeof 运算符检测变量是否初始化。对于未声明的变量 b 来说,如果直接在表达式中使用,会引发异常。
var a; console.log(typeof a); //返回"undefined” console.log(typeof b); //返回"undefined" console.log(b == undefined); //提75未定义的错误信息 function f(){} console.log(f()); //返回"undefined"
undefined 隐含着意外的空值,而 null 隐含着意料之中的空值。因此,设置一个变量、参数为空值时,建议使用 null,而不是 undefined。
JavaScript 支持把十进制数值转换为二进制、八进制和十六进制等不同进制的数值。
1.ECMAscript5 新增了严格运行模式。推出严格模式的目的如下:
2.在代码首部添加以下一行字符串,即可启用严格模式。
"use strict"
首部就是指其前面没有任何有效的 JavaScript 代码。注释语句不作为有效的 JavaScript 代码。
不支持严格模式的浏览器会把它作为字符串直接量忽略掉。
3.严格模式的应用场景
全局模式不利于 JavaScript 文件合并。例如,如果一个开启了严格模式的 JavaScript 库,被导入到一个正常模式的网页脚本中,由于无法确保 "use strict" 位于脚本的首部位置,容易导致严格模式失效。因此,推荐的最佳实践是使用局部模式,将整个 JavaScript 文件脚本放在一个立即执行的匿名函数中,在匿名函数内启动严格模式。当 JavaScript 库文件被导入到不同模式的网页中,就不用担心严格模式失效了。
(function(){ "use strict"; // JavaScript库文件 代码 }) ();
使用 constructor
constructor 是 Object 类型的原型属性,它能够返回当前对象的构造器(类型函数)。利用该属性,可以检测复合型数据的类型,如对象、数组和函数等。
var o = {}; var a =[]; if (o.constructor == Object) document.write("o 是对象"); if (a.constructor == Array) document.write("a 是数组");
使用 toString
toString 是 Object 类型的原型方法,它能够返回当前对象的字符串表示。利用该属性,可以检测复合型数据的类型,如对象、数组、函数、正则表达式、错误对象、宿主对象、自定义类型对象等;也可以对值类型数据进行检测。
不同类型对象调用 toString() 方法时返回的字符串格式并不统一,这是因为不同类型的子类在继承 Object 的原型方法 toString,时重写了该方法。如果在对象上调用 Object 的原型方法 toString(),就会返回统一格式的字符串表示。
var o = {}; //对象 var a = [1,2]; //数组 var f = function(){}; //函数 console.log(o.toString()); //表示为 "[object Object]" console.log(a.toString()); //表示为 "1,2" console.log(f.toString()); //表示为 "function (){}" var _toString = Object.prototype.toString; //引用 Objget 的原型方法 toString () //使用 apply 方法在对象上动态调用 Object 的原型方法 toString () console.log(_toString.apply(o)); //表示为 "[object Object]" console.log(_toString.apply(a)); //表示为 "[object Array]" console.log(_toString.apply(f)); //表示为 "[object Function]"
下面是比较完整的数据类型检测函数。
//强健的数据类型检测工具函数 //参数:obj 表示待检测的值 //返回值:返回字符串表示,格式与 typeof 运算符相同, //"undefined" "number" "boolean" "string" "function" //"regexp" "array" "date" "error" "object"或 "null" function typeOf(obj){ var _toString = Object.prototype.toString; //引用 Object 的原型方法 toString () //列奉所有可能的类型字符串表示 //模仿typeof运算符返回值,通过映射,统一字符串表示的值 var _type ={ "undefined" : "undefined", "number" : "number", "boolean" : "boolean", "string" : "string", "[object Function]" : "function0f", "[object RegExp]" : "regexp", "[object Array] " : "array", "[object Date]" : "date", "[object Error]" : "error" //在这里可以继续展开要检测的类型 } //把值转换为字符串表示,然后匹配 _type 对象中的键值对,最后处理特殊值 null return _type[typeof obj] || _type[_toString.call(obj)] || (obj ? "object" :"null"); }
转换为字符串
当值与空字符串相加运算时,JavaScript 会自动把值转换为字符串。
转换为数字模式字符串
toString() 是 Object 类型的原型方法,Number 子类继承该方法后,重写了 toString(),允许传递一个整数参数,设置显示模式。数字默认为十进制显示模式,通过设置参数可以改变数字模式。
如果省略参数,则 toString() 方法会采用默认模式,直接把数字转换为数字字符串。
如果设置参数,则 toString() 方法会根据参数把数值转换为对应进制的值之后,再输出为字符串表示。
转换为小数格式字符串
toFixed()
toFixed() 能够把数值转换为字符串,并显示小数点后的指定位数。
toExponential()
toExponential() 方法专门用来把数字转换为科学计数法形式的字符串。
toPrecision()
toPrecision() 方法与 toExponential() 方法相似,但它可以指定有效数字的位数,而不是指定小数位数。
转换为数字
parseInt() 是一个全局方法,它可以把值转换为整数。转换的过程如下:
parseInt() 也支持基模式,可以把二进制、八进制、十六进制等不同进制的数字字符串转换为整数。基模式由 parseInt() 函数的第二个参数指定。
parseFloat() 的参数必须是十进制形式的字符串,而不能使用八进制或十六进制的数字字符串。同时,对于数字前面的 0(八进制数字标识)会忽略,对于十六进制的数字将返回 0。
如果变量乘以 1,则变量会被 JavaScript 自动转换为数值。乘以 1 之后,结果没有发生变化,但是值的类型被转换为数值。如果值无法被缓缓为合法的数值,则返回 NaN。
转换为布尔值
使用双重逻辑非
一个逻辑非运算符!可以把值转换为布尔值并取反,两个逻辑非运算符就可以把值转换为正确的布尔值。
使用 Boolean() 函数
使用 Boolean() 函数可以强制把值转换为布尔值。
转换为对象
使用 new 命令调用 String,Number,Boolean 类型函数执行实例化操作,并把值“123”传进去,使用 new 运算符创建实例对象,简单值分别被封装为字符串型对象、数值型对象和布尔型对象。
var n = "123"; console.log(typeof new String(n)); //返回Object console.log(typeof new Number(n)); //返回Object console.log(typeof new Boolean(n)); //返回Object console.log(Object.prototype.toString.call(new String(n))); //返回 [object String] console.log(Object.prototype.toString.call(new Number(n))); //返回 [object Number] console.log(Object.prototype.toString.call(new Boolean(n))); //返回 [object Boolean]
强制类型转换
JavaScript 支持使用以下函数进行强制类型转换。