第3章 语言基础

引言


任何语言的核心所描述的都是这门语言在最基本的层面上如何工作,涉及语法、操作符、数据类型以及内置功能,在此基础之上才可以构建复杂的解决方案

本章接下来的内容主要基于ECMAScript第6版。ES6


语法

js的语法借鉴了c/c++,java。js是相对宽松的一门脚本语言

区分大小写

js,JS是俩个不同的声明

标识符

所谓标识符,就是变量、函数、属性或函数参数的名称

标识符由下划线,数字,字符组成。第一个字符不能是数字

注释

不会被程序执行,是给程序员看的代码

// 单行注解
/ *  
	多行注解
 * /

严格模式

在js开头,或者某部分代码块中使用

"use strict";

语句

  • 加分号也便于开发者通过删除空行来压缩代码(如果没有结尾的分号,只删除空行,则会导致语法错误)
  • 加分号也有助于在某些情况下提升性能,因为解析器会尝试在合适的位置补上分号以纠正语法错误。
 let sum = a + b        // 没有分号也有效,但不推荐
 let diff = a - b;     // 加分号有效,推荐

语句可以被写在代码块中,if单个代码建议也加上大括号(方便阅读)

{
	let sum=a+b;
}

关键字与保留字

保留字简单来说就是未来的关键字

关键字与保留字是js内部的标识符有特定的功能,我们声明的标识符不能和其重名


变量

ECMAScript变量是松散类型的,意思是变量可以用于保存任何类型的数据

有3个关键字可以声明变量:var、const和let。

var关键字

此段代码声明了var类型变量名为message的变量,不给初始值的情况下js默认会给一个undefined

var message;

js中的赋值可以赋任意值包括数据类型,这就意味着数值类型可以随时改变
下述代码给message赋值hi并且为字符串类型,随后又赋值了100为数值类型

var message = "hi";
message=100;  //合法,但不推荐

1. var声明作用域

使用var操作符定义的变量会成为包含它的函数的局部变量,函数在运行完毕message会被销毁。并且只能在自己的作用域范围能够被使用

function test() {
  var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!

在函数内定义变量时省略var操作符,可以创建一个全局变量:注意:必须在调用函数后使用

只要调用一次函数test(),就会定义这个变量,并且可以在函数外部访问到。

function test() {
  message="hi";     //全局变量
}
test();
console.log(message); // "hi"
  • 在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出ReferenceError。
  • 在局部作用域中定义的全局变量很难维护,也会造成困惑

定义多个变量

var message = "hi",
    found = false,
    age = 29;

2. var声明提升

使用var声明的变量会自动提升到函数作用域的顶部

此外,反复多次使用var声明同一个变量也没有问题:

function foo() {
  console.log(age);		// undefined
  var age = 26;
}
foo();   // undefined

let 关键字

let声明的范围是块作用域,而var声明的范围是函数作用域。

if (true) {
  var name = 'Matt';
  console.log(name); // Matt
}
console.log(name);    // Matt
if (true) {
  let age = 26;
  console.log(age);    // 26
}
console.log(age);      // ReferenceError: age没有定义

let不允许同一个块作用域中出现冗余声明,如果变量名存在作用域链遵循就近原则

let a=10;
let a=20;	// erroe

1. 暂时性死区

let声明的变量不会在作用域中被提升。

// name会被提升
console.log(name); // undefined
var name = 'Matt';
// age不会被提升
console.log(age); // ReferenceError:age没有定义
let age = 26;

2. 全局声明

var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age);   // undefined

3. 条件声明

由于let的作用域是块级的可能会出现条件声明
let中根据不同的条件声明相同的变量这是没有必要的,代码也是不易理解的

if(a>10){
	let b=300;
}else{
	let b=20;
}
return b;

最好声明到外部,或者用三目运算符

let b
if(a>10){
	b=300
}else{
	b=20;
}
return b;

4. for循环中的let声明

var由于函数作用域再var循环中使用会出现问题

    for (var i = 0; i < 5; ++i) {
      // 循环逻辑
    }
    console.log(i); // 5

let的作用域是块级的所以是不会出现这个问题

const声明

const声明的变量必须给初始值

const的行为与let基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误。

const a=10;
a=100; // error

const声明的限制只适用于它指向的变量的引用,换句话说如果是个对象,你改变对象里面的值则不会报错

const obj={};
obj.name="zhangsan";

声明风格及最佳实践

  • 不使用var
  • const优先,let次之

数据类型

ECMAScript有6种简单数据类型。Undefined、Null(本质上是Object)、Boolean、Number、String和Symbol

还有一种复杂数据类型Objec

只有7种数据类型似乎不足以表示全部数据。但ECMAScript的数据类型很灵活,一种数据类型可以当作多种数据类型来使用

typeof操作符

typeof判断数据的数据类型

let message = "some string";
console.log(typeof message);     // "string"
console.log(typeof(message));    // "string"
console.log(typeof 95);           // "number"

Undefined类型

Undefined类型只有一个值,就是特殊值undefined

当使用var或let声明了变量但没有初始化时,就相当于给变量赋予了undefined值:

let message;
var t
console.log(message == undefined); // true
console.log(t== undefined); // true
  • 声明了没有赋值和没有声明是由本质区别的 虽然typeof是返回是undefined类型
  • 声明了没有赋值不会报错,没有声明使用了会报错

Null类型

Null类型同样只有一个值,即特殊值null

逻辑上讲,null值表示一个空对象指针,这也是给typeof传一个null会返回"object"的原因:

let car = null;
console.log(typeof car);   // "object"

undefined值是由null值派生而来的

console.log(null == undefined);   // true

Boolean类型

有两个字面值:true和false。

注意boolean的隐式转换
第3章 语言基础_第1张图片

Number类型

1. 整数

十进制可以直接写出来

int a=10;

八进制开头必须是0,如果值超出8进制的范围会按十进制处理,忽略0

let octalNum1 = 070;   // 八进制的56
let octalNum2 = 079;   // 无效的八进制值,当成79 处理
let octalNum3 = 08;    // 无效的八进制值,当成8 处理

十六进制开头必须是0x,十六进制数字中的字母大小写均可

let hexNum1 = 0xA;    // 十六进制10
let hexNum2 = 0x1f;   // 十六进制31

2. 浮点值

let a=10.1;

因为存储浮点值使用的内存空间是存储整数值的两倍,所以ECMAScript总是想方设法把值转换为整数

let floatNum1 = 1.;    // 小数点后面没有数字,当成整数1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数10 处理

对于非常大或非常小的数值,浮点值可以用科学记数法来表示

 let floatNum = 3.125e7;  // 等于31250000
 let num=0.0000003		 // 等于3e-7

浮点值的精确度最高可达17位小数,但在算术计算中远不如整数精确。

0.1+0.2=0.30000000000000004

3. 值的范围

ECMAScript并不支持表示这个世界上的所有数值

最小值通过Number.MIN_VALUE可以活动,最大值Number.MAX_VALUE

如果某个计算值超过这个数字会转换为无穷大(正负)无穷数值不能运算

4. NaN

表示不是一个数,在其他的语言中除0会报错

console.log(0/0);     // NaN
console.log(-0/+0);   // NaN

如果分子是非0值,分母是有符号0或无符号0,则会返回Infinity或-Infinity:

console.log(5/0);    // Infinity
console.log(5/-0);   // -Infinity

NaN与任何数值比较都等于自己

console.log(NaN == NaN); // false

isNaN来判断一个数是否为数值

把一个值传给isNaN()后,该函数会尝试把它转换为数值。某些非数值的值可以直接转换成数值

console.log(isNaN(NaN));      // true
console.log(isNaN(10));        // false,10 是数值
console.log(isNaN("10"));     // false,可以转换为数值10
console.log(isNaN("blue"));   // true,不可以转换为数值
console.log(isNaN(true));     // false,可以转换为数值1

5. 数值转换

Number()的转换规则如下

  • 布尔值,true转换为1,false转换为0。
  • 数值,直接返回。
  • null,返回0。
  • undefined,返回NaN。
  • string,如果是数值(±广)直接转换为相应十进制,空字符返回0,其他情况返回NaN
let num1 = Number("Hello world! ");   // NaN
let num2 = Number("");                  // 0
let num3 = Number("000011");          // 11
let num4 = Number(true);               // 1

parseInt()的转换规则如下

  • 布尔值,true转换为1,false转换为0。
  • 数值,整数直接返回,浮点数小数舍去
  • null,返回0。
  • undefined,返回NaN。
  • string,如果是数值(±广)直接转换为相应十进制(整数),空字符返回NaN,结尾包含字符舍去
let num1 = parseInt("1234blue");   // 1234
let num2 = parseInt("");             // NaN
let num3 = parseInt("0xA");         // 10,解释为十六进制整数
let num4 = parseInt(22.5);          // 22
let num5 = parseInt("70");          // 70,解释为十进制值
let num6 = parseInt("0xf");         // 15,解释为十六进制整数

parseFloat()的转换规则和parseInt()类似不过是带小数

第一个主要的区别是第一次出现的小数点是有效的,但第二次出现的小数点就无效了,此时字符串的剩余字符都会被忽略。"22.34.5"将转换成22.34。

parseFloat()函数的另一个不同之处在于,它始终忽略字符串开头的零,16进制直接返回0,因此不能指定底数
如果字符串表示整数则返回整数

let num1 = parseFloat("1234blue");   // 1234,按整数解析
let num2 = parseFloat("0xA");         // 0
let num3 = parseFloat("22.5");        // 22.5
let num4 = parseFloat("22.34.5");    // 22.34
let num5 = parseFloat("0908.5");     // 908.5
let num6 = parseFloat("3.125e7");    // 31250000

String类型

字符串可以使用双引号(")、单引号(')或反引号(`)标示

不过要注意的是,以某种引号作为字符串开头,必须仍然以该种引号作为字符串结尾。

let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`

1. 字符字面量

第3章 语言基础_第2张图片

	//  \u03a3由于是字面量所以被当作一个字符处理
    let text = "This is the letter sigma: \u03a3.";		// length==28

2. 字符串的特点

当操作字符串时,JavaScript 中的字符串是不可变的,这意味着对字符串的操作会创建一个新的字符串赋值,原始字符串本身不会被修改。

3. 转换为字符串

toString()方法可见于数值、布尔值、对象和字符串值。null和undefined值没有toString()方法。

let age = 11;
let ageAsString = age.toString();        // 字符串"11"
let found = true;
let foundAsString = found.toString();   // 字符串"true"

如果你不确定一个值是不是null或undefined,可以使用String()转型函数

  • 如果值有toString()方法,则调用该方法(不传参数)并返回结果。
  • 如果值是null,返回"null"。
  • 如果值是undefined,返回"undefined"。
 let value1 = 10;
 let value2 = true;
 let value3 = null;
 let value4;
 console.log(String(value1)); // "10"
 console.log(String(value2));   // "true"
 console.log(String(value3));   // "null"
 console.log(String(value4));   // "undefined"

4. 模板字面量

模板字面量保留换行字符,可以跨行定义字符串:

let myMultiLineString = 'first line\nsecond line';
let myMultiLineTemplateLiteral = `first line
second line`;
console.log(myMultiLineString);
// first line
// second line"
console.log(myMultiLineTemplateLiteral);
// first line
// second line
console.log(myMultiLineString === myMultiLinetemplateLiteral); // true

由于模板字面量会保持反引号内部的空格,因此在使用时要格外注意。格式正确的模板字符串看起来可能会缩进不当:

// 这个模板字面量在换行符之后有25 个空格符
let myTemplateLiteral = `first line
                          second line`;
console.log(myTemplateLiteral.length);   // 47
// 这个模板字面量以一个换行符开头
let secondTemplateLiteral = `
first line
second line`;
console.log(secondTemplateLiteral[0] === '\n'); // true
// 这个模板字面量没有意料之外的字符
let thirdTemplateLiteral = `first line
second line`;
console.log(thirdTemplateLiteral);
// first line
// second line

5. 字符串插值(用于md的限制用’'代替``)

字符串插值通过在${}中使用一个JavaScript表达式实现:

插值可以用于运算

const num='${1+1}'  // num==2

插值可以用于调用方法

function foo(){
	return "World"
}
console.log(`Hello, ${ foo() }! `);        // Hello, World!

插值可以用于字符拼接

const str="hello";
const stl='${str} world';  // hello world

Symbol类型

Symbol(符号)是ECMAScript 6新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。

1. 符号的基本用法

符号需要使用Symbol()函数初始化。

let sym = Symbol();
console.log(typeof sym); // symbol

调用Symbol()函数时,也可以传入一个字符串参数作为对符号的描述

 let genericSymbol = Symbol();
 let otherGenericSymbol = Symbol();
 let fooSymbol = Symbol('foo');
 let otherFooSymbol = Symbol('foo');
 console.log(genericSymbol == otherGenericSymbol);   // false
 console.log(fooSymbol == otherFooSymbol);             // false

符号没有字面量语法,这也是它们发挥作用的关键。按照规范,你只要创建Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。

2. 符号的应用场景

利用Symbol来作为对象的属性名,Symbol定义的属性无法通过Object.keys()中的方法和遍历获取,实现属性的私有

var gender = Symbol();
var person = {
    name: 'kreme',
    age: 12,
    [gender]: 'male'
}
 
Object.keys(person)   // ['name', 'age']
 
for (let p in person) {
   console.log(p)   // 分别会输出:'name' 和 'age'
}
 
Object.getOwnPropertyNames(person)   // ['name', 'age']

我们可以通过新的api获取

var gender = Symbol();
var person = {
    name: 'kreme',
    age: 12,
    [gender]: 'male'
}
// 使用Object的API
Object.getOwnPropertySymbols(person) // [[gender]]
 
// 使用新增的反射API
Reflect.ownKeys(person) // [[gender], 'age', 'title']

使用Symbol()来定义常量,利用Symbol()的唯一性来定义常量

const a = Symbol();
const b = Symbol();
const c = Symbol();

定义某个类的私有属性或方法

// 这个是a文件内定义的Login类:
const password = Symbol()
class Login {
    constructor(username, password) {
        this.username = username
        this[password] = password
    }
    checkPassword(pwd) {
        return this[password] === pwd
    }
}
export default Login;   // 对外暴露了login方法
 
// 这个是在b文件内调用a文件中的方法:
const login = new Login('admin', '123456')
login.checkPassword('123456')  // true
login.password        // 无法访问
login[password]       // 无法访问
login["password"]     // 无法访问

Object类型

ECMAScript中的对象其实就是一组数据和功能的集合。对象通过new操作符后跟对象类型的名称来创建。
开发者可以通过创建Object类型的实例来创建自己的对象,然后再给对象添加属性和方法:

let o = new Object();
let obj=new Object		// 不推荐

每个Object实例都有如下属性和方法。

  • constructor:用于创建当前对象的函数。在前面的例子中,这个属性的值就是Object()函数。
  • hasOwnProperty:用于判断当前对象实例上是否存在给定的属性,要检查的属性名必须是字符串
  • isPrototypeOf:用于判断当前对象是否为另一个对象的原型
  • propertyIsEnumerable::用于判断给定的属性是否可以使用(本章稍后讨论的)for-in语句枚举
  • toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
  • toString():返回对象的字符串表示。
  • valueOf():返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。

操作符

一元操作符

只操作一个值的操作符叫一元操作符

1. 递增/递减操作符

前缀运算符遵循先变后算,后缀运算符遵循先算后变

int num=10;
++num,num++,--num,num--

递增递减操作符对于其他类型运算的规则如下

  • 字符串如果是有效数值,先转换为数值型然后运算。非有效数值直接返回NaN
  • bool如果是true先转换为1然后运算,如果是false先转换为0然后运算
  • 如果是对象会调用其valueOf然后运算
 let obj={
     valueOf(){
         return -1;
     }
 }
console.log(obj++);			// -1
console.log(obj);		    // 0

2. 一元加和减

一元加法和减法主要可以用于类型转换
数值

int a=10;
int b=20;
+a		// 10
-b		// -20

非数值,遵循Number()的转换规律。负号一样

let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
  valueOf() {
    return -1;
  }
};
s1 = +s1;   // 值变成数值1
s2 = +s2;   // 值变成数值1.1
s3 = +s3;   // 值变成NaN
b = +b;     // 值变成数值0
f = +f;     // 不变,还是1.1
o = +o;     // 值变成数值-1

位操作符

ECMAScript中的所有数值都以IEEE 754 64位格式存储,但位操作并不直接应用到64位表示,而是先把值转换为32位整数,再进行位操作,之后再把结果转换为64位。所以我们只需要考虑32即可

有符号整数使用32位的前31位表示整数值。第32位表示数值的符号,如0表示正,1表示负。这一位称为符号位

正值以真正的二进制格式存储,即31位中的每一位都代表2的幂。第一位(称为第0位)表示20,第二位表示21,依此类推。如果一个位是空的,则以0填充

数值18的二进制格式为00000000000000000000000000010010,或更精简的10010。

第3章 语言基础_第3张图片

负值以一种称为二补数(或补码)的二进制编码存储

  • 先计算数值的绝对值,二进制存储
  • 然后所有二进制取反(补码)
  • 最后一位+1

那么,-18的二进制表示就是11111111111111111111111111101110。要注意的是,在处理有符号整数时,我们无法访问第31位。

特殊值NaN和Infinity在位操作中都会被当成0处理。如果将位操作符应用到非数值,那么首先会使用Number()函数将该值转换为数值

1. 按位非

按位非运算得到的数值要比数值加减运算效率更高,因为这是直接在操作内存

    let num1 = 25;        // 二进制00000000000000000000000000011001
    let num2 = ~num1;    // 二进制11111111111111111111111111100110
    console.log(num2);   // -26

2. 按位与

是将二进制对其比较,都是1返回,否则返回0。计算并返回最终结果

let result = 25 & 3;
console.log(result); // 1

3. 按位或

是将二进制对其比较,只要有一个1就返回1,否则返回0。计算并返回最终结果

let result = 25 | 3;
console.log(result); // 27

4. 按位异或

是将二进制对其比较,只在一位上是1的时候返回1,否则返回0。计算并返回最终结果

let result = 25 ^ 3;
console.log(result); // 26

布尔操作符

1. 逻辑非

无论应用到的是什么数据类型。逻辑非操作符首先将操作数转换为布尔值,然后再对其取反。

  • 如果是对象,返回false
  • 如果是空字符串,返回true,
  • 如果是非空字符串,返回false
  • 如果是0,返回true
  • 如果是非0,返回false
  • 如果是NaN,Null,undefined返回true
console.log(! false);    // true
console.log(! "blue");   // false
console.log(!0);         // true
console.log(! NaN);      // true
console.log(! "");        // true
console.log(!12345);    // false

同时使用!!效果和Boolean()一样

console.log(! ! "blue"); // true
console.log(! !0);        // false
console.log(! ! NaN);     // false
console.log(! ! "");      // false
console.log(! !12345);   // true

2. 逻辑与

逻辑与遵循,都真则真,否则为假

如果有操作数不是布尔值,则逻辑与并不一定会返回布尔值,而是遵循如下规则。

  • 如果第一个操作数是对象,则返回第二个操作数。
  • 如果第二个操作数是对象,则只有第一个操作数求值为true才会返回该对象。
  • 如果两个操作数都是对象,则返回第二个操作数。
  • 如果有一个操作数是null / NaN / undefined,则返回null / NaN / undefined。

逻辑与操作符是一种短路操作符,意思就是如果第一个操作数决定了结果,那么永远不会对第二个操作数求值。

	// 这里因为第一个操作符为true,所以运算到了第二个运算符又因为没有定义所以报错
    let found = true;
    let result = (found && someUndeclaredVariable); // 这里会出错
    console.log(result); // 不会执行这一行
	// 这里因为第一个操作符为false,所以结果被确定不再运算第二个操作符
    let found = false;
    let result = (found && someUndeclaredVariable);
    console.log(result); // false

3. 逻辑或

逻辑或遵循,有一个真就为真,否则为假

如果有操作数不是布尔值,则逻辑或并不一定会返回布尔值,而是遵循如下规则。

  • 如果第一个操作数是对象,则返回第一个操作数。
  • 如果第一个操作数求值为false,则返回第二个操作数。
  • 如果两个操作数都是对象,则返回第一个操作数。
  • 如果操作数都是null / NaN / undefined,则返回null / NaN / undefined。

逻辑或也有短路的特性

	// 这里因为第一个操作符为true,所以结果被确定不再运算第二个操作符
    let found = true;
    let result = (found && someUndeclaredVariable);
    console.log(result); // false
	// 这里因为第一个操作符为false,所以运算到了第二个运算符又因为没有定义所以报错
    let found = false;
    let result = (found && someUndeclaredVariable);		// 报错
    console.log(result); // 不会执行

乘性操作符

如果乘性操作符有不是数值的操作数,则该操作数会在后台被使用Number()转型函数转换为数值

1. 乘法操作符

乘法操作符遵循如下规则

  • 都是数值正常运算
  • 不是数值,先Number()转换后继续运算
  • 任何一方为NaN,返回NaN

2. 除法操作符

除法操作符遵循如下规则

  • 都是数值正常运算
  • 如果有任一操作数是NaN,则返回NaN。
  • 如果是0除以0,则返回NaN。
  • 不是数值,先Number()转换后继续运算

3. 取模操作符

取模操作符遵循如下规则

  • 都是数值正常运算
  • 不是数值,先Number()转换后继续运算
  • 如果被除数是有限值,除数是0,则返回NaN。

指数操作符

console.log(Math.pow(3, 2);     // 9
console.log(3 ** 2);              // 9
console.log(Math.pow(16, 0.5); // 4
console.log(16** 0.5);           // 4

加性操作符

1. 加法操作符

加法操作符遵循以下规则

  • 如果有任一操作数是NaN,则返回NaN;
  • 如果两个操作数都是数值
  • 如果两个操作数都是字符串,则将第二个字符串拼接到第一个字符串后面;
  • 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,再将两个字符串拼接在一起。

2. 减法操作符

加法操作符遵循以下规则

  • 如果有任一操作数是NaN,则返回NaN;
  • 如果两个操作数都是数值
  • 如果有任一操作数是字符串、布尔值、null或undefined,则先在后台使用Number()将其转换为数值,然后再根据前面的规则执行数学运算。如果是NaN直接返回
  • 如果有任一操作数是对象,则调用其valueOf()方法取得表示它的数值。如果该值是NaN,则减法计算的结果是NaN。如果对象没有valueOf()方法,则调用其toString()方法,然后再将得到的字符串转换为数值。

关系操作符

关系操作符执行比较两个值的操作,包括小于(<)、大于(>)、小于等于(<=)和大于等于(>=),用法跟数学课上学的一样。这几个操作符都返回布尔值。

关系操作符符遵循以下规则

  • 如果操作数都是数值,则执行数值比较。
  • 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。
  • 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
  • 如果有任一操作数是对象,则调用其valueOf()方法,取得结果后再根据前面的规则执行比较。如果没有valueOf()操作符,则调用toString()方法,取得结果后再根据前面的规则执行比较。
  • 如果有任一操作数是布尔值,则将其转换为数值再执行比较。

即任何关系操作符在涉及比较NaN时都返回false

相等操作符

1. 等于和不等于

这两个操作符都会先进行类型转换(通常称为强制类型转换)再确定操作数是否相等。

相等和不相等操作符遵循如下规则。

  • 如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false转换为0, true转换为1。
  • 如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。
  • 如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法取得其原始值,再根据前面的规则进行比较。
  • null和undefined相等。
  • NaN和任何值都不想等
  • 对象比较地址

2. 全等和不全等

全等和不全等操作符不存在类型的强制转换,直接是值的比较

由于相等和不相等操作符存在类型转换问题,因此推荐使用全等和不全等操作符。这样有助于在代码中保持数据类型的完整性。

3. 条件操作符

variable = boolean_expression ? true_value : false_value;

赋值操作符

=,+=,-=,…

逗号操作符

let num1 = 1, num2 = 2, num3 = 3;

语句

()中的值会自动用Boolean()转换,根据结果值执行对应语句

if语句

if (i > 25) {
  console.log("Greater than 25.");
} else if (i < 0) {
  console.log("Less than 0.");
} else {
  console.log("Between 0 and 25, inclusive.");
}

while语句

 let i = 0;
 while (i < 10) {
   i += 2;
 }

for语句

let count = 10;
for (let i = 0; i < count; i++) {
  console.log(i);
}

for-in语句

for-in语句是一种严格的迭代语句,用于枚举对象中的属性

每次执行循环,都会给变量propName赋予一个window对象的属性作为值,直到window的所有属性都被枚举一遍。

ECMAScript中对象的属性是无序的,因此for-in语句不能保证返回对象属性的顺序。换句话说,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而定

如果for-in循环要迭代的变量是null或undefined,则不执行循环体。

for (const propName in window) {
  document.write(propName);
}

for-of语句

for-of语句是一种严格的迭代语句,用于枚举对象中的属性值

与for-in用法类型

for (const el of [2,4,6,8]) {
  document.write(el);
}

break和continue语句

break跳出临近循环
countinue跳出本次循环

switch语句

必须加break,否则下面代码会以此执行。可以用return替代
default每次匹配都会被执行一次

switch (expression) {
  case value1:
    statement
    break;
  case value2:
    statement
    break;
  case value3:
    statement
    break;
  case value4:
    statement
    break;
  default:
    statement
}

函数

函数对任何语言来说都是核心组件,因为它们可以封装语句,然后在任何地方、任何时间执行。

function sayHi(name, message) {
  console.log("Hello " + name + ", " + message);
}

sayHi("Nicholas", "how are you today? ");

有返回值的函数

只要碰到return语句,函数就会立即停止执行并退出。因此,return语句后面的代码不会被执行

function sum(num1, num2) {
  return num1 + num2;
}
const result = sum(5, 10);

你可能感兴趣的:(前端,javascript,开发语言)