AI智能
改变未来

JavaScript语言基础


JavaScript语言基础

1.语法

1.1 区分大小写

变量test和变量Test是不同的变量。typeof不能作为函数名(关键字),但Typeof合法

1.2 标识符

变量、函数、属性、函数参数的名称

  • 第一个字符必须是字母、下划线(_)、或者美元符号($)
  • 其他字符可以是字母、下划线、美元符号或数字

1.3严格模式

ES3不规范的写法会被处理,对于不安全的活动将抛出错误

对整个脚本启用严格模式

\"use strict\";

单独一个函数在严格模式下执行

function doSomething(){\"use strict\";//函数体}

2.变量

js的变量是松散类型的,var、const和let都可以声明变量

2.1 var关键字

var message;

如果声明的变量未初始化变量为undefined

  • var 定义的变量为函数作用域
    但如果在函数中定义变量时省略了var操作符会创建一个全局变量
    function test(){message = \"hi\";}test();console.log(message);    //\"hi\"

  • 可以通知声明多个变量
    var message = \"hi\",found = fales,age = 29;

  • var 声明提升
    所谓的“提升” 就是将声明放到函数作用域顶部
    console.log(age); //undefinedvar age = 26;//与下方代码等价var age;console.log(age);var age = 26;

2.2 let声明

  • let 声明的范围为块作用域
  • let 不允许冗余声明
  • let 声明的变量不会提升
  • 全局声明不会成为window对象属性

注:关于for循环

for循环中var的问题

// 迭代遍历渗透到循环体外部for(var i=0; i<5; i++){//循环体}console.log(i);  //5//定时器问题for(var i=0; i<5; i++){setTimeout(()=>console.log(i),0);}//实际输出 5、5、5、5、5

如果使用let声明迭代变量,每次循环会成名一个新的迭代变量

2.3 const声明

const与let基本相同 唯一的区别时声明变量时必须初始化,且修改会报错

注:如果修改对象中的属性则不受限制

for-in 与 for-of使用 const

for(const key in {a:1, b:2}){console.log(key);}// a,b//for-in为迭代对象的键for(const value of [1,2,3,4,5]){console.log(value);}// 1, 2, 3, 4, 5//for-of迭代实现iterator的对象

3.数据类型

ECMAScript有6种简单数据类型(也称为原始类 型):Undefined、Null、Boolean、Number、 String和Symbol。Symbol(符号)是 ECMAScript 6新增的。还有一种复杂数据类型叫 Object(对象)。

3.1 typeof操作符

因为ECMAScript的类型系统是松散的,所以需要一 种手段来确定任意变量的数据类型。

  • \”object\”表示值为对象(而不是函数)或 null
  • \”function\”表示值为函数;
console.log(typeof 95); // \"number\"console.log(typeof(\"message\")); // \"string\"

注:typeof是一个操作符而不是函数,但可以使用参数。

3.2 undefined类型

变量声明未赋值,值为undefined

let message;// let message = undefined; 等价console.log(message == undefined); // true

对未声明的变量使用typeof 也为 \”undefined\”

// 确保没有声明过这个变量// let ageconsole.log(typeof age); //\"undefined\"

3.3 Null类型

在定义将来要保存对象值的变量时,建议使用null 来初始化

注:undefined值是由null值派生而来的,因此 ECMA-262将它们定义为表面上相等

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

3.4 Boolean类型

布尔值字面量true和false是区分大小写的

任何类型的值都可以调用Boolean()函数转化为Boolean类型

数值类型 转换为true的值 转换为false的值
Boolean true false
String 非空字符串 \”\”(空字符串)
Number 非零数值(包括无穷值) 0、NaN
Object 任意对象 null
Undefined N/A(不存在) undefined

注:像if等流控制语句会 自动执行其他类型值到布尔值的转换

3.5 Number类型

  • 八进制字面量
    第一 个数字必须是零(0),然后是相应的八进制数字 (数值0~7)
    严格模式下,前缀0会被视为语法错误,如果要表示八进制值,应该使用前缀0o

  • 浮点数

    let floatNum1 = 0.1;let floatNum2 = .1; // 有效,但不推荐let floatNum3 = 1.; // 小数点后面没有数字,当成整数1处理let floatNum4 = 10.0; // 小数点后面是零,当成整数10处理let floatNum5 = 3.125e7; // 等于31250000let floatNum6 = 0.0000003;  // 等于3e-7//ECMAScript会将小数点后至少包含6个零的浮点值转换为科学记数法let floatNum7 = 0.1+0.2;   //  等于0.300000000000004  存在舍入错误

  • 值的范围
    ECMAScript可以表示的最小数值为 Number.MIN_VALUE,可以表示的最大数值为Number.MAX_VALUE
    超过范围的值会转化成为Infinity 或 -Infinity ,可以使用 isFinite() 判断一个数是否在范围内
  • NaN(Not a Number)
    在ECMAScript中,0、+0或-0相除 会返回NaN
    console.log(0/0); // NaNconsole.log(-0/+0); // NaNconsole.log(5/0); // Infinityconsole.log(5/-0); // - Infinity

    任何涉及 NaN的操作始终返回NaN

    console.log(NaN == NaN); //false// NaN与任何值不相等

    ECMAScript提供了isNaN()函数,一个值传给isNaN()后,该函数会尝试把它转换为数值,任何不能转换为数值的值都会导致这个函数返回true。

  • Number() 函数
    类型 结果
    boolean true转为1,false转为0
    数值 直接返回
    null 0
    undefined NaN
    字符串 1. 完全符合数字格式返回该数字
    2. 空字符串返回0
    3. 其他情形返回NaN
    对象 先调用valueOf()然后按上述方法转换,如果为NaN
    则再调用toString() 方法,再按上述方法转换
  • parseInt()函数
    第一个参数 接收一个字符串
    let num1 = parseInt(\"1234blue\"); //1234let num2 = parseInt(\"\");// NaNlet num3 = parseInt(\"0xA\");// 10,解释为十六进制整数let num4 = parseInt(22.5);// 22

    第二个参数 代表进制

    let num1 = parseInt(\"10\", 2);// 2,按二进制解析let num2 = parseInt(\"10\", 8);// 8,按八进制解析let num3 = parseInt(\"10\",10); // 10,按十进制解析let num4 = parseInt(\"AF\",16); // 175let num5 = parseInt(\"AF\");// NaN

  • parseFloat() 函数
    只能解析十进制
    let num1 = parseFloat(\"1234blue\"); //1234,按整数解析let num2 = parseFloat(\"0xA\");// 0let num3 = parseFloat(\"22.5\"); //22.5let num4 = parseFloat(\"22.34.5\"); //22.34

3.6 String类型

String(字符串)数据类型表示零或多个16位 Unicode字符序列。字符串可以使用双引号(\”)、 单引号(\’)或反引号(`)标示

  • 特殊字面量
    \\xnn 以十六进制编码nn表示的字符 (其中n是十六进制数字 0~F),
    例如\\x41等于\”A\”
    \\unnnn 以十六进制编码nnnn表示的 Unicode字符(其中n是十六 进制数字0~F),
    例如 \\u03a3等于希腊字符\”Σ\”
  • toString() 函数
    toString()方法可见于数值、布尔值、 对象和字符串值。(字符串值也有 toString()方法,返回自身的一个副本)
    null和 undefined值没有toString()方法 (使用会报错)

    注:在对数值调用这个方法时, toString()可以接收一个底数参数,即 以什么进制来输出数值的字符串表示。

    let num = 10;console.log(num.toString());// \"10\"console.log(num.toString(2));// \"1010\"console.log(num.toString(8));// \"12\"console.log(num.toString(10)); // \"10\"console.log(num.toString(16)); // \"a\"

  • String() 函数(接收任意类型参数)
    值有toSring()方法 调用并返回结果
    null 返回 \”null\”
    undefined \”undefined\”
  • 模板字面量
    ① 模板字面量保留换行字符,可以跨行 定义字符串
    从技术上讲模板字面量不是字符串,而是一种特殊的JavaScript 句法表达式,只不过求值后得到的是字符串
    可以通过在${}中使用一个 JavaScript表达式实现字符串插值
    let value = 5;let exponent = \'second\';let interpolatedTemplateLiteral =`${ value } to the ${exponent } power is ${ value * value }`;console.log(interpolatedTemplateLiteral); // 5 to the second power is 25

    插入的值都会使用toString()强制转型为字符串(实际使用的是String() 函数
    ③字面量也支持特有的标签函数 以及String.raw可用于查看原始字面量内容 此处略

3.7 Symbol() 类型

  • 符号需要使用Symbol()函数初始化。
    let sym = Symbol();console.log(typeof sym); //symbollet fooSymbol = Symbol(\'foo\');let otherFooSymbol = Symbol(\'foo\');console.log(fooSymbol == otherFooSymbol); //false

  • Symbol()函数不能用作构造函数,与new关键字一起使用
  • Symbol.for() 全局符号注册表
    如果程序中需要共享和重用符号实例,那么可以用一个字符串作为键, 在全局符号注册表中创建并重用符号
    let fooGlobalSymbol = Symbol.for(\'foo\'); //创建新符号let otherFooGlobalSymbol = Symbol.for(\'foo\'); // 重用已有符号let localSymbol = Symbol(\'foo\');console.log(fooGlobalSymbol === otherFooGlobalSymbol); // trueconsole.log(localSymbol === fooGlobalSymbol); // false
  • Symbol.keyFor() 可用来查询全局注册表
    // 创建全局符号let s = Symbol.for(\'foo\');console.log(Symbol.keyFor(s)); // foo// 创建普通符号let s2 = Symbol(\'bar\');console.log(Symbol.keyFor(s2)); // undefined

  • 使用符号作为属性
    let s1 = Symbol(\'foo\'),s2 = Symbol(\'bar\');let o = {[s1]: \'foo val\'};// 这样也可以:o[s1] = \'foo val\';console.log(o);// {Symbol(foo): foo val}Object.defineProperty(o, s2, {value: \'bar val\'});console.log(o);// {Symbol(foo): foo val, Symbol(bar): bar val}Object.defineProperties(o, {[s3]: {value: \'baz val\'},[s4]: {value: \'qux val\'}});

    注:几个查询属性的函数
    // 以下面对象为例子

    let s1 = Symbol(\'foo\'),s2 = Symbol(\'bar\');let o = {[s1]: \'foo val\',[s2]: \'bar val\',baz: \'baz val\',qux: \'qux val\'};

    函数名 返回值
    Object.getOwnPropertySymbols(o) [Symbol(foo), Symbol(bar)]
    Object.getOwnPropertyNames(o) [\”baz\” , \”qux\”]
    Object.getOwnPropertyDescriptors(o) {baz: {…}, qux: {…}, Symbol(foo): {…}, Symbol(bar): {…}}
    Reflect.ownKeys(o) [\”baz\” , \”qux\” , Symbol(foo), Symbol(bar)]
  • 常用内置符号
    ECMAScript 6也引入了一批常用内置符号 (well-known symbol),用于暴露语言 内部行为,开发者可以直接访问、重写或 模拟这些行为。
    • Symbol.asyncIterator
      这个符号作为一个 属性表示“一个方法,该方法返回对象默 认的AsyncIterator。由for-await-of语句使用”。
      for-await-of循环会利用这个函数执行 异步迭代操作。循环时,它们会调用以 Symbol.asyncIterator为键的函数, 并期望这个函数会返回一个实现迭代器API 的对象。

      技术上,这个由 Symbol.asyncIterator函数生成的对 象应该通过其next()方法陆续返回 Promise实例

      class Emitter {constructor(max) {this.max = max;this.asyncIdx = 0;}async * [Symbol.asyncIterator]() {while(this.asyncIdx < this.max) {yield new Promise((resolve) =>resolve(this.asyncIdx++));}}}// 用于调用异步迭代器的异步函数async function asyncCount() {let emitter = new Emitter(5);for await(const x of emitter) {console.log(x);}}asyncCount();// 0// 1// 2// 3// 4

    • Symbol.hasInstance
      这个符号作为一个 属性表示“一个方法,该方法决定一个构造器对象(Class)是否认可一个对象是它的实例。
      这个属性定义在Function的原型上,因此默认在所有函数和类上都可以调用。
      function Foo() {}let f = new Foo();console.log(Foo[Symbol.hasInstance](f)); // true//也可使用 instanceofconsole.log(f instanceof Foo); // true

    • Symbol.isConcatSpreadable
      这个符号作为一个 属性表示“一个布尔值,如果是true,则意味着对象应该用 Array.prototype.concat()打平其数组元素”
      (只对类数组对象有效,其他对象设置会导致忽略连接)
      let initial = [\'foo\'];let array = [\'bar\'];console.log(array[Symbol.isConcatSpreadable]); //undefinedconsole.log(initial.concat(array)); // [\'foo\', \'bar\'] 数组对象本身默认打平array[Symbol.isConcatSpreadable] = false;console.log(initial.concat(array)); // [\'foo\',Array(1)] 改变默认行为let arrayLikeObject = {length: 1, 0: \'baz\' };console.log(arrayLikeObject[Symbol.isConcatSpreadable]);//undefinedconsole.log(initial.concat(arrayLikeObject));// [\'foo\', {...}]arrayLikeObject[Symbol.isConcatSpreadable] = true;console.log(initial.concat(arrayLikeObject));// [\'foo\',\'baz\']  类数组对象true有效let otherObject = new Set().add(\'qux\');console.log(otherObject[Symbol.isConcatSpreadable]);//undefinedconsole.log(initial.concat(otherObject)); //[\'foo\', Set(1)]otherObject[Symbol.isConcatSpreadable] = true;console.log(initial.concat(otherObject)); //[\'foo\']  非类数组导致忽略

    • Symbol.iterator
      这个符号作为一个属性表示“一个方法,该方法返回对象默认的迭代器。由for-of语句使用”。
      for-of循环这样的语言结构会利用这个函数执行迭代操作。循环时,它们会调用以 Symbol.iterator为键的函数,并默认这个函数会返回一个实现迭代器API的对象。
      技术上,这个由Symbol.iterator函数 生成的对象应该通过其next()方法陆续返回值。可以通过显式地调用next()方法返回,也可以隐式地通过生成器函数返回
      class Emitter {constructor(max) {this.max = max;this.idx = 0;}*[Symbol.iterator]() {while(this.idx < this.max) {yield this.idx++;}}}function count() {et emitter = newEmitter(5);for (const x of emitter) {console.log(x);}}count();// 0// 1// 2// 3// 4

    • 还有一些内置符号这里先省略 需要再补充

    3.8 Object类型

    对象其实就是一组数据和功能的集合

    let o = new Object();let o = new Object; // 合法,但不推荐

    每个Object实例都拥有的属性和方法(方法都在Object的原型上)

    属性/方法 说明
    constructor 值为用于创建当前对象的函数。
    hasOwnProperty(propertyName) 用于判断当前对象实例(不是原型)上是否存在给定的属性。
    要检查的属性名必须是字符串或符号。
    isPrototypeOf(object) 用于判断当前对象是否为另一个对象的原型
    例:Foo.prototype.isPrototypeOf(foo) //true
    propertyIsEnumerable(propertyName) 用于判断给定的属性是否可以使用for-in语句枚举
    toLocaleString() 返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
    toString() 返回对象的字符串表示。
    valueOf() 返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。

    注意:浏览器环境中的BOM和DOM对象都是由宿主环境定义和提供的宿主对象。 而宿主对象不受ECMA-262约束,所以它们可能会也可 能不会继承Object。

    4.操作符

    4.1 一元操作符

    • 自增/自减操作符 ++,–
      可以作用于任何值,整数、字符串、布尔值、浮点值, 甚至对象都可以。
      先对操作的值执行Number() 函数 再进行操作
    • 一元加减操作符 (正负号)
      可以作用于任何值,先对操作的值执行Number() 函数再进行操作

    4.2 位运算

    此处略

    4.3 布尔操作符

    • 逻辑非 ( ! )
      始终返回布尔值,可以作用于任何值。
      具体操作为先对值执行Boolean() 然后取反 注:也可以使用 (! !) 两个叹号效果和Boolean() 相同
    • 逻辑与 ( && ) 短路
      可以操作任何类型,如果有操作数不是布尔值,则逻辑与并不一定会返回布尔值。
      它会先对第一个操作数执行Boolean() 如果值为false,则返回第一个操作数。如果为true,直接返回第二个
    • 逻辑或 ( | | ) 短路
      可以操作任何类型,如果有操作数不是布尔值,则逻辑与并不一定会返回布尔值。
      它会先对第一个操作数执行Boolean() 如果值为false,则返回第二个操作数。如果是true,直接返回第一个

      注:可以通过或运算符设置备用值

      // backupObject 为备用值// 当preferredObject为undefined或null时使用let myObject = preferredObject || backupObject;  

    4.4 乘性操作符

    • 乘法运算符 ( * )
      如果有不是数值的操作数 先应用Number() 转换为数值
      下面列举一些特殊行为
      特殊情形 返回值
      乘积超过范围 Infinity或-Infinity
      任意操作数为NaN NaN
      Infinity乘以0 NaN
      Infinity乘以非0的有 限数值 Infinity或-Infinity
      Infinity乘以(正负)Infinity Infinity或-Infinity

    • 除法运算符 ( / )
      如果有不是数值的操作数 先应用Number() 转换为数值
      下面列举一些特殊行为
      特殊情形 返回值
      商超过范围 Infinity或-Infinity
      任意操作数为NaN NaN
      Infinity除以Infinity NaN
      0除以0 NaN
      非0常数除以0 Infinity或-Infinity
      Infinity除以任何数值 Infinity或-Infinity

    • 取模运算符 ( % )
      如果有不是数值的操作数 先应用Number() 转换为数值 (小数也可以求余数 例:14.22%3=2.2200000000000006)
      下面列举一些特殊行为
      特殊情形 返回值
      Infinity除以有限值 NaN
      有限值除以0 NaN
      Infinity除以Infinity NaN
      有限值除以Infinity 有限值(被除数)
      0除以非0 0

    4.5 指数操作符 ( ** )

    Math.pow()现 在有了自己的操作符**

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

    4.6 加性运算符

    • 加法操作符
      如果有一个是字符串则执行连接字符串操作 其他类型执行String()
      如果没有字符串则执行数字相加 其他类型执行Number()
    • 减法操作符
      期待操作数都是数字,除了对象的其他类型会执行Number() 转换为数字。
      如果是对象,有valueOf() 就只调用valueOf(),没有就调用toString() 再调用Number()

    4.7 关系操作符

    包括小于 (<)、大于(>)、小于等于(<=)和大于等于 (>=)
    如果都是字符串则比较字符编码
    其他情况——期待操作数都是数字,除了对象的其他类型会执行Number() 转换为数字。
    如果是对象,有valueOf() 就只调用valueOf(),没有就调用toString() 再调用Number()

    4.8 相等操作符

    等于、不等于和全等、不全等

    • 等于和不等于 ( == )&( != )
      布尔值都转换为数字,数字和字符串比较 字符串转换为数字,对象调用valueOf()
      null == undefined
      null和undefined不能转换为 其他类型的值再进行比较
    • 全等不全等
      不转换类型(相当于问两个操作数有没有区别)

    4.9 条件操作符 (?… : …)

    a?b:c
    条件(a)为真,表达式值为b,否则为c

    4.10 赋值表达式 (=) 略

    4.11 逗号表达式 ( , )

    用来在一条语句中执行多个操作,值为表达式的最后一个值

    5.语句

    5.1 标签语句

    标签语句用于给语句加标签,可以在后面通过 break或continue语句引用。

    let num = 0;outermost:for (let i = 0; i < 10; i++) {for (let j = 0; j < 10; j++) {if (i == 5 && j == 5) {break outermost;}num++;}}console.log(num); // 55

    5.2 with语句

    with语句的用途是将代码作用域设置为特定的对象

    let qs = location.search.substring(1);let hostName = location.hostname;let url = location.href;// 下方等价with(location) {let qs = search.substring(1);let hostName = hostname;let url = href;}

    注:由于with语句影响性能且难于调试其中的代 码,通常不推荐在产品代码中使用with语句。

    5.3 switch语句

    可以 使用 switch(true) 然后使用类似 case num>0: 增加更多逻辑

    赞(0) 打赏
    未经允许不得转载:爱站程序员基地 » JavaScript语言基础