影子的知识库

影子的知识库

  • 知识库
  • GitHub

›JS 基础

JVM系列

  • JVM内存区域
  • 对象创建-布局-访问
  • 内存溢出实战
  • 内存区域回收
  • 四大引用
  • 垃圾回收算法
  • HotSpot回收算法细节

Java系列

  • java注解
  • springboot请求参数绑定
  • springboot请求参数校验框架
  • YAML语法
  • 动态代理
  • classpath和java命令
  • springboot-aop编程
  • springboot统一异常处理
  • springboot数据库和事务
  • springboot拦截器
  • springboot中的web配置
  • docker的简单开发
  • springboot自动配置
  • 数据库的隔离级别
  • springboot监控
  • java类加载
  • java-agent的相关内容
  • 类加载器详解
  • java的SecurityManager
  • maven学习

Node

    JS 基础

    • 语法基础和数据类型
    • 数据类型转换
    • 语句 表达式 运算符
    • 变量与对象
    • 函数
    • 数据处理
    • 常用 API
    • 重点知识

    ES6

    • 块级作用域
    • 字符串和正则表达式
    • 函数
    • 对象
    • Symbol
    • Set和Map
    • 迭代器和生成器
    • 类
    • 数组
    • Promise

    Node 基础

    • 模块系统
    • package.json
    • 内置对象
    • npm脚本的使用
    • Buffer
    • Stream
    • 事件循环机制
    • 示例代码

    stream系列

    • 流的缓冲
    • 可读流
    • 可写流
    • 双工流和转换流
    • 自定义流

后期计划

  • 学习计划
  • 专题研究计划
Edit

本文内容

本文主要是说明一些 Javascript 中的一些语法元素,包括语句、表达式、运算符等

6种循环(ES 6)

在 Javascript 中包含 6 种循环语句,for each in 语句在 ECMAScrupt 中并不存在,属于 Javascript 特有的增强功能。

  • while (条件表达式)
  • do while (条件表达式)
  • for(初始化表达式;条件表达式;更新表达式)
  • for (变量 in 对象表达式)(属性名迭代)
  • for each (变量 in 对象表达式) (非 ES 标准,属性值迭代)
  • for (变量 of 对象表达式)(ES 6 标准,属性值迭代,具体内容后续 ES 6 内容中进行补充)

for 循环

唯一的注意点:ES 6 之前,JS 没有块级作用域,所以 for 循环中声明的循环变量,在循环结束后依然是可以访问的,例如:

for (var i = 0; i < 10; i++) {
    ; // 什么都不干
}
console.log(i); // 输出 10,这里我们依然能访问到 i

for in 语句

for in 语句是用于枚举对象属性名的循环语句。在对象表达式处所写的对象的属性名的字符串,会被依次赋值给循环变量,例如:

var obj = { x: 1, y: 3, z: 2 };
for (var k in obj) {
    // 迭代的是属性名称而不是属性值
    console.log(k);
}
// 依次输出 x y z (也可能不是这个顺序)

如果想要输出属性值,一般使用 obj[k] 的方式进行迭代,例如:

var obj = { x: 1, y: 3, z: 2 };
for (var k in obj) {
    console.log(obj[k]);
}
// 依次输出 1 3 2 (也可能不是这个顺序)

处理数列

数列也是一种对象,而且下标值相当于一种属性名,所以可以像下面这样进行迭代(但是一般不推荐),例如:

/**
 * 输出
 * 0=>7
 * 1=>1
 * 2=>5
 */
var arr = [7, 1, 5];
for (var n in arr) {
    console.log(n + '=>' + arr[n]);
}

如果我们给数列对象加上了别的属性,那么加上的属性也会被迭代,例如:

/**
 * 输出
 * 0=>7
 * 1=>1
 * 2=>5
 * x=>3
 */
var arr = [7, 1, 5];
arr.x = 3; // 增加了一个 x 属性
for (var n in arr) {
    console.log(n + '=>' + arr[n]);
}

注意:

  1. for in 的属性是不确定的,不能认为它有某种顺序规则,我们不应该依靠它的任何顺序,把它当成随机顺序即可。(虽然大部分情况会有相同的顺序,但是不能认为这一定是成立的)

  2. for in 可以枚举由原型继承而来的属性

  3. for in 有些属性是不能进行枚举的(enumerable = false 的属性,我们添加的常规属性都是 true,数组的 length 是 false)。也就是说,属性本身也是有属性的(或者可以称为元属性?),就像在 Java 中,属性除了属性值外,还有可见性、是否 final 等一些其它的属性值之外的属性。在 Javascript 中,属性有 5 种元属性(在此只简单列举,后续会有详细分析):

    属性的属性名称含义
    writable可以改写属性值
    enumerable属性可以被 for in 语句枚举
    configutable元属性本身是否可以进行改变(就是说一个对象的某个属性的这 5 种元属性是否还能进行更改,configurable 一旦为 false,就再也不可改了)
    get设置属性值的 getter 函数
    set设置属性值的 setter 函数

错误处理

我们可以用 throw 抛出异常,用 try...catch 捕获它(跟 Java 差不多)。

错误类型

ES 标准定义了 7 种异常类型:

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

其中,Error 是以上所有异常的基类,包含 2 个属性:name 和 message,表示错误的名称和错误的信息。一般不会直接抛出 Error,而是会抛出子类型的错误。

  • EvalError 类型的错误现在不再会被抛出了(新的 ES 标准中)

  • RangeError 会在数值超过相应范围时候抛出,例如定义数组时设置不支持的项数,例如:

    var items1 = new Array(-20); // 抛出 RangeError
    var items2 = new Array(Number.MAX_VALUE);  // 抛出 RangeError
    
  • ReferenceError 在使用不存在的变量时会抛出,例如:

    console.log(a); // a 从未声明过,会抛出 ReferenceError
    
  • SyntaxError 就是语法错误,这个不用多说明了

  • TypeError 在变量类型不符合要求时出现,例如下面 3 行都会出现该错误:

    var o = new 10;
    console.log("name" in true);
    Function.prototype.toString.call("name");
    
  • URIError 在使用 encodeURI() 或 decodeURI(),而 URI 格式不正确时,就会导致 URIError 错误。

try...catch 语句

例如:

try {
    console.log(foo);
} catch (someError) {
    console.log('错误名称:' + someError.name);
    console.log('错误信息:' + someError.message);
}

finally 块的代码一定会最后执行,所以如果 finally 块中有返回语句,那么会覆盖前面的返回值。

我们可以处理不同类型的错误,使用如下方式:

try {
    someFunction();
} catch (error) {
    if (error instanceof TypeError) {
        //处理
    } else if (error instanceof ReferenceError) {
        //处理
    } else {
        //处理其它类型错误
    }
}

throw 抛出错误

Javascript 可以抛出任何类型和值的错误,也就是说,下面的代码都是有效的:

throw 12345; 
throw "Hello world!"; 
throw true; 
throw { name: "JavaScript"};

throw 之后的语句都不会执行,直到被捕获后在捕获的那一块儿代码中继续执行,例如:

function test() {
    console.log('before throw');
    throw 100;
    console.log('after throw'); // 永远不会执行到这里
}
try {
    test();
} catch (error) {
    console.log('捕获到:' + error);
}
// 输出
// before throw
// 捕获到:100

使用内置错误,每种错误都接收一个参数,就是错误的信息:

throw new Error("something wrong");

利用原型链可以创建自定义的错误类型,这个可以以后再研究

NEW 运算符

MDN 文档:NEW 运算符

new 运算符会进行如下操作:

  1. 创建一个空的简单 JavaScript 对象,也就是 {},假设起一个临时名字是 tmp
  2. 将新对象 tmp 的原型对象指向构造函数(假设是 Func() 函数)的 prototype 属性,也就是说 tmp.__proto__ = Func.prototype
  3. 此时 tmp.constructor = Func.prototype.constructor = Func
  4. 步骤 3 有两个关键,一个是 tmp.constructor = Func,一个是 Func.prototype.constructor = Func
    • 也就是说新对象的 constructor是从原型链继承来的
    • 函数对象的 prototype 属性上,有一个属性 prototype.constructor 指向函数对象自身
  5. 调用新对象的 constructor 方法,也就是 tmp.constructor(...)
  6. 步骤 5 的接收对象是 tmp,因此构造函数中 this 指向 tmp
  7. 如果 tmp.constructor(...) 没有返回新对象,则返回 this,也就是 tmp 对象
  8. new Func 等同于 new Func(),也就是进行没有任何参数的构造函数调用

示例:

function a(arg) { this.x = 1; console.log(arg); }
var b = new a(); // 输出 undefined

/**
 * b.constructor = b.__proto__.constructor 且 b.__proto__ = a.prototype
 * 因此 b.__proto__.constructor = a.prototype.constructor
 * 而 a.prototype.constructor = a 自身
 * 所以 b.constructor = a
 * 这里输出 [Function: a]
 */
console.log(b.constructor); 

b.__proto__ = Object.prototype;

/**
 * 此时 b.constructor = b.__proto__.constructor = Object.prototype.constructor
 * 因此 b.constructor = Object
 * 所以输出 [Function: Object]
 */
console.log(b.constructor);

a.prototype.constructor(11111); // 等价于 a(11111)调用,因此输出 11111

INSTANCEOF 运算符

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。例如:

var d = new Date();
// true,Date.prototype = d.__proto__
console.log(d instanceof Date);
// true,Object.prototype = Date.prototype.__proto__ = d.__proto__.__proto__
console.log(d instanceof Object);
function Derived() {}
function Base() {}
Derived.prototype = new Base();
var obj = new Derived();
// true Derived.prototype = obj.__proto__
console.log(obj instanceof Derived);
// true Base.prototype = Derived.prototype.__proto__ = obj.__proto__.__proto__
console.log(obj instanceof Base);
//true 一样的道理
console.log(obj instanceof Object);
Last updated on 11/8/2020
← 数据类型转换变量与对象 →
  • 6种循环(ES 6)
  • for 循环
  • for in 语句
    • 处理数列
  • 错误处理
    • 错误类型
    • try...catch 语句
    • throw 抛出错误
  • NEW 运算符
  • INSTANCEOF 运算符
影子的知识库
Docs
Getting Started (or other categories)Guides (or other categories)API Reference (or other categories)
Community
User ShowcaseStack OverflowProject ChatTwitter
More
BlogGitHub
Copyright © 2020 Cen ZhiPeng