JavaScript语言基础

任何语言的核心所描述的都是这门语言在最基本的层面上如何工作,涉及语法、操作符、数据类型以及内置功能,在此基础之上才可以构建复杂的解决方案。
语法
  • 区分大小写
    例如
    let Main="这是一个主体" let main=""

  • 标识符
    什么是标识符:
    变量、函数、属性或函数参数的名称,
    规则:
    第一个字符必须是一个字母、下划线(_)或美元符号($),剩下的其他字符可以是字母、下划线、美元符号或数字。
    推荐使用方式
    采用驼峰式命名即第一单词首字母小写其他单词首字母大小
    例如:
    let userName="admin"

  • 注释
    单行和多行
    //这是单行注释 /* 多行注释 1.xxxx 2.xxxxx */

  • 严格模式
    "use strict" //如果放在脚本开头整个脚本采用严格模式 //如果放在函数体内则该函数采用严格模式

  • 语句
    1.ECMAScript 中的语句以分号结尾
    2.多条语句可以合并到一个 C 语言风格的代码块中(一条语句也推荐放在代码块中)。
    关键字和保留字关键字和保留字没什么好说的,以下这些词汇不能用作标识符来使用。
    //ECMA-262 第 6 版规定的所有关键字 break do in typeof case else instanceof var catch export new void class extends return while const finally super with continue for switch yield debugger function this default if throw delete import try //未来保留的关键字 //始终保留 enum //严格模式下 implements package public interface protected static let private //模块代码中 await

    变量
  • 什么是变量
    用于保存任何类型的数据,声明变量的的方式有var、let、const三种
    var声明特征
  • 函数作用域
    function fn(){ console.log(a)//undefined var a=123 console.log(a)//123 } fn() console.log(a)//报错 Uncaught ReferenceError: a is not defined //对比 if(true){ var a=123 } console.log(a)//123

  • 变量提升
    console.log(a)//undefined var a=123 console.log(a)//123

    let声明
  • 块级作用域
    function fn(){ console.log(a)//undefined let a=123 console.log(a)//123 } fn() console.log(a)//报错 Uncaught ReferenceError: a is not defined //对比 if(true){ let a=123 } console.log(a)//报错 Uncaught ReferenceError: a is not defined

  • 【JavaScript语言基础】暂时性死区
    console.log(a)//Uncaught ReferenceError: Cannot access 'a' before initialization let a=12

  • 同一作用域下不能声明冗余
    let a=12 let a=123//Uncaught SyntaxError: Identifier 'a' has already been declared 或 var a=121//Uncaught SyntaxError: Identifier 'a' has already been declared 或 const a//Uncaught SyntaxError: Identifier 'a' has already been declared

    const声明
    const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误
数据类型 原始类型:Undefined、Null、String、Boolean、Number、 Symbol和、Bigint
引用类型:Object
检测数据类型的方法
  • typeof
    console.log(typeof "str")//string console.log(typeof 12)//number console.log(typeof true)//boolean console.log(typeof undefined)//undefined console.log(typeof Symbol("id"))//symbol console.log(typeof 10n)//bigint console.log(typeof null)//object console.log(typeof {})//object console.log(typeof function(){})//function console.log(typeof [])//object

    typeof对于基本数据类型除去null判断为object其他都能准确判断出,对于引用类型数据能够判断出对象和函数
  • instanceof检测引用类型
    console.log({} instanceof Object)//ture console.log([] instanceof Array)//ture console.log(function(){} instanceof Function)//ture console.log(new Date() instanceof Date)//ture

  • toString比较全面的检测类型的方法
    let toString=Object.prototype.toString console.log(toString.call(null))//[object Null] console.log(toString.call(undefined))//[object Undefined] console.log(toString.call('1212'))//[object String] console.log(toString.call(1212))//[object Number] console.log(toString.call(true))//[object Boolean] console.log(toString.call(Symbol('ID')))//[object Symbol] console.log(toString.call(10n))//[object BigInt] console.log(toString.call({}))//[object Object] console.log(toString.call([]))//[object Array] console.log(toString.call(new Date()))//[object Date] console.log(toString.call(function (){}))//[object Function] console.log(toString.call(NaN))//[object Number] console.log(toString.call(Infinity))//[object Number]

    Undefined
    用于未定义的值 —— 只有一个 undefined 值的独立类型
    Null
    用于未知的值 —— 只有一个 null 值的独立类型
    Boolean
    用于 true 和 false。
    类型转换
    数据类型 转换成true的值 转换成false的值
    Boolean true fasle
    String 非空字符串 ""(空字符串)
    Number 非零数值(包括无穷值) 0、NaN
    Object 任意对象 null
    Undefined N/A(不存在) undefined
    Number
    用于任何类型的数字:整数或浮点数,在 ±(2^53^-1) 范围内的整数,特殊的值Infinity、-Infinity 和 NaN。
    数值转换方法:
  • Number()//转型函数,可用于任何数据类型
    转换规则:
    1.布尔值,true 转换为 1,false 转换为 0。
    2.数值,直接返回
    3.null,返回 0
    4.undefined,返回 NaN。
    5.字符串:
    01.字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值(忽略前面的0)
    02.字符串包含有效的浮点值格式,则会转换为相应的浮点值(忽略前面的0)
    03.有效的十六进制格式,则会转换为与该十六进制值对应的十进制整
    数值
    04.空字符串(不包含字符),则返回 0
    05.包含除上述情况之外的其他字符,则返回 NaN
    6.对象:
    调用 valueOf()方法,并按照上述规则转换返回的值。如果转换结果是 NaN,则调用toString()方法,再按照转换字符串的规则转换
  • parseInt()//需要得到整数时可以优先使用可以指定进制数。字符串最前面的空格会被忽略,遇到小数点不在解析,建议使用此方法时指定进制数
  • parseFloat()//与parseInt()类似,不能指定进制数,遇到第二个小数点不在解析,始终忽略字符串开头的零,只解析十进制值
    String
    用于字符串:一个字符串可以包含 0 个或多个字符,所以没有单独的单字符类型。
    字符串标示:''、""、``
  • 字符字面量
字面量 含义
\n 换行
\t 制表
\b 退格
\r 回车
\f 换页
\ \ 反斜杠(\)
\ ' 单引号(') ,在字符串以单引号标示时使用,例如'He said, \'hey.\''
\ " 双引号("),在字符串以双引号标示时使用,例如"He said, \"hey.\""
\ ` 反引号,在字符串以反引号标示时使用,例如He said, \hey.\``
\xnn 以十六进制编码 nn 表示的字符(其中 n 是十六进制数字 0~F),例如\x41 等于"A"
\unnnn 以十六进制编码 nnnn 表示的 Unicode 字符(其中 n 是十六进制数字 0~F),例如\u03a3 等于希腊字符"Σ
  • 转换为字符串方法
    xxx.toString(number)//2、8、10、16表示进制书或者不加参数转字符串

  • 模板字面量(``)
    //1.可以换行例子: let str=`我是一个, 字符串。` //字符串插值例子: let age=20 let man=`我是一个男人,年龄${age}岁`

    Symbol
    用于唯一的标识符
    1.基本使用方法
    letname=Symbol("ID"); console.log(name.description)//ID //Symbol()函数不能与 new 关键字一起作为构造函数使用 ,可以通过Object实现 { let sym=new Symbol("ID"); // TypeError: Symbol is not a constructor } { let sym =Symbol() let mySymbol =Object(sym) console.log(typeof myWrappedSymbol); // "object" } //警示!Symbol 不会被自动转换为字符串

    2.使用全局符号注册表
    // 创建全局符号 let s = Symbol.for('foo'); let s4=Symbol.for('foo'); console.log(s === s4)//true console.log(Symbol.keyFor(s)); // foo // 创建普通符号 let s2 = Symbol('bar'); let s3=Symbol('bar'); console.log(s2===s3)//false console.log(Symbol.keyFor(s2)); // undefined

    3.使用符号作为属性
    let s1=Symbol('id'); let obj={ name:"lly", [s1]:'01', [Symbol('value')]:'我是一名程序员' } //Symbol 在 for…in 中会被跳过 for(let key in obj){ console.log(key)//name }

    4.常用内置符号
    //全局函数 Symbol 的普通字符串属性,指向一个符号的实例。所有内置符号属性都是不可写、不可枚举、不可配置的。 @@iterator=>Symbol.iterator

    5.Symbol.asyncIterator
    指定了一个对象的默认异步迭代器
    const myAsyncIterable = new Object(); myAsyncIterable[Symbol.asyncIterator] = async function*() { yield "hello"; yield "async"; yield "iteration!"; }; (async () => { for await (const x of myAsyncIterable) { console.log(x); // expected output: //"hello" //"async" //"iteration!" } })();

    6.Symbol.hasInstance
    //用于判断某对象是否为某构造器的实例 //实现一个自定义的instanceof 行为 class MyArray { static [Symbol.hasInstance](instance) { return Array.isArray(instance); } } console.log([] instanceof MyArray); // true

    7.Symbol.isConcatSpreadable
    //控制数组或类似数组(array-like)的对象的行为: //1.对于数组对象,用于concat时,可以改变其默认情况下。 let alpha = ['a', 'b', 'c'], numeric = [1, 2, 3]; let alphaNumeric = alpha.concat(numeric); console.log(alphaNumeric); // 结果: ['a', 'b', 'c', 1, 2, 3] numeric[Symbol.isConcatSpreadable] = false; console.log(alphaNumeric); // 结果: ['a', 'b', 'c',[ 1, 2, 3]] //2.对于类似数组的对象,用于concat时,该对象整体作为新数组的元素,改变默认行为 var x = [1, 2, 3]; var fakeArray = { [Symbol.isConcatSpreadable]: true,//如果false length: 2, 0: "hello", 1: "world" } //[Symbol.isConcatSpreadable]: true x.concat(fakeArray); // [1, 2, 3, "hello", "world"] //[Symbol.isConcatSpreadable]: false x.concat(fakeArray); // [1, 2, 3, {…}]

    8.Symbol.iterator
    //Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of循环使用。 let myIterable = {} myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable] // [1, 2, 3]

    9.Symbol.match
    //指定了匹配的是正则表达式而不是字符串 //禁止表达式检测 let re = /foo/; re[Symbol.match] = false; "/foo/".startsWith(re); // true "/baz/".endsWith(re); // false

    10.Symbol.replace
    //当一个字符串替换所匹配字符串时所调用的方法 class Replace1 { constructor(value) { this.value = https://www.it610.com/article/value; } [Symbol.replace](string) { return `s/${string}/${this.value}/g`; } }console.log('foo'.replace(new Replace1('bar'))); // expected output: "s/foo/bar/g"

    11.Symbol.search
    //指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标 class caseInsensitiveSearch { constructor(value) { this.value = https://www.it610.com/article/value.toLowerCase(); } [Symbol.search](string) { return string.toLowerCase().indexOf(this.value); } }console.log('foobar'.search(new caseInsensitiveSearch('BaR'))); // expected output: 3

    12.Symbol.species
    //被构造函数用以创建派生对象 class MyArray extends Array { // 覆盖 species 到父级的 Array 构造函数上 static get [Symbol.species]() { return Array; } } var a = new MyArray(1,2,3); var mapped = a.map(x => x * x); console.log(mapped instanceof MyArray); // false console.log(mapped instanceof Array); // true

    13.Symbol.split
    //正则表达式的索引处分割字符串的方法 let exp ={ pat:'in', [Symbol.split](str) { return str.split(this.pat); } } console.log( "dayinlove".split(exp)); //["day", "love"]

    14.Symbol.toPrimitive
    //干扰一个对象转换为原始值时输出的结果的 var obj2 = { [Symbol.toPrimitive](hint) { if (hint == "number") { return 10; } if (hint == "string") { return "hello"; } return true; } }; console.log(+obj2); // 10-- hint 参数值是 "number" console.log(`${obj2}`); // "hello" -- hint 参数值是 "string" console.log(obj2 + ""); // "true"-- hint 参数值是 "default"

    15.Symbol.toStringTag
    //自定义类型标签 class ValidatorClass { get [Symbol.toStringTag]() { return "Validator"; } }console.log(Object.prototype.toString.call(new ValidatorClass())); // "[object Validator]"

    Symbol的使用场景
  • '隐藏' 对象属性
  • JavaScript 使用了许多系统 Symbol,这些 Symbol 可以作为 Symbol.* 访问
Bigint
用于任意长度的整数。
//用法 let bg=1n 或 let big=BigInt(1)

Object
用于更复杂的数据结构(一组数据和功能的集合)
Object 类型的所有方法和属性:
1.constructor//用于创建当前对象的函数。
2.hasOwnProperty(propertyName)//判断当前对象实例(不是原型)上是否存在给定的属性
3.isPrototypeOf(object)//判断当前对象是否为另一个对象的原型
4.propertyIsEnumerable(propertyName)//用于判断给定的属性是否可以使用
5.toLocaleString()//对象的字符串表示,该字符串反映对象所在的本地化执行环境
6.toString()//对象的字符串
7.valueOf()//对象对应的字符串、数值或布尔值表示
操作符 一元操作符
  • 递增|递减(++ | --)
    //前缀和后缀区别 //后缀版递增和递减在语句被求值后才发生 let num=10 console.log(num--)//10 或 console.log(--num)//9 //递增和递减操作符遵循如下规则 /*1.对于字符串,如果是有效的数值形式,则转换为数值再应用改变。变量类型从字符串变成数值。 2.对于字符串,如果不是有效的数值形式,则将变量的值设置为 NaN 。变量类型从字符串变成 数值。 3.对于布尔值,如果是 false,则转换为 0 再应用改变。变量类型从布尔值变成数值。 4.对于布尔值,如果是 true,则转换为 1 再应用改变。变量类型从布尔值变成数值。 5.对于浮点值,加 1 或减 1。 6.如果是对象,则调用其(第 5 章会详细介绍的)valueOf()方法取得可以操作的值。对得到的 值应用上述规则。如果是 NaN,则调用 toString()并再次应用其他规则。变量类型从对象变成数值。 */

  • 一元加|减(+|-)
    //一元加和减操作符主要用于基本的算术,但也可以像上面的例子那样,用于数据类型转换。

位操作符
  • 按位非(~)
    //对数值取反并减 1 let num=10 console.log(~num)//-11

  • 按位与(&)
第一个数值的位 第二个数值的位 结 果
1 1 1
1 0 0
0 1 0
0 0 0
  • 按位或(|)
第一个数值的位 第二个数值的位 结 果
1 1 1
1 0 1
0 1 1
0 0 0
  • 按位异或(^)
第一个数值的位 第二个数值的位 结 果
1 1 0
1 0 1
0 1 1
0 0 0
  • 左移(<<)
    按照指定的位数将数值的所有位向左移动用0补全
    let oldValue = https://www.it610.com/article/2; console.log(oldValue.toString(2))// 等于二进制 10 let newValue = oldValue << 5; console.log(newValue.toString(2))// 等于二进制 1000000

  • 有符号右移(>>)
    let oldValue = https://www.it610.com/article/64; console.log(oldValue.toString(2))// 等于二进制 1000000 let newValue = oldValue>> 5; console.log(newValue.toString(2))//等于二进制10

  • 无符号右移(>>>)
    //对于正数,无符号右移与有符号右移结果相同。 let oldValue = https://www.it610.com/article/64; console.log(oldValue.toString(2))// 等于二进制 1000000 let newValue = oldValue>>> 5; console.log(newValue.toString(2))//等于二进制10 //无符号右移操作符将负数的二进制表示当成正数的二进制表示来处理。因为负数是其绝对值的二补数,所以右移之后结果变得非常之大 let oldValue = https://www.it610.com/article/-64; console.log(oldValue.toString(2))// 等于二进制-1000000 let newValue = oldValue>>> 5; console.log(newValue.toString(2))//等于二进制111111111111111111111111110 console.log(newValue.toString(10))//等于十进制134217726

    布尔操作符
  • 逻辑非(!)
    1.如果操作数是对象,则返回 false。
    2.如果操作数是空字符串,则返回 true。
    3.如果操作数是非空字符串,则返回 false。
    4.如果操作数是数值 0,则返回 true。
    5.如果操作数是非 0 数值(包括 Infinity),则返回 false。
    6.如果操作数是 null,则返回 true。
    7.如果操作数是 NaN,则返回 true。
    8.如果操作数是 undefined,则返回 true。
    !!=>Boolean()
  • 逻辑与(&&)
第一个操作数 第二个操作数 结 果
true true true
true false false
false true false
false false false
  • 逻辑或(||)
第一个操作数 第二个操作数 结 果
true true true
true false true
false true true
false false false
乘性操作符
  • 乘法(*)
  • 除法(/)
  • 取余(%)
指数操作符
  • 指数 (2**3=>2^3^)
加性操作符
  • 加法(+)
  • 减法(-)
关系操作符
  • 小于(<)
  • 大于(>)
  • 小于等于(<=)
  • 大于等于(>=)
相等操作符
  • ==//等于
    任一操作数是布尔转成数值再比较
    一个操作数是字符串一个是数值转成数字在比较
    一个对象另一个不是调用valueOf()取得原生值在比较
    null 和 undefined 相等。
    null 和 undefined 不能转换为其他类型的值再进行比较
    任一操作数是 NaN,则相等操作符返回 false,NaN和NaN不相等
    两个操作数都是对象,则比较它们是不是同一个对象,是true否false
表达式 结 果
null == undefined true
"NaN" == NaN false
5 == NaN false
NaN == NaN false
NaN != NaN true
false == 0 true
true == 1 true
true == 2 false
undefined == 0 false
null == 0 false
"5" == 5 true
  • ===//全等
    不进行类型转换 ,未转换前相等是true否则false
    条件操作符
    //三目运算符 条件?执行体1:执行体2 等价于 if(){}else{}

    赋值操作符
  • 乘后赋值(*=)
  • 除后赋值(/=)
  • 取模后赋值(%=)
  • 加后赋值(+=)
  • 减后赋值(-=)
  • 左移后赋值(<<=)
  • 右移后赋值(>>=)
  • 无符号右移后赋值(>>>=)
逗号操作符
//一条语句中执行多个操作 let a=1,b=2,c=3; 或 let A=(1,2,3,0)//0

语句 if语句
//流程控制 if(//条件1){ //执行体1 }else if(//条件2){ //执行体2 }else{ //执行体3 }

do-while语句
//后测试循环语句 let i = 0; //循环初始值 do { i += 2; //循环规则 console.log(i)//2 执行此语句 } while (i < 0); //循环阀值

while语句
//先测试循环语句 let i = 0; //循环初始值 while(i < 0) { //循环阀值 i += 2; //循环规则 console.log(i)//不执行此语句 }

for语句
//先测试循环语句,把初始值和执行的表达式加进来 for(let i=0; i<10; i++){//初始值,阈值,循环表达式 //执行语句 }

for-in语句
//一种严格的迭代语句,用于枚举对象中的非符号键属性,null 和undefined,则不执行循环体。 for(letkey in enumObject){//enumObject可枚举对象 console.log(key) }

for-of语句
//一种严格的迭代语句,用于遍历可迭代对象的元素 for(let key of enumObject){//enumObject遍历可迭代对象 console.log(key) }

标签语句
//用于循环嵌套 start:for(let i=0; i<10; i++){ if(i%5==0){ break start//1,2,3,4,5 } }

break和continue语句
//break立即退出循环,强制执行循环后的下一条语句 //例: let num=0; for(let i=1; i<10; i++){ if(i%3==0){ break; } num++ } console.log(num)//2 //continue立即退出循环,但会再次从循环顶部开始执行 //例: let num=0; for(let i=1; i<10; i++){ if(i%3==0){ continue; } num++ } console.log(num)//6

with语句
//严格模式不允许使用 with 语句,否则会抛出错误(不推荐使用) //将代码作用域设置为特定的对象 //使用场景针对一个对象反复操作,这时候将代码作用域设置为该对象能提供便利 //例子 let qs = location.search.substring(1); let hostName = location.hostname; let url = location.href; //上面代码中的每一行都用到了 location 对象。如果使用 with 语句,就可以少写一些代码: with(location) { let qs = search.substring(1); let hostName = hostname; let url = href; }

switch语句
//控制语句 switch(expression){//参数 case value1: //条件1 statement //执行语句 break; case value2: //条件1 statement //执行语句 break; ..... default: statement//执行语句 }

函数 严格模式对函数的一些限制:
  • 函数不能以 eval 或 arguments 作为名称;
  • 函数的参数不能叫 eval 或 arguments;
  • 两个命名参数不能拥有同一个名称。

    推荐阅读