1、运算符
(1)赋值运算符
一个 赋值运算符(assignment operator) 将它右边操作数的**值**赋给它左边的操作数。最简单的赋值运算符是等于(=),它将右边的操作数值赋给左边的操作数。那么 x = y 就是将 y 的值赋给 x。
=
+=
-=
*=
/=
(2)算术运算符
算术运算符使用数值(字面量或者变量)作为操作数并返回一个数值。标准的算术运算符就是加减乘除(+ - * /)。
当操作数是浮点数时,这些运算符表现得跟它们在大多数编程语言中一样(特殊要注意的是,除零会产生Infinity)。
除了标准的算术运算符(+, - ,* /),JavaScript还提供了下表中的算术运算符。
%
:求余,返回相除之后的余数。++
:自增--
:自减- -:返回操作数的负值
- +:如果操作数在之前不是number,试图将其转换为number
- **:指数运算符
2 ** 3
returns8
10 ** -1
returns0.1
(2)逻辑运算符
逻辑运算符常用于布尔(逻辑)值之间; 当操作数都是布尔值时,返回值也是布尔值。 不过实际上&&和||返回的是一个特定的操作数的值,所以当它用于非布尔值的时候,返回值就可能是非布尔值。
&&
||
!
短路求值:
作为逻辑表达式进行求值是从左到右,它们是为可能的“短路”的出现而使用以下规则进行测试:
false
&& anything // 被短路求值为falsetrue
|| anything // 被短路求值为true
逻辑的规则,保证这些评估是总是正确的。请注意,上述表达式的anything
部分不会被求值,所以这样做不会产生任何副作用。
(3)比较运算符
= // 赋值运算符
== // 等于(类型不一样,值一样,也会判断true
=== // 绝对等于(类型一样,值一样)
- 这是js的一个缺陷,坚持不要使用 == 比较
- NaN 和任何值都不相等,包括自身,只能通过 isNaN(NaN) 来判断这个数是否是NaN
- 浮点数问题:
null 和 undefined
- null 空
- undefined 未定义
(4)字符串运算符
除了比较操作符,它可以在字符串值中使用,连接操作符(+)连接两个字符串值相连接,返回另一个字符串,它是两个操作数串的结合。
var myString = "alpha";
myString += "bet"; // 返回 "alphabet"
(5)逗号运算符
逗号操作符(,)对两个操作数进行求值并返回最终操作数的值。它常常用在 for 循环中,在每次循环时对多个变量进行更新。
例如
- 假如 a 是一个二维数组,每个维度各有10个元素,以下代码利用逗号操作符来同时改变两个变量的值。
- 这段代码的功能是打印出该二维数组的对角线元素的值:
var x = [0,1,2,3,4,5,6,7,8,9]
var a = [x, x, x, x, x];
for (var i = 0, j = 9; i <= j; i++, j--)
console.log('a[' + i + '][' + j + ']= ' + a[i][j]);
结果:
a[0][9]= 9
a[1][8]= 8
a[2][7]= 7
a[3][6]= 6
a[4][5]= 5
(6)一元操作符
delete
- delete操作符,删除一个对象的属性或者一个数组中某一个键值
- 如果 delete 操作成功,属性或者元素会变成 undefined。
- 删除数组中的元素时,数组的长度是不变的,例如删除a[3], a[4],a[4]和a[3] 仍然存在变成了undefined。
typeof
- typeof 操作符返回一个表示 operand 类型的字符串值。operand 可为字符串、变量、关键词或对象,其类型将被返回。
void
- void运算符表明一个运算没有返回值。
- 如下创建了一个超链接文本,当用户单击该文本时,不会有任何效果。
<a href="javascript:void(0)">Click here to do nothing</a>
(7)关系操作符
in
- in操作符,如果所指定的属性确实存在于所指定的对象中,则会返回true
// Arrays
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees; // returns true
3 in trees; // returns true
6 in trees; // returns false
"bay" in trees; // returns false (you must specify the index number,
// not the value at that index)
"length" in trees; // returns true (length is an Array property)
// Predefined objects
"PI" in Math; // returns true
var myString = new String("coral");
"length" in myString; // returns true
// Custom objects
var mycar = {make: "Honda", model: "Accord", year: 1998};
"make" in mycar; // returns true
"model" in mycar; // returns true
instanceof
- 如果所判别的对象确实是所指定的类型,则返回
true
。 - 当你需要确认一个对象在运行时的类型时,可使用
instanceof
- 如果所判别的对象确实是所指定的类型,则返回
(7)运算符优先级
运算符的优先级,用于确定一个表达式的计算顺序。在你不能确定优先级时,可以通过使用括号显式声明运算符的优先级。
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 | , |
2、流程控制
(1)if else
let age = 3;
if (age >= 18){
console.log("成年人");
}else if (age >= 12){
console.log("青少年");
}else{
console.log("儿童");
}
(2)switch
<script>
let err = 0;
switch(err){
case 0:
console.log('请求错误');
break;
case 1:
console.log("请求超时");
break;
case 2:
console.log("请求成功");
break;
default:
console.log("未知错误");
break;
}
</script>
<script>
let age = 0;
switch(true){
case age >=18 && age < 65:
console.log('青壮年');
break;
case age >= 12 && age < 18:
console.log("青少年");
break;
case age >=3 && age < 12:
console.log("儿童");
break;
case age < 3:
console.log("婴幼儿");
break;
default:
console.log("退休了");
break;
}
</script>
(3)三元表达式
Boolean(条件)? A : B
// 如果Boolean(gender)则输出女,否则输出男。
Boolean(gender)? '女': '男';
(3)for循环
循环三条件:
- 初始条件:数组索引的引用(i= 0)
- 循环条件:为真则执行循环体(i < arr.length)
- 更新条件:必须要有,否则进入死循环(i++)
①、for循环
for(let i=0; i< 100; i++){
console.log(i)
}
let age = [12, 3, 45, 24, 53, 32, 56, 45, 67];
②、while循环
var num = 0;
while(num <= 100){
console.log(num);
num++;
}
do{
console.log(num);
num++;
}while(num < 100)
③、for of 循环
ES6语法糖,类似python
let age = [12, 3, 45, 24, 53, 32, 56, 45, 67];
for (let num of age){
console.log(num);
}
④、for in 循环
对象遍历用 for…in
let age = [12, 3, 45, 24, 53, 32, 56, 45, 67];
for (let num in age){
console.log(num); // num 是age的索引
console.log(age[num]); // 输出值
}
let obj = {
id:1,
username: 'xiaoniu',
'max salary': 123456,
};
for (var key in obj){
console.log(key); // key obj
console.log(obj[key]); // 输出值
}
3、函数
对于重复的计算过程,可以考虑函数进行封装,实现“代码复用”。
(1)函数的声明和调用
这部分基础语法(一)中已有。
(2)匿名函数
匿名函数有两种:
- 第一种:函数是一次性的,称为立即调用函数, IIFE
- 将声明与调用二合一
(function(a,b){
console.log(a+b);
})(10,50);
- 第二种:函数不是一次性的,可以使用函数表达式
- 将匿名函数当成值赋给一个变量
- 调用方式:通过变量
let getUserName = function(username){
return "Hello" + username;
}
console.log(getUserName('小牛同学'));
- 第三种:箭头函数
- 用于简化匿名函数
// 命名函数
function sum(a, b){
return a + b
}
// 匿名函数
let add1 = function(a, b){
return a + b
}
// 箭头函数
let add2 = (a, b)=>{
console.log(a + b)
}
转化方法:
- 去掉function
- 在参数列表与大括号之间使用 =>
// 如果函数体只有一条语句,**大括号**可以不写
<script>
let sum = (a, b)=>a+b;
let res = sum(23, 342);
console.log(res); // 结果为:365
</script>
<script>
let sum = (a, b)=>console.log(a+b);
sum(23, 342); // 结果为:365
</script>
// 如果参数只有一个,那么**参数的括号**也可以不写
add = a => a+5;
console.log(add(34, 42));
// 但是没有参数时,括号必须写
add = ()=>15+3;
console.log(add());
补充
- 胖箭头:=>
- 瘦箭头:→
(3)函数传参
①、参数不足时,可以设置默认参数
参数不足时,可以设置默认参数
function sum1(num1, num2){
let total = 0;
total = num1 + num2;
console.log("total =", total);
}
sum1(12, 34);
sum1(23); // 输出: NaN,原因是由于参数不足。
//对于参数不足可以设置一个默认参数
function sum2(num1, num2=0){
let total = 0;
total = num1 + num2;
console.log("total =", total);
}
sum2(23);
- function: 函数声明的关键字
- sum1:函数名称
- (num1, num2): 参数列表
- (12, 34):调用参数,实际参数(实参),与上面参数列表中的参数一一对应。
③、参数过多时,可以使用rest语法
对于传入函数参数过多的情况,可以使用 rest语法 来解决,这种方式叫做归内参数/剩余参数/不定参数,将多余参数压到一个数组参数中。
function sum3(...args){
console.log(args); // 输出:[23, 34, 545, 7, 23]
}
sum3(23,34,545,7,23);
①、将 … 用在函数的形参中,就是rest,归并操作,把多余的参数压到一个数组中。
<script>
let f = (a,b,...c)=>console.log(a,b,c);
f(1,2,3,4,5,6); // 输出: 1 2 [3, 4, 5, 6]
</script>
②、将 … 用在函数的调用参数中,就是扩展/展开,spread。
let f = (a,b,...c)=>console.log(a,b,c);
f(1,2,3,4,5,6);
const arr = [12,45,67,76,34]
f(...arr)
(4)函数的返回值
函数只能有一个返回值,默认单值返回。
如果需要返回多个值呢?
- 可以使用数组或者对象
<script>
let fn = () => [1,2,3]
let res = fn();
console.log(res);
fn = () =>({
id:2,
name:'admin',
age:'23',
});
console.log(fn());
</script>
(5)作用域
作用域分为:全局作用域、函数作用域,还有块作用域(块作用域不常用)。
// 块作用域
{
let a = 1;
console.log(a);
}
console.log(a);
①、函数作用域
函数作用域,即为在函数里边的变量。
②、全局作用域
全局作用域,即在函数外边的变量。
注:
函数里可以调用函数外的变量,但是函数外不能调用函数内的变量。
如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:
这说明JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。
function foo() {
var x = 1;
function bar() {
var x = 'A';
console.log('x in bar() = ' + x);
}
console.log('x in foo() = ' + x); // 1
bar(); // 'A'
console.log('x in foo() = ' + x); // 1
}
foo();
// 输出:
x in foo() = 1
x in bar() = A
x in foo() = 1
作用域链:作用域链用于查询变量。作用域链的内容是:查询变量的时候,先从函数内部查询,如果有就直接访问,如果没有则向上一个作用域查询,一级一级向上,直到全局作用域。
作用域链的特点:
- 单向的。
- 由外向内传递可以,但是由内向外禁止。
(6)闭包
闭包的两个条件:
- 父子函数
- 自由变量
<body>
<script>
function parent() {
let a = 5;
function f(b) {
let c = 7;
return a + b + c;
}
return f;
}
console.log(parent());
const f1 = parent();
console.log(f1);
console.log(f1(3));
</script>
</body>
以下代码中 a 是子函数f 的自由变量。
<body>
<script>
function parent1(a) {
function f(b) {
let c = 7;
return a + b + c;
}
return f;
}
// 这时候,在外部调用 parent1() 会返回一个函数,此时闭包就产生了。
console.log(parent1(4));
// parent1() 调用结束,应该将空间和参数都释放的,但是由于父函数中第一个变量a 被它的一个子函数引用着,所有就不能销毁,这就会产生闭包。
const f1 = parent1(4);
console.log(f1);
console.log(f1(3));
</script>
</body>
// 如果:
const f1 = parent1();
console.log(f1(3)); // 结果为NaN,因为a缺少参数。
闭包的示例:
let counter = (function(n){return function(){return n++}})(1);
console.log(counter());
console.log(counter());
console.log(counter());
(7)对象字面量的简化
①、属性简化
<script>
let username = 'jack';
let name = 'marry';
let user1 = {
username: 'tom',
};
console.log(user1.username); // 输出:tom
let user2 = {
username: name,
};
console.log(user2.username); // 输出:marry
let user3 = {
username: username,
};
console.log(user3.username); // 输出:jack
// 简化熟悉
let user4 = {
username,
};
console.log(user4.username); // 输出:jack
</script>
当满足以下两个条件的时候,可以简化属性:
- 作用域相同:对象属性与变量处于同一作用域下面。
- 名称相同:对象属性与变量同名。
②、方法简化
<script>
let username = 'jack';
let user = {
username,
};
console.log(user.username); // 输出:jack
let user1 = {
username,
getName: function(){
return 'Hello ' + this.username;
},
};
console.log(user1.getName()) // 输出:Hello jack
// 简化方法
// 语法:省略 ": function"
let user2 = {
username,
getName(){
return 'Hello ' + this.username;
},
};
console.log(user2.getName()) // 输出:Hello jack
</script>
(8)模板字面量和模板函数
模板字面量:也叫”模板字符串”,是同义词,我觉得用”模板字面量”更直观,准确
模板函数:有的书也翻译与”标签函数”,因为它使用”模板字面量”做参数,称为”模板函数”更准确。
①、模板字符串
<script>
// 传统的输出字符串,使用双引号或者单引号
console.log("Hello World!");
// 如果要输出多行字符串,那么传统方法:
console.log("html \n" + "css\n" + "js");
// 输出表达式计算结果:
let a = 10, b=20;
console.log(a + "+" + b + "=" + (a, b))
// 使用模板字符串
// 模板字符串语法: 对变量或表达式可以使用 ${x} 来引用。
let res = `${a} + ${b} = ${a + b}`
console.log(res);
// 模板表达式可以嵌套
let gender = 0;
let res1 = `${gender? `男:${name}`: `女`}`;
console.log(res1);
</script>
注:使用插值占位符: **${}
** ,可以将变量或表达式插入到字符串中。
②、模板函数
使用模板字符串为参数的函数
例如:
alert`Hello World!`
<script>
function calc(strs, ...args){
console.log(strs);
console.log(args);
console.log(args[0] * args[1])
}
calc`数量: ${10}, 单价: ${50}`
</script>
注:
- 模板函数就是在“模板字面量”之前加一个标签/标识符,而这个标签就是一个函数名。
- 模板函数的参数是有约定的,不能乱写,第一个是字面量数组,从第二个开始才是内部的占位符参数。