Awe JavaScript [1] 基本概念

前言

本文是 Awesome JavaScript 系列文章的第一篇,本系列文章主要为 JavaScript 的一些常见知识点,是我在 JavaScript 学习过程当中的一些笔记。javascript


JavaScript 简介

JavaScript 诞生于 1995 年,和博主同年哈哈。当时,它的主要目的是处理之前由服务器端语言(如 Perl)负责的一些输入验证操做。JavaScript 从一个简单的输入验证器发展为一门强大的编程语言,彻底出乎人们的预料。应该说,它既是一门很是简单的语言,又是一门很是复杂的语言。html

1997 年,以 JavaScript 1.1 为蓝本的建议被提交给了欧洲计算机制造商协会(ECMA,European Computer Manufacturers Association)。不久后,该协会定义了一种名为 ECMAScript 的新脚本语言的标准,即 ECMA-262。java

1998 年,ISO/IEC(International Organization for Standardization and International Electrotechnical Commission,国标标准化组织和国际电工委员会)也采用了 ECMAScript 做为标准(即 ISO/IEC-16262)。自此之后,浏览器开发商就开始致力于将 ECMAScript 做为各自 JavaScript 实现的基础,也在不一样程度上取得了成功。express

到如今呢,咱们能够说 JavaScript 是一门专为与网页交互而设计的脚本语言,他其实由如下三部分组成:编程

  • ECMAScript,由 ECMA-262 定义,提供核心语言功能。
  • 文档对象模型(DOM,Document Object Model),针对 XML 但通过扩展用于 HTML 的应用程序编程接口(API,Application Programming Interface)。提供访问和操做网页内容的方法和接口。
  • 浏览器对象模型(BOM,Browser Object Model),提供与浏览器交互的方法和接口。


在 HTML 中使用 JavaScript

JavaScript 放置位置

传统的作法是将全部的 <script> 元素都放到页面的 <head> 元素中。这样作的目的是将全部的外部文件(包括 CSS 文件和 JavaScript 文件)的引用都放在相同的地方。可是这样就意味着必须等到所有 JavaScript 代码都被下载、解析和执行完成后,才能开始呈现页面的内容(浏览器在遇到 <body> 标签时才开始呈现内容)。这种状况下的用户体验就很是的很差。数组

其实咱们能够将全部的 <script> 元素都放到页面的 <body> 元素中页面内容的后面,即 </body> 前。这样在解析包含 JavaScript 代码以前,页面的内容将彻底呈如今浏览器中。而用户也会由于浏览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。浏览器

noscript 元素

早期浏览器都面临一个特殊的问题,即当浏览器不支持 JavaScript 时如何让页面平稳退化。对这个问题的最终解决方案就是创造一个 <noscript> 元素,用以在不支持 JavaScript 的浏览器中显示替代的内容。这个元素能够包含可以出如今文档 <body> 中的任何 HTML 元素(<script> 除外)。包含在 <noscript> 元素中的内容只有在浏览器不支持脚本或浏览器支持脚本可是脚本被禁用的状况下才会显示出来。服务器

<html>
  <head>
    <title>Example HTML Page</title>
    <script type="text/javascript" defer="defer" src="example1.js"></script>
    <script type="text/javascript" defer="defer" src="example1.js"></script>
  <head>
  <body>
    <noscript>
      <p>本页面须要在浏览器支持(启用)JavaScript。</p>
    </noscript>
  </body>
</html>复制代码


基本概念

标识符

所谓标识符就是指变量、函数、属性的名字,或者函数的参数。标识符能够是按照下列格式规则组合起来的一或多个字符:编程语言

  • 第一个字符必须是一个字母、下划线 _ 或一个美圆符号 $
  • 其余字符能够是字母、下划线、美圆符号或数字;
  • 标识符中的字母能够包含扩展的 ASCIIUnicode 字母字符,但不推荐这样作。

注释

注释推荐像下面这样写:函数

// 单行注释

/*
* 这是一个多行
* (块级)注释
*/复制代码

严格模式

ECMAScript 5 引入了严格模式的概念,严格模式是为 JavaScript 定义了一种不一样的解析与操做模型。严格模式启用方法以下:

function doSomething() {
 "use strict";
  //函数体
}复制代码

"use strict"; 这行代码实际上是一个编译指示(pragma),用于高速支持的 JavaScript 引擎切换到严格模式。

变量

用 var 操做符定义的变量将成为定义该变量的做用域中的局部变量。也就是说,若是在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁。

function test() {
  var message = "hi";  //局部变量
}
test();
alert(message);       //错误!复制代码
function test() {
  message = "hi";  //全局变量
}
test();
alert(message);       //"hi"复制代码

不推荐滥用全局变量,由于在局部做用域中定义的全局变量很难维护。并且给未经声明的变量赋值在严格模式下会致使抛出 ReferenceError 的错误。

可使用一条语句定义多个变量,只要把每一个变量(初始化与否都可)用逗号分隔开便可:

var message = "hi",
    found = false,
    age = 29;复制代码

由于 ECMAScript 是松散类型的,于是使用不一样类型初始化变量的操做能够放在一条语句中完成。

注意,在严格模式下不能定义名为 evalarguments 的变量,不然会致使语法错误。

数据类型

ECMAScript 中有五种简单数据类型(基本数据类型):UndefinedNullBooleanNumberString。还有一种复杂数据类型 -- Object,在本质上,Object 是一组无序的明值对组成的。乍一看这几种数据类型不足以表示全部数据,可是 ECMAScript 数据类型具备动态性,因此没有必要再定义其余类型的数据了。

typeof 操做符

返回值 含义
"undefined" 这个值未定义
"boolean" 这个值是布尔值
"string" 这个值是字符串
"number" 这个值是数值
"object" 这个值是对象或 null
"function" 这个值是函数
var message = "some string";
alert(typeof message);    //"string"
alert(typeof (message));  //"string"
alert(typeof 95);         //"number"复制代码

上面几个例子说明,typeof 操做符的操做数能够是变量(message),也能够是数值字面量。注 -- typeof 是一个操做符。

在 JavaScript 中,null 是一个 object,即 typeof null; 返回 object。这是设计的缺陷,在最初,使用标记位来区分对象类型和原始类型,对象型用 0 标识,原始型用 1 标识。致使了全零的 null 被识别为 objectnull 被认为是一个空的对象引用,也就是一个空的对象指针。这也正是使用 typeof 操做符检测 null 值时会返回 object 的缘由。

在技术上讲,函数在 ECMAScript 中是对象,不是一种数据类型。然而函数确实也有一些特殊的属性,所以经过 typeof 操做符来区分函数和其余对象是有必要的。

Undefined 类型

在 JavaScript 中,包含 undefined 值的变量与还没有定义的变量仍是不同的。

var message;      //
alert(message);  //
alert(age);复制代码
var message;
alert(typeof message);  //"undefined"
alert(typeof age);      //"undefined"复制代码

即使未初始化的变量会自动被赋予 undefined 值,但显示的初始化变量依然是明智的选择。若是作到这一点,那么当 typeof 操做符返回 undefined 值时,咱们就知道被检测的变量是没有被声明仍是还没有初始化。

对于未声明的变量,只能执行一项操做即用 typeof 操做符检测其数据类型(未声明的变量调用 delet 不会报错,但没意义,并且在严格模式下也会报错)。

未初始化和未声明的变量的区别就是,在用 typeof 操做符检测其数据类型时都显示 undefined,可是在除此以外调用未声明的变量时就会报错。

由于在 JavaScript 中未定义和未声明的变量用 typeof 操做符检测其数据类型时都显示 undefined,因此 DOM 相关函数都是返回 null,从 API 设计角度来说是合理的。

不管什么状况下,都没有必要将一个变量的值显示的设置为 undefined

Null 类型

若是定义的变量准备在未来保存对象,那么最好将该变量初始化为 null 而不是其余值。这样只要检查 null 值就能够知道相应的变量是否已经保存了一个对象的引用,以下所示:

if(car != null) {
  //对 car 对象执行某些操做
}复制代码

因此只要意在保存对象的变量尚未真正保存对象,就应该明确地让该变量保存 null 值。

实际上,undefined 值是派生自 null 值的,所以 ECMA-262 规定对他们的相等性测试要返回 true

alert(null == undefined);      //true复制代码

Number 类型

  • 由于保存浮点数值须要的内存空间是保存整数值的两倍,因此 ECMAScript 会不失时机的将浮点数值转换为整数值。

  • ECMAScript 可以表示的数的范围为 Number.MIN_VALUE ~ Number.MAX_VALUE,在大多数浏览器中为 5e-324 ~ 1.7976931348623157e+308。当程序执行时,数值超过正负范围时会被分别转化为 Infinity-Infinity。想肯定一个数是否超出 JavaScript 数值范围,能够用 isInfinite() 函数。

var result = Number.MIN_VALUE + Number.MIN_VALUE;
alert(isFinite(result));     //false复制代码
  • NaN 即非数值(Not a Number)是一个特殊值。用于表示一个原本要返回数值的操做数未返回数值的状况(这样就不会抛出错误了)。其有两个特色,首先任何涉及 NaN 操做都会返回 NaN,这一点在多步计算中可能会致使问题。其次, NaN 与任何值都不相等,包括其自己。ECMAScript 也定义了 isNaN(); 函数。这个函数接收一个参数,这个参数能够是任何类型的,而函数会帮咱们肯定这个参数是否 不是数值。函数检查过程是 `isNaN(); => valueOf(); => toString();

  • 有三个能够把非数值转化为数值的函数:Number()parseInt()parseFloat()。在使用 parseInt() 转换数据类型时,为了不错误解析,建议不管什么时候都要明确指定基数。多数状况下咱们要解析的都是是进制数,所以始终将 10 做为第二个参数是十分必要的。

var num1 = Number("Hello world!");  //NaN
var num2 = Number("");              //0
var num3 = Number("000011");        //11
var num4 = Number(true);            //1

alert(num1);
alert(num2);
alert(num3);
alert(num4);复制代码
var num1 = praseInt("10", 2);       //2 (按二进制解析)
var num1 = praseInt("10", 8);       //8 (按八进制解析)
var num1 = praseInt("10", 10);      //10 (按十进制解析)
var num1 = praseInt("10", 16);      //16 (按十六进制解析)复制代码

parseFloat() 只解析十进制值,因此其没有第二个参数。

var num1 = parseFloat("1234blue");    //1234 - integer
var num2 = parseFloat("0xA");         //0
var num3 = parseFloat("22.5");        //22.5
var num4 = parseFloat("22.34.5");     //22.34
var num5 = parseFloat("0908.5");      //908.5
var num6 = parseFloat("3.125e7");     //31250000

alert(num1);
alert(num2);
alert(num3);
alert(num4);
alert(num5);
alert(num6);复制代码

String 类型

字符串由双引号或单引号表示均可以,在 ECMAScript 中的这两种语言形式没有什么区别。

任何字符串的长度均可以经过访问其 length 属性取得,若是字符串中包含双字节字符,那么 length 属性可能不会精确的返回字符串中的字符数目。

var text = "This is the letter sigma: \u030a.";
alert(text.length);   //输出 28复制代码

ECMAScript 中的字符串是不可变的,若是要改变某个变量保存的字符串,首先要销毁原来的字符串,而后再用另外一个包含新值的字符串填充该变量,这个过程是在后台完成的,这也就是某些旧版本浏览器在拼接字符串的时候速度很慢的缘由了。

要把一个值转换为字符串有两种方法,第一种是 toString() 方法。数值、布尔值、对象和字符串值都有相应的 toString() 方法,可是 nullundefined 值没有。通常调用 toString() 方法时不用传递参数,可是他也能够传递参数。

var age = 11;
var ageAsString = age.toString();    //the string "11"
var found = true;
var foundAsString = found.toString(); //the string "true"

alert(ageAsString);
alert(typeof ageAsString);
alert(foundAsString);
alert(typeof foundAsString);复制代码
var num = 10;
alert(num.toString());       //"10"
alert(num.toString(2));      //"1010"
alert(num.toString(8));      //"12"
alert(num.toString(10));     //"10"
alert(num.toString(16));     //"a"复制代码

在不知道要转换的值是否是 nullundefined 的状况下可使用第二种方法:转型函数 String()。使用这种方法时,若是值有 toString() 方法则会调用该方法,没有的话就按本方法规则执行。

var value1 = 10;
var value2 = true;
var value3 = null;
var value4;

alert(String(value1));     //"10"
alert(String(value2));     //"true"
alert(String(value3));     //"null"
alert(String(value4));     //"undefined"复制代码

Object 类型

ECMAScript 中的对象其实就是一组数据和功能的集合。

var o = new Object();复制代码


操做符

在 ECMAScript 中,当对数值应用位操做符时,后台发生以下的转换过程:64 位的数值被转换为 32 位数值,而后执行位操做,最后再将 32 位的结果转换回 64 位数值。可是这个转换过程会致使特殊的 NaN 和 Infinity 值应用位操做时,这两个值会被当成 0 来处理。对非数值能够先使用 Number() 函数将该值转换为一个数值,而后再应用位操做。

var num1 = 25;             //binary 00000000000000000000000000011001
var num2 = ~num1;          //binary 11111111111111111111111111100110
alert(num2);               //-26复制代码

按位非操做的本质就是操做数的负值减一。

左移操做:左移操做符为 <<,左移不会影响操做数的符号位。

var oldValue = 2;             //equal to binary 10
var newValue = oldValue << 5; //equal to binary 1000000 which is decimal 64
alert(newValue);              //64复制代码

右移操做分为有符号 >> 和无符号 >>> 两种。对于正数来讲,这两种方法的结果同样。但对于负数来讲,无符号右移是以 0 填充空位,而不是像有符号右移那样以符号位的值来填充空位。

var oldValue = -64;              //equal to binary 11111111111111111111111111000000
var newValue = oldValue >>> 5;   //equal to decimal 134217726
alert(newValue);                 //134217726复制代码

咱们能够利用逻辑或的行为特性来避免为变量赋 nullundefined 值。例如:

var myObject = preferredObject || backupObject;复制代码

上面这段代码,若是 preferredObject 的值不是 null,那么它的值将被赋给 myObject;若是是 null,则将 backupObject 的值赋给 myObject。ECMAScript 程序的赋值语句经常使用这种模式。

加性操做符有如下特性:+0+0 结果为 +0-0-0 结果为 -0+0-0 结果为 +0。若是两个操做数都是字符串,则将第二个操做数与第一个操做数拼接起来。若是只有一个操做数是字符串,则将另外一个操做数转换为字符串,而后再将两个字符串拼接起来。

var result1 = 5 + 5;     //two numbers
alert(result1);           //10
var result2 = 5 + "5";   //a number and a string
alert(result2);           //"55"复制代码
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message);    //"The sum of 5 and 10 is 510"复制代码
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message);    //"The sum of 5 and 10 is 15"复制代码

减性操做符有如下特性:+0+0 结果为 +0-0+0 结果为 -0-0+0 结果为 +0

var result1 = 5 - true;    //4 because true is converted to 1
var result2 = NaN - 1;     //NaN
var result3 = 5 - 3;       //2
var result4 = 5 - "";      //5 because "" is converted to 0
var result5 = 5 - "2";     //3 because "2" is converted to 2
var result6 = 5 - null;    //5 because null is converted to 0复制代码

相等操做符有相等 == 和不相等 !=、全等 === 和不全等 !== 两种。前者先转换再比较,后者仅比较不转换。除此以外无区别。转换指转换成数值。

var result1 = ("55" == 55);    //true ?equal because of conversion
var result2 = ("55" === 55);   //false ?not equal because different data types

var result3 = ("55" != 55);    //false ?equal because of conversion
var result4 = ("55" !== 55);   //true ?not equal because different data types

alert(null == undefined);    //true
alert(null === undefined);   //false

alert("NaN" == NaN);        //false
alert("NaN" === NaN);       //false
alert(NaN == NaN);          //false
alert(NaN === NaN);         //false
alert(NaN != NaN);          //true
alert(NaN !== NaN);         //true

alert(false == 0);          //true
alert(false === 0);         //false
alert(true == 1);           //true
alert(true === 1);          //false

alert(null == 0);           //false
alert(undefined == 0);      //false

alert(5 == "5");            //true
alert(5 === "5");           //false复制代码

注意:null == undefined 会返回 true,而 null === undefined 会返回 false,由于他们是不一样类型的值。因为相等和不相等操做符存在类型转换问题,而为了保持代码中数据类型的完整性,咱们推荐使用全等和不全等操做符。

条件操做符:

var max = (num1 > num2) ? num1 : num2;复制代码


语句

  • if 语句do-while 语句while 语句for 语句for-in 语句lable 语句break 和 continue 语句with 语句switch 语句

  • 由于 ECMAScript 中不存在块级做用域,所以在循环内部定义的变量也能够在外部访问到。例如:

var count = 10;
for (var i=0; i < count; i++){
    alert(i);
}
alert(i);    //10复制代码
  • for-in语句是一种精准的迭代语句,能够用来枚举对象属性。用法是:
for (property in wxpression) statement复制代码

下面是一个示例:这个例子循环显示 BOM 中 window 对象的全部属性。

for (var propName in window) {
  document.wright(propName);
}复制代码

若是要迭代的对象的变量值为 nullundefinedfor-in 语句会抛出错误。ECMAScript 5 已经更正了这一行为,对这种状况再也不抛出错误,而只是不执行循环体。为了保证最大限度兼容性,建议在使用 for-in 循环以前先检查确认该对象的值不是 nullundefined

  • lable 语句能够在代码中添加标签,以便未来使用。语法为:
lable: statement;复制代码

代码示例:这个例子中定义的 start 标签能够在未来由 breakcontinue 语句引用。加标签的语句通常都要与 for 语句等循环语句配合使用。

start: for (var - = 0; i < count; i++) {
}复制代码

下面这段代码使得 break 语句不只会退出内部的 for 语句,并且也会退出外部的 for 语句。

var num = 0;

outermost:
for (var i=0; i < 10; i++) {
  for (var j=0; j < 10; j++) {
    if (i == 5 && j == 5) {
      break outermost;
    }
    num++;
  }
}

alert(num);    //55复制代码
var num = 0;

outermost:
for (var i=0; i < 10; i++) {
  for (var j=0; j < 10; j++) {
    if (i == 5 && j == 5) {
        continue outermost;
    }
    num++;
  }
}

alert(num);    //95复制代码
  • with 语句的做用是将代码的做用域设置到一个特定的对象中,语法以下:
with (expression) statement;复制代码

定义 with 语句的目的是简化屡次编写同一个对象的工做,以下面的例子所示:

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;复制代码

with 语句写的话就能够简化成下面这样:

with (location) {
  var qs = search.substring(1);
  var hostName = hostname;
  var url = href;
}复制代码

注意:严格模式下不容许使用 with 语句,不然将视为语法错误。同时,大量使用这种语句会致使性能降低,同时也会给调试代码形成困难,所以在开发大型应用程序时不建议使用 with 语句。

  • switch 语句,虽然 ECMAScript 的 switch 语句是借鉴其余语言的,可是也有其特点。能够在 ECMAScript 的 switch 语句中使用任何数据类型。其次,每个 case 的值不必定是常量,能够是变量,也能够是表达式。
switch ("hello world") {
  case "hello" + " world": 
    alert("Greeting was found.");
    break;
  case "goodbye": 
    alert("Closing was found.");
    break;
  default: 
    alert("Unexpected message was found.");
}复制代码
var num = 25;
switch (true) {
  case num < 0: 
    alert("Less than 0.");
    break;
  case num >= 0 && num <= 10: 
    alert("Between 0 and 10.");
    break;
  case num > 10 && num <= 20: 
    alert("Between 10 and 20.");
    break;
  default: 
    alert("More than 20.");
}复制代码


函数

对于函数的返回值,推荐的作法是要么让函数始终都返回一个值,要么永远都不要返回值,不然,若是函数有时候返回值,有时候不返回值,会给调试代码带来不便。

ECMAScript 不介意你传递的参数个数和参数的数据类型,由于 ECMAScript 中的参数只在内部是一个数组来表示的。实际上在函数体内能够经过 arguments 对象来访问这个参数数组,从而得到传递给函数的每个参数。arguments 对象只是与数组相似但并非 Array 的实例。

没有传递值的命名参数将自动被赋予 undefined 值,这就和定义变量但为初始化相似。

在 ECMAScript 中,定义了两个名字相同的函数,则该名字只属于后定义的函数。

相关文章
相关标签/搜索