欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

新手该如何学习JavaScript ?

程序员文章站 2022-05-22 13:30:27
JavaScript入门 - 01 准备工作 在正式的学习JavaScript之前,我们先来学习一些小工具,帮助我们更好的学习和理解后面的内容。 js代码位置 首先是如何编写JavaScript代码,说到这,我们首先要来说明一个需要新人们关注的点,因为我们的js是一门跨平台的语言,所以说,我们的代码 ......

javascript入门 - 01

准备工作

在正式的学习javascript之前,我们先来学习一些小工具,帮助我们更好的学习和理解后面的内容。

js代码位置

首先是如何编写javascript代码,说到这,我们首先要来说明一个需要新人们关注的点,因为我们的js是一门跨平台的语言,所以说,我们的代码可以运行在不同的平台之上。这也就导致了可能相同的代码放在不同的平台运行就会有所出入。

这里面说的平台其实被称之为宿主环境

同时,代码在不同的平台上的运行方式也有所不同。

如果运行在服务端,那么更多的时候我们需要通过命令行的形式去运行,而如果是代码运行在客户端,则需要通过启动浏览器来运行代码。

我们在学习的初期建议是在浏览器中运行代码,减少学习成本。

首先,我们的js代码可以写在script标签内部并且将script标签放在网页的任何位置。

<!doctype html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title></title>
    <script>
        // js code ...
    </script>
</head>
<body>
    <script>
        // js code ...
    </script>
</body>
<script>
    // js code ... 
</script>
</html>

在上面的代码中,我们把包含有js代码的script标签放在了head标签、body标签、和body标签之后的位置。从语法的层面来说,上面的这几种写法都是正确的。但是在本教程中较为推荐的写法是将scirpt标签放在body标签的闭合标签的后面。

<!doctype html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title></title>
</head>
<body>

</body>
<script>
    // js code ... 
</script>
</html>

推荐的原因,是因为js代码经常需要操作html标签,而放在后面可以等到html标签加载完毕之后再来执行js代码。避免因为html标签未加载而导致的报错。

而另外一种写法是将js代码完全的写在一个后缀名为.js的文件中。在需要的html文件中通过script标签引入。

<!doctype html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title></title>
</head>
<body>
    
</body>
  // 通过src属性与script标签配合引入外部的js文件
<script src="01.js"></script>
</html>

js语句

js当中的语句表示js向宿主环境发送的命令。

例如下面的语句是向页面中输出计算10 + 2的结果。

document.write(10+2);

在每一条语句的后面都带有一个分号,表示语句结束。

当然js允许我们将分号省略掉,但是无论是从代码的维护成本还是其他因素考虑,都不建议将每条语句后面的分号省略掉。

需要注意的是,如果分号前面的语句为空,则没有意义。

 ; ; ;

类似上面的语句代码是没有意义的。

注释

注释是任何编程语言当中必不可少的一环。通过注释,可以让我们开发过的代码具有更好的可读性,也能变相的提升后期代码的维护和升级速度。

一般情况下,注释的内容可以包含很多,例如参数信息代码功能使用方式等等。

js中,注释分为两种,一种是单行注释,一种是多行注释

单行注释通过//表示,一般写在语句的后面或者语句的上方。

// 这里是代码注释

多行注释通过/**/的形式来创建,一般写在代码的上方。

/*
这里是多行注释...
*/

无论你是一个js新人,还是一个成熟的老程序员,合理的应用注释都是一个非常好的习惯。

直接量

js中,直接使用的量,我们称之为叫做直接量

例如,在代码中,我们要使用10,那么这个10就是一个直接量

表达式

一般情况下,表达式需要得到一个结果。

例如10+2就是一个表达式,我们在创建这个表达式的时候,就希望得到10+2的结果。

document.write(10+2);// 通过document.write()方法将10+2这个表达式的结果输出到网页当中

输出方式

我们在编写js代码的时候,经常需要得到计算的值,用以判断得到的值与我们预期的值是否相符,所以我们需要了解下面的基本的输出方式。

// console.log() 将内容输出到浏览器的控制台
console.log(10+2);
// document.write() 将内容输出到网页当中
document.write(10+2);

通常情况下我们通过console.log()这种形式输出代码我们称之为代码打印

弹窗

js中,如果你的代码运行环境是在浏览器当中,那么就可以使用浏览器给我们提供的弹窗。

alert(10+2);
confirm(10+2);
prompt(10+2);

上述的三个弹窗只能够在运行环境为浏览器的情况下使用。

变量

我们上面说到了表达式,通过表达式能够得到计算的结果,但是如果我们计算的逻辑较为复杂,那么如果单纯的依赖表达式将会变得不那么方便。

这个时候,就可以使用变量

什么是变量呢?

我们可以把变量理解为是一个代名词或者说叫做临时的容器

我们可以把一个具体的值存入到变量中。那么此时这个变量就代表着我们这个具体的值。我们如果想要重新的使用这个值,不再需要重新的计算或者其他操作,直接使用变量就可以得到之前存储的这个值。

而想要创建一个变量(也可以说是声明一个变量),需要通过var关键字(es6中通过let声明)。

var val = 10 + 2;

在上面的代码中,我们创建了一个变量val,并且使用这个变量val存储了表达式10+2的计算结果。那么如果想要第二次使用10+2的结果,可以直接使用变量val即可。

console.log(val);// 通过console.log() 输出val,此时就可以在控制台看到10+2的结果

在我们使用变量的时候,还有一点需要理解,变量之所以叫变量,是因为变量随时可以根据我们的需要更改其中存储的值。

var a = 10;
a = 20; // 当我们重新的向变量中存储数据的时候,不需要再加var
console.log(a); // 此时再打印a结果就为20

需要注意的是,上面我们将变量a内存储的数据由10变成了20,在重新存储的过程中,我们并没有使用var,那么上面的代码就相当于我们将20的值存储到之前创建的变量a中。

而如果在重新的存储的过程中使用了var,如同下面的案例:

var a = 10; // 第一次声明变量a
var a = 20; // 再一次通过var声明变量a,并且使用了var
consoloe.log(a);

需要注意的是,虽然最后的结果和上面的打印结果相同,但是变量a本质上已经发生了变化。

如果在重新存储数据的过程中,没有在变量名前面加var,那么相当于是更改变量a中存储的值,而如果前面加了var,则相当于重新的创建了一个变量a,并且存储了20这个数据

如果采用下面的这种写法,那么重新创建的变量将会无效:

var x = 1;
var x;
x // 1

变量提升:

javascript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)

console.log(a);
var a = 1;

上面代码首先使用console.log方法,在控制台(console)显示变量a的值。这时变量a还没有声明和赋值,所以这是一种错误的做法,但是实际上不会报错。因为存在变量提升,真正运行的是下面的代码。

var a;
console.log(a);
a = 1;

最后的结果是显示undefined,表示变量a已声明,但还未赋值。

标识符

标识符(identifier)指的是用来识别各种值的合法名称。最常见的标识符就是变量名,以及后面要提到的函数名。javascript 语言的标识符对大小写敏感,所以aa是两个不同的标识符。

标识符有一套命名规则,不符合规则的就是非法标识符。javascript 引擎遇到非法标识符,就会报错。

简单说,标识符命名规则如下。

  • 第一个字符,可以是任意 unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
  • 第二个字符及后面的字符,除了 unicode 字母、美元符号和下划线,还可以用数字0-9

下面这些都是合法的标识符。

arg0
_tmp
$elem
π

下面则是一些不合法的标识符:

1a  // 第一个字符不能是数字
23  // 同上
***  // 标识符不能包含星号
a+b  // 标识符不能包含加号
-d  // 标识符不能包含减号或连词线

需要注意的是,在js当中,中文也是合法的标识符,但是并不推荐使用。

javascript 有一些保留字,不能用作标识符:arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。

数据类型

变量用来临时存储数据(如果想要永久的存储数据,需要通过数据库)。而在任何一门编程语言当中,数据都是分为不同类型的。就如同人类也分为男人和女人一样。

下面就来说一下在javascript中数据的不同类型。

js当中数据类型分为两类,一类是原始类型,一类是引用数据类型原始类型又称之为基础数据类型引用类型也称之为对象类型

原始类型的数据包含有下面几个:

  • boolean
  • null
  • undefined
  • number
  • string
  • symbol(es6中新增加的内容)

引用类型的数据包含有下面几个:

  • object
  • array
  • function

js当中,引用类型也包括datemathregexp等内容。

需要注意的是,js当中的原始值并不能够更改,也就意味着一旦一个原始值创建成功。那么将不能够进行第二次的值得修改,除非重新创建一个数据。

boolean

in computer science, a boolean is a logical data type that can have only the values true or false. for example, in javascript, boolean conditionals are often used to decide which sections of code to execute (such as in if statements) or repeat (such as in for loops).

mdn中,对于javascript中的布尔值(boolean)有上面一段描述,翻译过来的意思大致如下:

在计算机科学中,布尔值是一种逻辑数据类型,其值只能为真或假。例如,在javascript中,布尔条件
常用于决定执行哪一部分代码(例如在if语句中)或重复(例如在for循环中)。

布尔值包含有两个值truefalse。其中true表示false表示

例如我们判断一个条件,如果这个条件满足,那么对应着布尔值true,如果这个条件不满足,那么就对应着布尔值false

下列运算符会返回布尔值:

  • 前置逻辑运算符: ! (not)
  • 相等运算符:===!====!=
  • 比较运算符:>>=<<=

如果 javascript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true

  • undefined
  • null
  • false
  • 0
  • nan
  • ""''(空字符串)

null

in computer science, a null value represents a reference that points, generally intentionally, to a nonexistent or invalid object or address. the meaning of a null reference varies among language implementations.

in javascript, null is one of the primitive values.

译文:

在计算机科学中,空值表示一个引用,该引用通常有意指向不存在或无效的对象或地址。空引用的含义因语言实现而异。

在javascript中,null是一个基本值(原始数据)。

null类型里面只有一个值,就是null
关于null,你可以把它理解为,它表示一个空值。

var a = null; 

例如上面的代码当中,你可以理解为此事的变量a表示的值为空。

当我们在一些需要传递值的地方,如果我们没有值进行传递,那么就可以传递一个null,表示传递的值为空。

undefined

undefined类型当中只有一个值就是undefined

在代码的编写过程中,一个没有被赋值的变量的类型就是undefined

var a;
console.log(a); // 会在浏览器的控制台中输出undefined

如果一个变量声明但是没有被赋值,我们就可以使用typeof运算符来检查一下结果.

var a;
console.log(typeof a);// 输出undefined类型

number

number类型即为数字类型

mdn中关于number类型的描述如下:

根据 ecmascript 标准,javascript 中只有一种数字类型:基于 ieee 754 标准的双精度 64 位二进制格式的值(-(263 -1) 到 263 -1)。它并没有为整数给出一种特定的类型。除了能够表示浮点数外,还有一些带符号的值:+infinity-infinity 和 nan (非数值,not-a-number)。

javascript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,11.0是相同的,是同一个数。

1 === 1.0 // true

这就是说,javascript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 javascript 会自动把64位浮点数,转成32位整数,然后再进行运算。

由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。

0.1 + 0.2 === 0.3
// false

0.3 / 0.1
// 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)
// false

数值范围:

根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 javascript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。

如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 javascript 无法表示这么大的数,这时就会返回infinity

如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 javascript 无法表示这么小的数,这时会直接返回0。

math.pow(2, -1075) // 0

下面是一个实际的例子。

var x = 0.5;

for(var i = 0; i < 25; i++) {
  x = x * x;
}

x // 0

上面代码中,对0.5连续做25次平方,由于最后结果太接近0,超出了可表示的范围,javascript 就直接将其转为0。

而如果在js小于-1.7976931348623157e+103088 的时候,就会表示为-infinity.

number当中的特殊值:

1、正零和负零

javascript 的64位浮点数之中,有一个二进制位是符号位。这意味着,任何一个数都有一个对应的负值,就连0也不例外。

javascript 内部实际上存在2个0:一个是+0,一个是-0,区别就是64位浮点数表示法的符号位不同。它们是等价的。

-0 === +0 // true
0 === -0 // true
0 === +0 // true

几乎所有场合,正零和负零都会被当作正常的0

+0 // 0
-0 // 0
(-0).tostring() // '0'
(+0).tostring() // '0'

但是当0-0被充当分母的时候,返回的值是不相等的。

(1 / +0) === (1 / -0) // false

上面的代码之所以出现这样结果,是因为除以正零得到+infinity,除以负零得到-infinity,这两者是不相等的。

2、nan

nan是 javascript 的特殊值,表示“非数字”(not a number),主要出现在将字符串解析成数字出错的场合。

console.log(5 - 'x'); //nan

需要注意的是,nan不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于number,使用typeof运算符可以看得很清楚。

需要注意,nan是一个非常的角色,它连自己都不认,也就是说,如果你判断nan是否等于nan,答案是否定的,也就是false,二者根本不想等。

3、infinity

infinity表示为无穷大。在js中,如果数值的内容超过了js所能表示的范围,就会输出infinity或者-infinity

number当中的全局方法:

1、parseint()

parseint方法用于将字符串转为整数。

parseint('123') // 123

如果字符串头部有空格,空格会被自动去除。

parseint('   81') // 81

如果parseint的参数不是字符串,则会先转为字符串再转换。

parseint(1.23) // 1
// 等同于
parseint('1.23') // 1

字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。

parseint('8a') // 8
parseint('12**') // 12
parseint('12.34') // 12
parseint('15e2') // 15
parseint('15px') // 15

上面代码中,parseint的参数都是字符串,结果只返回字符串头部可以转为数字的部分。

如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回nan

parseint('abc') // nan
parseint('.3') // nan
parseint('') // nan
parseint('+') // nan
parseint('+1') // 1

所以,parseint的返回值只有两种可能,要么是一个十进制整数,要么是nan

2、parsefloat()

parsefloat方法用于将一个字符串转为浮点数。

parsefloat('3.14') // 3.14

如果字符串符合科学计数法,则会进行相应的转换。

parsefloat('314e-2') // 3.14
parsefloat('0.0314e+2') // 3.14

如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。

parsefloat('3.14more non-digit characters') // 3.14

parsefloat方法会自动过滤字符串前导的空格。

parsefloat('\t\v\r12.34\n ') // 12.34

如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回nan

parsefloat([]) // nan
parsefloat('ff2') // nan
parsefloat('') // nan
parsefloat('1avc') // 1
parsefloat('a1') // nan

上面代码中,尤其值得注意,parsefloat会将空字符串转为nan

这些特点使得parsefloat的转换结果不同于number函数。

parsefloat(true)  // nan
number(true) // 1

parsefloat(null) // nan
number(null) // 0

parsefloat('') // nan
number('') // 0

parsefloat('123.45#') // 123.45
number('123.45#') // nan

3、isnan()

isnan方法可以用来判断一个值是否为nan

isnan(nan) // true
isnan(123) // false

但是,isnan只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成nan,所以最后返回true,这一点要特别引起注意。也就是说,isnantrue的值,有可能不是nan,而是一个字符串。

isnan('hello') // true
// 相当于
isnan(number('hello')) // true

4、isfinite()

isfinite方法返回一个布尔值,表示某个值是否为正常的数值。

isfinite(infinity) // false
isfinite(-infinity) // false
isfinite(nan) // false
isfinite(undefined) // false
isfinite(null) // true
isfinite(-1) // true

除了infinity-infinitynanundefined这几个值会返回falseisfinite对于其他的数值都会返回true

string

0个或者任意多个字符排列起来放在单引号或者双引号当中,就是一个字符串(string)

var a = "hello,world!";
var b = 'hello,javascript!';

上面的变量ab当中存储的数据就是字符串,其中一个使用了单引号,一个使用了双引号,两者都是合法的。

单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号。

'key = "value"'
"it's a long journey"

如果要在单引号字符串的内部,使用单引号,就必须在内部的单引号前面加上反斜杠,用来转义。双引号字符串内部使用双引号,也是如此。

'did she say \'hello\'?'
// "did she say 'hello'?"

"did she say \"hello\"?"
// "did she say "hello"?"

由于 html 语言的属性值使用双引号,所以很多项目约定javascript语言的字符串只使用单引号,在这套系列教程中会遵守这个约定。当然,只使用双引号也完全可以。重要的是坚持使用一种风格,不要一会使用单引号表示字符串,一会又使用双引号表示。

字符串默认只能写在一行内,分成多行将会报错。

'a
b
c'
// syntaxerror: unexpected token illegal

上面代码将一个字符串分成三行,javascript 就会报错。

如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠。

var longstring = 'long \
long \
long \
string';

longstring
// "long long long string"

上面代码表示,加了反斜杠以后,原来写在一行的字符串,可以分成多行书写。但是,输出的时候还是单行,效果与写在同一行完全一样。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错。

连接运算符(+)可以连接多个单行字符串,将长字符串拆成多行书写,输出的时候也是单行。

var longstring = 'long '
  + 'long '
  + 'long '
  + 'string';

转义字符:

反斜杠()在字符串内有特殊含义,用来表示一些特殊字符,所以又称为转义符。

需要用反斜杠转义的特殊字符,主要有下面这些。

  • \0 :null(\u0000
  • \b :后退键(\u0008
  • \f :换页符(\u000c
  • \n :换行符(\u000a
  • \r :回车键(\u000d
  • \t :制表符(\u0009
  • \v :垂直制表符(\u000b
  • \' :单引号(\u0027
  • \" :双引号(\u0022
  • \\ :反斜杠(\u005c

如果在一个正常的字符前面加了\,是没有效果的。

console.log("\a"); //输出a

运算符

在编程语言当中,运算符是处理数据的基本方法,能够根据现有的值得到新的值。

javascript当中,存在下列的运算符。

  • 赋值运算符
  • 比较运算符
  • 算数运算符
  • 位运算符
  • 逻辑运算符
  • 字符串运算符
  • 条件(三元)运算符
  • 逗号运算符
  • 一元运算符
  • 关系运算符

下面我们将逐一的来讲解不同的运算符。

这一部分很枯燥,请做好心理准备!

赋值运算符

赋值运算符(assignment operator)基于右值(right operand)的值,给左值(left operand)赋值。

在之前的内容中,我们通过下面的写法来创建变量。

var a = 10;

上面我们通过=来将右边的10存储到左边的变量a身上。而这种操作,我们在编程当中称之为赋值

=也就是赋值运算符。也可以使用链式赋值。

var a = b = c = 15;
console.log(a,b,c);//15,15,15 

顺序是从右向左的进行赋值操作。

下面的列表中包含全部的赋值运算符

  • 赋值 x = y
  • 加赋值 x += y
  • 减赋值 x -= y
  • 乘赋值 x *= y
  • 除赋值 x /= y
  • 模赋值 x %= y
  • 指数赋值 x **= y
  • 左移赋值 x <<= y
  • 右移赋值 x >>= y
  • 无符号右移赋值 x >>>= y
  • 按位与赋值 x &= y
  • 按位异或赋值 x ^= y
  • 按位或赋值 x |= y

赋值

简单的赋值运算符,把一个值赋给一个变量。为了把一个值赋给多个变量,可以以链式使用赋值运算符。

加赋值

加赋值运算符把一个右值与一个变量相加,然后把相加的结果赋给该变量。两个操作数的类型决定了加赋值运算符的行为。算术相加或字符串连接都有可能。

例如:

var x = 10;
var y = 20;
x += y;
console.log(x); 
// 相当于 
x = x + y;

减赋值

减赋值运算符使一个变量减去右值,然后把结果赋给该变量。

例如:

var x = 10;
var y = 20;
x -= y;
console.log(x); // -10 
// 相当于 
x = x - y;

乘赋值

乘赋值运算符使一个变量乘以右值,然后把相成的结果赋给该变量。

例如:

var x = 10;
var y = 20;
x *= y;
console.log(x); // 200
// 相当于
x = x * y;

除赋值

除赋值运算符使一个变量除以右值,然后把结果赋给该变量。

例如:

var a = 10;
var b = 20;
a /= b;
console.log(a);
// 相当于 
a = a / b; 

模赋值

模赋值运算符使一个变量除以右值,然后把余数交给该变量。

var x = 10;
var y = 20;
a %= b;
console.log(a);
//等同于 
a = a % b;

指数赋值

指数赋值运算符使一个变量为底数、以右值为指数的指数运算(乘方)结果赋给该变量。

例如:

var x = 2;
var y = 3;
x **= y;
console.log(x); // 8
// 相当于
x = x ** y 

剩下的放在后面说到进制的时候再来说。

比较运算符

比较运算符包括下列内容:

  • 等于 == 如果两边操作数相等时返回true。
  • 不等于 != 如果两边操作数不相等时返回true
  • 全等 === 两边操作数相等且类型相同时返回true。
  • 不全等!== 两边操作数不相等或类型不同时返回true。
  • 大于> 左边的操作数大于右边的操作数返回true
  • 大于等于>= 左边的操作数大于或等于右边的操作数返回true
  • 小于< 左边的操作数小于右边的操作数返回true
  • 小于等于<= 左边的操作数小于或等于右边的操作数返回true

=> 并不是一个运算符,而是箭头函数。

/*
下面是比较运算符的示例:
 */
// == 相等运算符
console.log(10 == 10); // true
console.log(20 == "20"); // true 

// != 不等运算符  
console.log(3 != 2); // true
console.log(2 != "hello"); // true

// === 全等
console.log(3 === 3);  // true
console.log(3 === "3"); // false  值虽然相等,但是类型不相等。

// !== 不全等
console.log(3 !== "3");  // true
console.log(3 !== 2); // true

// > 大于  
console.log(3 > 2); // true
console.log("3" > "4");  // false   

// < 小于  
console.log(2 < 1); // false
console.log(3 < 4); // true

// >= 大于等于
// <= 小于等于
console.log(2 >= 1); // true
console.log(2 >= 2); // true
console.log(3 <= 3); // true
console.log(3 <= 4); // true

算数运算符

js当中,除了提供基础的+,-,*,/以外,还提供了一些其他的运算符,下面是所有的算术运算符:

  • +加法运算
  • - 减法运算
  • *乘法运算
  • / 除法运算
  • %求余运算(求模运算)
  • ++自增运算
  • --自减运算
  • +一元正值符
  • -一元负值符
  • **指数运算符

例子:

    /*
        下面是一些算数运算符的案例:  
     */
    
    var a,b;
    a = 10;
    b = 3;

    console.log(a + b); // 13
    console.log(a - b); // 7 
    console.log(a * b); // 30 
    console.log(a / b); // 3.3333333333333335


    console.log(a % b); // 1 
    console.log(++a); // 11  自增|自减符号在前,则先运算,在使用值
    console.log(a++); // 11 自增|自减符号在后,则先使用值,在运算
    console.log(a); // 12  // 上面a++后a由11变成了12

    // 一元正值符,如果操作数不是number,则尝试着将操作数转换为number  
    var c = "3";
    console.log(+c,typeof +c); // 3 number 

    // 一元负值负,将一个值变为负数
    var d = 3;
    console.log(-d); // -3  

    var e = '3';
    console.log(-e,typeof -e); //-3 number 也起到了转换的效果

    console.log(-3 === -e); // true

    // 指数运算符
    var f = 2;
    var x = 3;

    console.log(f ** x); // 8 相当于2 的 3 次幂

逻辑运算符

逻辑运算符常用于布尔(逻辑)值之间; 当操作数都是布尔值时,返回值也是布尔值。 不过实际上&&||返回的是一个特定的操作数的值,所以当它用于非布尔值的时候,返回值就可能是非布尔值。

下面是逻辑运算符:

  • 逻辑与(&&)
  • 逻辑或(||)
  • 逻辑非(!)

逻辑与:

逻辑与&&运算符又称为且运算符,往往用于多个表达式之间的求值。

它的运算规则是:如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。

语法:

exrp1 && exrp2;

逻辑或:

逻辑或||运算符又称为或运算符,同样用于在多个表达式之间求值。

它的运算规则是:如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值。

语法:

exrp1 || exrp2

例如:

// 逻辑与
    // 当运算符的前后都为条件语句的时候,当条件同时为true,则返回true,否则返回false
    var a = 1;
    var b = 2;
    console.log(a > 0 && b > a); //true 第一个条件判断为true,第二个条件判断为true,那么整体返回true
    console.log(a > b && b > 1); // false 第一个条件判断为false,第二个条件判断为true,整体返回false
    console.log(a > 0 && b > 2); // false 第一个条件为true,第二个条件为false,整体返回false
    //
    console.log("dog" && "cat"); // cat  当运算符的前后是一个直接量的时候,如果运算符前后都为true,则返回第二个直接量   
    // 逻辑或
    console.log(a > b || b > a); //true 其中只要有一个条件成立,那么就会返回true
    console.log(a > 2 || b > 2); // false 两个条件都不成立,所以返回fasle
    // 第一个条件如果成立,那么就不会去读取后面的条件
    console.log(a > 0 || b > 2); // true 

在上面的两个逻辑运算符的使用过程中,容易造成短路效果

  • false && anything // 被短路求值为false
  • true || anything // 被短路求值为true

在上面的短路代码中,anything部分不会被求值,也就意味着不会对代码产生任何的影响。

逻辑与运算符和逻辑或的连用:

逻辑与运算符可以多个连用,这时返回第一个布尔值为false的表达式的值。如果所有表达式的布尔值都为true,则返回最后一个表达式的值。

true && 'foo' && '' && 4 && 'foo' && true
// ''

1 && 2 && 3
// 3

上面代码中,例一里面,第一个布尔值为false的表达式为第三个表达式,所以得到一个空字符串。例二里面,所有表达式的布尔值都是true,所有返回最后一个表达式的值3

运算符可以多个连用,这时返回第一个布尔值为true的表达式的值。如果所有表达式都为false,则返回最后一个表达式的值。

false || 0 || '' || 4 || 'foo' || true
// 4

false || 0 || ''
// ''

上面代码中,例一里面,第一个布尔值为true的表达式是第四个表达式,所以得到数值4。例二里面,所有表达式的布尔值都为false,所以返回最后一个表达式的值。

逻辑或运算符通常情况下用于给一个变量设置默认值。

var a = username || "zhangsan";

逻辑非:

逻辑非(!)运算符又叫取反运算符,就是取一个值的反值。主要用于将一个布尔值变为相反值。即true变为false,false变为true

如果使用取反运算符的值不是一个布尔值,那么取反运算符就会将其变为一个布尔值,然后再取反。

下面的六个值使用取反运算符取反后都为true,其他都为false

  • undefined
  • null
  • false
  • 0
  • nan
  • 空字符串('')
!undefined // true
!null // true
!0 // true
!nan // true
!"" // true

!54 // false
!'hello' // false
![] // false
!{} // false

不管什么类型的值,经过取反运算后都会变成布尔值。

如果对一个值连续做两次的取反运算,等于将其转换为对应的布尔值,与boolean函数的作用相同。这是一种较为常见的类型转换的方法。

例如:

var a = "hello";
console.log(!!a); // true 

字符串运算符

字符串运算符指的是+,通过加号,我们可以对两个字符串进行拼接从而返回一个新的字符串。

var a = "hello,";
var b = "world!";
console.log(a + b); // hello,world!

也可以采用简写的形式来拼接字符串。

var str = "hello,";
var str += "world!";
console.log(str); // hello,world!

我们也可以在使用的过程中进行数据的拼接。

var sayhello = "hello,my name is ";
console.log(sayhello + "zhangsan");// hello,my name is zhangsan

条件运算符

条件运算符也称之为三元运算符

条件运算符是javascript中唯一需要三个操作数的运算符。运算的结果根据给定条件在两个值中取其一。语法为:

条件 ? 值1 : 值2

如果条件为真,则结果取值1。否则为值2。你能够在任何允许使用标准运算符的地方使用条件运算符。

var status = (age >= 18) ? "adult" : "minor";

当 age 大于等于18的时候,将“adult”赋值给status;否则将“minor”赋值给 status

逗号运算符

逗号操作符(,)对两个操作数进行求值并返回最终操作数的值。它常常用在 for 循环中,在每次循环时对多个变量进行更新。

当然,我们在console.log()的过程中,如果输出多个值,也会用到逗号运算符。

console.log("hello","world");

一元操作符

一元操作符仅对应一个操作数。

常用的一元操作符有如下几个:

  • delete
  • typeof
  • void

delete主要用于删除对象当中的某个元素。

void主要用于表明一个运算没有返回值。

例如:

var trees = new array("redwood", "bay", "cedar", "oak", "maple");
delete trees[3]; // 删除数组当中的一个元素 

<a href="javascript:void(0)">click here to do nothing</a> // 用户点击这个链接不会有任何效果

上面的demo中的两个运算符,我们暂时还没有用到,所以可以先放在这,后面再来理解。

至于typeof运算符,主要用来查看数据的类型,将获取的数据类型以一个字符串的形式展示出来。

var a = "hello,world!";
console.log(typeof a); // "string"

var b = 13;
console.log(typeof (b)); // "number"

在上面的demo中,我们发现typeof有两种使用方式。运算符后面的括号可以选择省略或者不省略。

案例:

console.log(typeof "hello,world"); // "string"
console.log(typeof 10); // "number"
console.log(typeof true); // "boolean"
console.log(typeof false); // "boolean"
console.log(typeof null); // "object"
console.log(typeof undefined); // "undefined"

// 查看typeof返回的数据的类型
console.log(typeof typeof(10)); // "string"

关系操作符

关系操作符对操作数进行比较,根据比较结果真或假,返回相应的布尔值。

下面是关系操作符的具体内容:

  • in

  • instanceof

运算符优先级

运算符的优先级,用于确定一个表达式的计算顺序。在你不能确定优先级时,可以通过使用括号显式声明运算符的优先级

下表列出了描述符的优先级,从最高到最低。

operator type individual operators
member . []
call / create instance () new
negation/increment ! ~ - + ++ -- typeof void delete
multiply/divide * / %
addition/subtraction + -
bitwise shift << >> >>>
relational < <= > >= in instanceof
equality == != === !==
bitwise-and &
bitwise-xor ^
bitwise-or |
logical-and &&
logical-or ||
conditional ?:
assignment = += -= *= /= %= <<= >>= >>>= &= ^= |=
comma ,

数据类型转换

javascript 是一种动态类型语言,变量没有类型限制,可以随时赋予任意值。

例如:

var a = 10; // 创建一个变量a,并且赋值为10
a = "hello,world!"; // 将"hello,world"重新赋值给变量a,这样a就由number变为string

再来看下面这个案例:

var x = y ? 1 : 'a';

上面代码中,变量x到底是数值还是字符串,取决于另一个变量y的值。ytrue时,x是一个数值;yfalse时,x是一个字符串。这意味着,x的类型没法在编译阶段就知道,必须等到运行时才能知道。

虽然变量的数据类型是不确定的,但是各种运算符对数据类型是有要求的。如果运算符发现,运算子的类型与预期不符,就会自动转换类型。比如,减法运算符预期左右两侧的运算子应该是数值,如果不是,就会自动将它们转为数值。

'4' - '3' // 1

上面代码中,虽然是两个字符串相减,但是依然会得到结果数值1,原因就在于 javascript 将运算子自动转为了数值。

在章节,我们将会先来讲解手动强制类型转换数据类型,接着会说到数据类型的自动转换规则

强制类型转换

强制转换主要指使用number()string()boolean()三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。

number()

使用number函数,可以将任意类型的值转化成数值。

下面分成两种情况讨论,一种是参数是原始类型的值,另一种是参数是对象。

原始类型值:

下面通过案例来演示一下原始类型值转换为number类型的规则:

// 数值:转换后还是原来的值
number(324) // 324

// 字符串:如果可以被解析为数值,则转换为相应的数值
number('324') // 324

// 字符串:如果不可以被解析为数值,返回 nan
number('324abc') // nan

// 空字符串转为0
number('') // 0

// 布尔值:true 转成 1,false 转成 0
number(true) // 1
number(false) // 0

// undefined:转成 nan
number(undefined) // nan

// null:转成0
number(null) // 0

number函数会自动过滤一个字符串前导和后缀的空格。

对象:
简单的规则是,number方法的参数是对象时,将返回nan,除非是包含单个数值的数组。

number({a: 1}) // nan
number([1, 2, 3]) // nan
number([5]) // 5

string()

string函数可以将任意类型的值转化成字符串,转换规则如下。
(1)原始类型值

  • 数值:转为相应的字符串。
  • 字符串:转换后还是原来的值。
  • 布尔值:true转为字符串"true",false转为字符串"false"。
  • undefined:转为字符串"undefined"。
  • null:转为字符串"null"。
string(123) // "123"
string('abc') // "abc"
string(true) // "true"
string(undefined) // "undefined"
string(null) // "null"

(2)对象:

string方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。

string({a: 1}) // "[object object]"
string([1, 2, 3]) // "1,2,3"

boolean()

boolean()函数可以将任意类型的值转为布尔值。

它的转换规则相对简单:除了以下五个值的转换结果为false,其他的值全部为true

  • undefined
  • null
  • 0(包含-0+0
  • nan
  • ''(空字符串)
boolean(undefined) // false
boolean(null) // false
boolean(0) // false
boolean(nan) // false
boolean('') // false

当然,truefalse这两个布尔值不会发生变化。

boolean(true) // true
boolean(false) // false

注意,所有对象(包括空对象)的转换结果都是true,甚至连false对应的布尔对象new boolean(false)也是true

boolean({}) // true
boolean([]) // true
boolean(new boolean(false)) // true

所有对象的布尔值都是true,这是因为 javascript 语言设计的时候,出于性能的考虑,如果对象需要计算才能得到布尔值,对于obj1 && obj2这样的场景,可能会需要较多的计算。为了保证性能,就统一规定,对象的布尔值为true

自动类型转换

上面说完了强制类型转换,再来说下自动类型转换,它是以强制类型转换为基础的。

遇到以下三种情况时,javascript 会自动转换数据类型,即转换是自动完成的,用户不可见。

第一种情况,不同类型的数据互相运算。

123 + 'abc' // "123abc"

第二种情况,对非布尔值类型的数据求布尔值。

if ('abc') {
  console.log('hello')
}  

第三种情况,对非数值类型的值使用一元运算符(即+-)。

var a = "10";
console.log(+ a,typeof +a); // 10 "number"
+ {foo: 'bar'} // nan
- [1, 2, 3] // nan

自动转换的规则是这样的:预期什么类型的值,就调用该类型的转换函数。比如,某个位置预期为字符串,就调用string函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认转为数值。

由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用booleannumberstring函数进行显式转换。

自动转换为布尔值

javascript 遇到预期为布尔值的地方(比如if语句的条件部分),就会将非布尔值的参数自动转换为布尔值。系统内部会自动调用boolean函数。

因此除了以下五个值,其他都是自动转为true

  • undefined
  • null
  • +0-0
  • nan
  • ''(空字符串)

下面这个例子中,条件部分的每个值都相当于false,使用否定运算符后,就变成了true

if ( !undefined
  && !null
  && !0
  && !nan
  && !''
) {
  console.log('true');
} // true

下面两种写法,有时也用于将一个表达式转为布尔值。它们内部调用的也是boolean函数。

// 写法一
expression ? true : false

// 写法二
!! expression

自动转换为字符串

javascript 遇到预期为字符串的地方,就会将非字符串的值自动转为字符串。具体规则是,先将复合类型的值转为原始类型的值,再将原始类型的值转为字符串。

字符串的自动转换,主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。

'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"

这种自动转换很容易出错。

var obj = {
  width: '100'
};

obj.width + 20 // "10020"

上面代码中,开发者可能期望返回120,但是由于自动转换,实际上返回了一个字符10020

自动转换为数值

javascript 遇到预期为数值的地方,就会将参数值自动转换为数值。系统内部会自动调用number函数。

除了加法运算符(+)有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值。

'5' - '2' // 3
'5' * '2' // 10
true - 1  // 0
false - 1 // -1
'1' - 1   // 0
'5' * []    // 0
false / '5' // 0
'abc' - 1   // nan
null + 1 // 1
undefined + 1 // nan

上面代码中,运算符两侧的运算子,都被转成了数值。

注意:null转为数值时为0,而undefined转为数值时为nan

一元运算符也会把运算子转成数值。

+'abc' // nan
-'abc' // nan
+true // 1
-false // 0