您的位置:首页 > Web前端 > JavaScript

JavaScript语言基础

2021-05-10 20:33 1181 查看

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); //undefined
    var 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 age

console.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; // 等于31250000
    
    let 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); // NaN
    console.log(-0/+0); // NaN
    
    console.log(5/0); // Infinity
    console.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"); //1234
    
    let num2 = parseInt("");// NaN
    
    let 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); // 175
    let num5 = parseInt("AF");// NaN

     

  • parseFloat() 函数
    只能解析十进制
    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


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); //symbol
    
    let 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); // true
    
    console.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
      //也可使用 instanceof
      console.log(f instanceof Foo); // true

       

    • Symbol.isConcatSpreadable
      这个符号作为一个 属性表示“一个布尔值,如果是true,则意味着对象应该用 Array.prototype.concat()打平其数组元素”
      (只对类数组对象有效,其他对象设置会导致忽略连接)
      let initial = ['foo'];
      let array = ['bar'];
      
      console.log(array[Symbol.isConcatSpreadable]); //undefined
      console.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]);//undefined
      console.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]);//undefined
      console.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));    //9
    console.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:  增加更多逻辑

     

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: