学而时习之 不亦说乎

现代JavaScript教程的基础快速笔记

发表于:2021-05-26分类:JavaScript笔记

现代模式

"use strict"; 这条指令应该出现在最前面,否则无法激活

现代 JavaScript 支持 “classes” 和 “modules”,就不需要在使用这条指令,他们默认激活

变量


let message;//声明一个变量
message = 'Hello'; // 为变量赋值

let message = 'Hello!'; // 简化为一起,定义变量,并且赋值
let user = 'John', age = 25, message = 'Hello';//同时声明并赋值多个变量

//非严格模式下可以不声明直接赋值,陋习!
name = 'tom';

变量的命名

变量名称必须仅包含字母,数字,符号 $ 和 _。
首字符必须非数字。
不能是保留关键词,list:保留关键词

常量

const name = 'tome' //常量已经产生就不能被修改了,使用时应该直接赋值

数据类型

//nimber类型 数值类型(整数或浮点数)
//Infinity 无穷大
//NaN 计算错误
//“number” 类型无法表示大于 (253-1)(即 9007199254740991),或小于 -(253-1) 的整数
let n = 123;
n=12.345

//Bigint类型 任意长度整数(很少用到)
// 尾部的 "n" 表示这是一个 BigInt 类型
const bigInt = 1234567890123456789012345678901234567890n;

//string 类型 字符串
let str = "Hello";//双引号
let str2 = 'Single quotes are ok too';//单引号
let phrase = `can embed another ${str}`;//反引号 允许将表达式和变量包在里面,用${}的方式内嵌。

//Bollean 类型 布尔值 逻辑类型
//仅包含true和false
let isGreater = 4 > 1;
alert( isGreater );//true

//null值 不属于上述任何类型
//表示未知、无、空

//undefined值 不属于上述任何类型
//和null类似,他的含义是未被赋值,简单的说就是没有操作过,未初始化。

//object类型和symbole类型
//object很特殊,其他类型只有一个单独的内容,它可以包含合集和更复杂的实体,也就是一个对象,数组也是一个对象。
//symbol 用于创建对象的唯一标识符

typeof 运算符

用于返回参数的类型

typeof undefined // "undefined"
//也支持typeof(undefined)的写法 下同
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof Math // "object" math是内建对象
typeof null // "object"  null是特殊值,其实不是对象
typeof alert // "function"  alert是个函数,其实没有函数类型,但是他会告诉你这是个函数

简单交互

let result = prompt('name','like leon');
//变量result,接收prompt返回询问name的值(like leon 是提示),如果输入,那就得到值,如果取消就是null
//ie中如果不指定第二个参数,会把undefined作为默认参数,建议始终提供第二参数哪怕是''空的
alert('name is:'+result);//弹出提示name is:XXX

let isBoss = confirm("Are you the boss?");
alert( isBoss ); // 如果“确定”按钮被按下,则显示 true 取消就是false

类型转换

和很多语言一样,js会通过运算符或函数自动转换类型,算术运算符会把值转为数字。

i = "1";
console.log(typeof i);//string
console.log(typeof(i*2));//number

//字符串转换
let value = true;
console.log(typeof(String(value)));//string

//数值型转换
console.log(typeof("9" / "3"));//number
value = "99";
console.log(typeof(Number(value)));//number,如果值无法转换,值就是nan,类型当然是number,因为nan也是数字
//undefined 变 NaN
//null 变 0
//true 和 false    1 and 0
//string    去掉首尾空格后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN。

//布尔值转换
//空 0 null undefined Nan 变 false
//其他是 true(注意"0"和" ",也是true,因为他是字符串,且含有内容0或空格,不是数值0)

基础运算符

let x = 1;
x = -x;//一元运算
let y = 2;
x = y*x//二元运算

数学运算

加减乘除:+,-,*,/

还有:%(取余),**(求幂)

5%2 //余数1
8%3 //余数2

2**2 //幂是4(2*2)
2**3 //幂是8(2*2*2)
//幂就是乘以自身的次数

二元运算符 + 连接字符串

二元运算,通常情况下+代表求和,但是如果并用于字符串他就是连接的意思,

let s = "my" + "string";
alert(s); // mystring
//2个运算元只要有一个是字符串,那另一个也是字符串
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
//需要注意,从左到右执行顺序问题
alert( 1 + 2 + '1' ); // "31" 先1+1得2,2 + '1' = "21"

只有加号有以上功能,其他运算符会将运算元转为数字

alert( 6 - '2' ); // 4,将 '2' 转换为数字
alert( '6' / '2' ); // 3,将两个运算元都转换为数字

数字转化,一元运算符+

一元运算的话+号就会将运算元转为数字,其作用和number相同,只是更简短了

// 对数字无效,因为本来就是数字
let x = 1;
alert( +x ); // 1 没有另一个运算元所以还是1

let y = -2;
alert( +y ); // -2 没有另一个运算元所以还是-2

// 转化非数字
alert( +true ); // 1 true转数字就是1
alert( +"" );   // 0 空转数值就是0


let apples = "2";
let oranges = "3";
// 替代number用法
alert( +apples + +oranges ); // 5

// 正常的写法 比较长
alert( Number(apples) + Number(oranges) ); // 5

alert( +apples + +oranges );

在这里一元运算符先于二元运算符进行了转化,一元优先有二元

运算符优先级

常识是1+2*2,是先算乘法的,这就是优先级,括号拥有更高的优先级,优先级表

= 等号也是个运算符,但是优先级很低,一般在最后用于赋值

let a = 1;
let b = 2;
//先算括号内 a=3,3-0 c=0
let c = 3 - (a = b + 1);
//因为=也是运算符所以括号内返回的实际上是a的最终值
alert( a ); // 3
alert( c ); // 0

//延伸出链式赋值
let a, b, c;
//+的优先级高于=,也就是2+2得4开始c=4,b=4,a=4
a = b = c = 2 + 2;
//实际代码是c=2+2;b=c;a=c
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4

原地修改

let n = 2;
n = n + 5;//n变7
n = n * 2;//n变14
//另一种写法

n = 2;
n += 5; // 自增5 7
n *= 2; // 自乘2 14
//这种写法优先级小于普通运算符所以
n *=3+5 //是14*8

自增自减

let counter = 2;
counter++;//自增+1 和下面效果一样,但是更简洁
++counter;//自增另一种写法
counter= counter+1;
counter +=1;

counter = 2;
counter--;//自减-1 和下面效果一样,但是更简洁
--counter;//另一种写法
counter = counter-1;
counter -= 1;

++--位于变量前后是由一定区别的

let counter = 1;
let a = counter++; // 返回原值a=1,counter自增变2
alert(a); // 1
alert(counter); // 2
a = ++counter; // 返回新值,counter自增变3
alert(a); // 3
alert(counter); // 3

也就是说,只要不是被使用,前后2个方法是一样的没有区别都是自增1,如果需要进行操作并立刻得到新值应该使用前置形式,例如要alert等操作,如果还想知道之前的值应该使用后置。

let counter = 1;
//自增的优先级比绝大部分的运算符要高,所以先算自增
alert( 2 * ++counter ); // 4
//反例
counter = 1;
alert( 2 * counter++ ); // 2,因为 counter++ 返回的是“旧值”

逗号运算符

很少使用的一个运算符之一,可以用来简短代码,同时运行多个语句,但只有最后一个结果会返回,优先级非常低!

let a = (1 + 2, 3 + 4);

alert( a ); // 7(3 + 4 的结果)
//1+2 实际上运行了,但被抛弃不返回
a = 1 + 2, 3 + 4
//因为优先级低于=,实际是a = 3 , 7,由于等号要先执行,a就等于3了,相当于:
(a = 1 + 2), 3 + 4

//通常用法
// 一行上有三个运算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 //3个运算符都被执行了
}

值的比较

比较结果是boolean值,例如 2>1 true 2==1 false

字符串比较,按字典顺序或词典( Unicode 编码顺序)顺序比较,注意是逐个字母或字符比较

alert( 'Z' > 'A' ); // true Z在顺序末尾最大
alert( 'a' > 'Z' ); // 小写字母总是大于大写字母
alert( 'Glow' > 'Glee' ); // true Gl一样比较o和e o大
alert( 'Bee' > 'Be' ); // true Be一样 比较e和无 有就是大

不同类型间比较

不同类型js会先转数字类型后再判断大小,

alert( '2' > 1 ); //'2'变2 比 1 大 true
alert( '01' == 1 ); //'01'变1 =1 true
alert( true == 1 ); // true转数值是1 true
alert( false == 0 ); // false转数值是0 false

let a = 0;
let b = "0";
alert(a == b); // 转数值后 0=0 true
alert(Boolean(a) == Boolean(b)); // 转布尔值后是false和true,很显然不会相等 false
//"0"转布尔值是true
//空 0 null undefined Nan 变 false
//" " "0"这种情况是ture
//php中"0"才是false

严格相等

普通==存在一个问题

0 == false 和 ''=false 都是成立的,这是因为==两侧都会先被转化成数值,如果需要区分0和false就需要用到严格相等运算符===

简单的说,严格比较不会转换格式,2边类型和值完全相等才行,还有:!== 严格不相等

null和undefined比较

这是个特殊的存在,严格相等比较时它们不相等,因为类型不一样,但是使用非严格比较时二者相等!

按之前的逻辑 null转数字为0 undefined为NaN,应该再非严格模式下也不行相等,但刚才说了这是特殊存在,只在非严格模式下成立

当使用其他方法(非==时)比较时他们还是遵循转数字之后的对比

奇观的null vs 0

知识点:null在相等性检查中,不会被转为数字

alert( null > 0 );  // (1) false
// null 转数字后也是0 不成立
alert( null == 0 ); // (2) false
// null不会转为数字,所以不成立
alert( null >= 0 ); // (3) true
// 转数字后是0 成立

特立独行的undefined

首先,不应该用它和其他值比较!

alert( undefined > 0 ); // false (1)
//转数字后是 nan,和谁比较都是false,包括它自己!
alert( undefined < 0 ); // false (2)
// 原因同上
alert( undefined == 0 ); // false (3)
//undefined在相等性检查时只会与null还有自己相等 所以不成立

条件分支 if和?

let year = 2015;
if (year == 2015) alert( 'You are right!' );//一行写法

if (year > 2015) {//多行写法,建议用这个!
  alert( "大于2015" );
}else if(year < 2015){
  alert( "小于2015" );
}else{
  alert("就是2015");
}

//用?重写,就是三元运算,也可以实现多个条件
year > 2015 ? alert( "大于2015" ) : 
year < 2015 ? alert( "小于2015" ) : 
alert("就是2015");

逻辑运算符

|| 或 && 与 !非

如果两边不是布尔值那么会转布尔值,与的优先级高于或,所以a && b || c && d 跟 && 表达式加了括号完全一样:(a && b) || (c && d)。

空 0 null undefined Nan 变 false
其他是 true(注意"0"和" ",也是true,因为他是字符串,且含有内容0或空格,不是数值0)

//或运算寻找第一个真值
result = a || b || c;
//从左到右,每次处理都换转为布尔值,如果转后结果是真,那就返回操作数的初始值,如果都不是就返回最后一个值
alert( 1 || 0 ); // 1(1 是真值)
alert( null || 1 ); // 1(1 是第一个真值)
alert( null || 0 || 1 ); // 1(第一个真值)
alert( undefined || null || 0 ); // 0(都是假值,返回最后一个值)
let firstName = "";
let lastName = "";
let nickName = "SuperCoder";
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder 第一个真值,后面??还有

//与运算寻找到一个假值
//从左到右,每次处理都换转为布尔值,如果转后结果是假,那就返回操作数的初始值,如果都不是就返回最后一个值
alert( 1 && 0 ); // 0 0是第一个假值
alert( 1 && 5 ); // 5 5是第一个假值

alert( null && 5 ); // null 是第一个假值返回null 不执行5
alert( 0 && "no matter what" ); // 0是第一个假值 不执行后面的了
alert( 1 && 2 && 3 ); // 都是真返回最后一个

//非
//将操作值转为布尔值,然后返回相反的布尔值
//!! 2个非可以用来转布尔值,建议还是用boolean


空值合并运算符??

a ?? b 如果a已定义结果是a,未定义就是b,JavaScript 禁止将 ?? 运算符与 && 和 || 运算符一起使用,除非加括号!

注意已定义是指null和undefined以外的值,如果用前面的知识写的话就是

result = (a !== null && a !== undefined) ? a : b;
///a 不等于 null 以及 a不等于undefined,那么就执行a,如果不成立就是b

//可能的用法:
let user;
alert(user ?? "匿名用户"); // 匿名用户,如果有值就返回值

let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// 显示第一个已定义的值:
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder 第一个已定义
//和之前学过的||相比,??更容错

let height = 0;
alert(height || 100); // 100 返回第一个真值
alert(height ?? 100); // 0 返回已定义的值
      
      
//??的优先级很低,需要用到的话尽量加括号
let height = null;
let width = null;

// 重要:使用括号 100 * 50
let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000

循环while和for

let i = 0;
while (i < 3) { // 依次显示 0、1 和 2
  alert( i );//弹出i
  i++;//i自增1
}
//只有一条语句的时候,可以写一行,省略花括号


let i = 0;
do {//先执行一次 结果是 0 1 2
  alert( i );//弹出i
  i++;//i自增1
} while (i < 3);//然后判断是否成立


//for比较复杂
//进入循环执行参数1
//每次循环之前检查参数2
//循环后执行参数3
for (let i = 0; i < 3; i++) { // 结果为 0、1、2
  alert(i);
}

//当你不需要先做任何事可以省略参数1,但是要在已经是声明过的情况下
//当然也可以省略参数3,在循环里做执行
//都没有也是可以的,无限循环!

//跳出循环使用
break;
//跳出本次,执行下一次用
continue;

//求奇数实例
for (let i = 0; i < 10; i++) {
  //取余,如果为真就是偶数,跳过本次循环,继续下次。
  if (i % 2 == 0) continue;
  alert(i); // 1,3,5,7,9
}
//上面的例子 套if里也可以,只是可读性不好。
for (let i = 0; i < 10; i++) {
  if (i % 2) {
    alert( i );
  }
}

//通过标签可以退出多级循环,注意只能跳出,不能跳转
outer: for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`Value at coords (${i},${j})`, '');

    // 如果是空字符串或被取消,则中断并跳出这两个循环。执行alert
    if (!input) break outer; // (*)

    // 用得到的值做些事……
  }
}
alert('Done!');

switch

当有多个if时可以用switch,与其他语言一样当没有break时会继续执行下一个case,通过这个特性可以搞分组例如:值是3,case 3不break,case 4执行,相当于把3 4 装在一个case中,注意switch是严格相等

let a = 2 + 2;

switch (a) {
  case 3:
    alert( 'Too small' );
    break;
  case 4:
    alert( 'Exactly!' );
    break;
  case 5:
    alert( 'Too large' );
    break;
  default:
    alert( "I don't know such values" );
}

函数

函数声明:

let name = 'leon'
function showMessage() {
  let message = "Hello, "; // 局部变量
  alert( message + name);//访问外部变量
    //当没有局部变量的时候访问外部
    //当有局部变量但与外部变量同名时优先访问外部
}

showMessage();//正常
alert(message);//错误 局部变量外部不能访问
function showMessage(from, text = "no text given") { // 参数:from 和 text(含有默认参数)
  alert(from + ': ' + text);
}
showMessage('Ann', 'Hello!'); // Ann: Hello! 
showMessage('Ann', "What's up?"); // Ann: What's up? 
showMessage("Ann"); // Ann: no text given


//默认参数可以是函数
function showMessage(from, text = anotherFunction()) {
  // anotherFunction() 仅在没有给定 text 时执行
  // 其运行结果将成为 text 的值
}

//更多玩法
if (text === undefined) {//函数中检查是不是未定义
    text = 'empty message';//未定义就赋予默认值
}

text = text || 'empty';//检查是否为空,为空就返回'empty',0的话也会返回
text = count ?? "unknown"//空值合并运算符,0的话不返回

函数表达式:

就是赋值后的匿名函数,函数表达式是执行到这里这里的时候被加载,函数实际上是预加载的,也就是类似变量提升,可以先调用后声明。

函数具有局部属性,当局部创建的函数,其他全局或局部是无法访问的,使用函数表达式可以将匿名函数装入全局变量中就能实现全局访问。

function sayHi() {
  alert( "Hello" );
}
//可以写成下面的形式
let sayHi = function() {
  alert( "Hello" );
};

回调函数

//问题,回答yes或no
function ask(question, yes, no) {
  if (confirm(question)) yes() //询问,yes就执行yes()
  else no();//反之就执行no()
}

function showOk() {
  alert( "You agreed." );
}

function showCancel() {
  alert( "You canceled the execution." );
}

ask("Do you agree?", showOk, showCancel);//传入问题、yes的回调函数showOk、no的回调函数showCancel

//如果使用函数表达式
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  "Do you agree?",//问题
  function() { alert("You agreed."); },//yes
  function() { alert("You canceled the execution."); }//no
);

箭头函数

一种语法糖吧 let func = (arg1, arg2, ...argN) => expression

let sum1 = function(a, b) {
  return a + b;
};
//箭头写法
let sum2 = (a, b) => a + b;
//只有一个参数可以省略括号
let double = n => n * 2;
//没有参数
let sayhi = () => alert('Hello') 
//多行的
let sum = (a, b) => {  // 花括号表示开始一个多行函数
  let result = a + b;
  return result; // 如果使用了花括号,需要写return
};

评论已关闭