Little H title

this is subtitle


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 公益404

javascript-class

发表于 2019-05-11 | 分类于 JavaScript完全手册(2018版)

javascript-class

2015 年,ECMAScript 6(ES6)标准引入了 Classes(类) 。

在此之前,JavaScript 只有一种非常独特的方式来实现继承。 它的原型继承虽然在我看来很棒,但与其他流行的编程语言不同。

来自 Java 或 Python 或其他语言的人很难理解原型继承的复杂性,因此 ECMAScript 委员会决定在它们之上引入一个语法糖,类似于基于类的继承在其他流行的实现中工作。

这很重要:引擎下的 JavaScript 实现仍然相同,您可以平常的方式继续访问对象原型。

定义一个 class(类)

这是一个班级的 class(类) 。

JavaScript 代码:

1
2
3
4
5
6
7
8
class Person {
constructor(name) {
this.name = name;
}
hello() {
return 'Hello, I am ' + this.name + '.';
}
}

一个类有一个标识符,我们可以使用它来使用 new ClassIdentifier() 创建对象实例。上述例子中你可以使用 new Person('') 来创建。

初始化对象时,将调用 constructor(构造函数) 方法,并传递一些参数。

一个类也有它需要的方法。 上述例子中,hello 是一个方法,可以在从该类派生的所有实例上调用:

JavaScript 代码:

1
2
const flavio = new Person('Flavio');
flavio.hello();

类的继承

类可以扩展另一个类,使用该类初始化的实例对象继承这两个类的所有方法。

如果继承的类具有与上层次结构中较高的类之一具有相同名称的方法,则最接近的方法优先:

JavaScript 代码:

1
2
3
4
5
6
7
class Programmer extends Person {
hello() {
return super.hello() + ' I am a programmer.';
}
}
const flavio = new Programmer('Flavio');
flavio.hello();

上面的程序打印出 “Hello, I am Flavio. I am a programmer.”

类没有显式的类变量声明,但必须初始化构造函数中所有的变量。

在类中,您可以调用 super() 来引用父类。

看完了 class 的是原型的糖, 那么可以知道 extends 也是原型糖, 即son.prototype = new F() 子的原型指向父的一个实例
super指代了整个prototype或者__proto__指向的对象, 用extends时别忘super

继承还是组合, 更多喜欢用组合的方式.

静态方法

通常,方法是在实例上执行的,而不是在类上执行的。

静态方法在类上执行:

JavaScript 代码:

1
2
3
4
5
6
class Person {
static genericHello() {
return 'Hello';
}
}
Person.genericHello(); //Hello

也就是在构造函数上加方法

注意, 如果用 ES5 Object.create的方式来创建, 是不能继承静态方法的, 而用extends可以继承

Object.create 可以创建一个普通对象,但不能创建一个函数对象
就是函数Function和对象Object的区别

理解 JavaScript 函数(函数和对象的区别和联系)

JavaScript 代码:

1
2
3
4
5
6
7
8
// ES5
function B() {}
B.f = function() {};

function D() {}
D.prototype = Object.create(B.prototype);

D.f(); // error

JavaScript 代码:

1
2
3
4
5
6
7
8
// ES6
class B {
static f() {}
}

class D extends B {}

D.f(); // ok

面向对象的 JavaScript – 深入了解 ES6 类

私有方法

JavaScript 目前没有内置的方法来定义私有或受保护的方法。目前有很多 hack 方式解决,但我不会在这里描述它们。

值得注意的是 TC39 最近在 GitHub 上通过了一条 EMCAScript 语法特性的草案,即类私有属性修饰符 #,不过,该特性之前在社区的调研中遭遇了大量反对。例如:

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Shape {
#height;
#width;

constructor(width, height) {
this.#width = width;
this.#height = height;
}

get area() {
return this.#width * this.#height;
}
}

const square = new Shape(10, 10);
console.log(square.area); // 100
console.log(square instanceof Shape); // true
console.log(square.#width); // 错误:私有属性只能在类中访问

确实有点丑陋!本人更喜欢 TypeScript 的方式:

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Shape {
private width;
private height;

constructor(width, height) {
this.width = width;
this.height = height;
}

get area() {
return this.width * this.height;
}
}
const square = new Shape(10, 10)
console.log(square.area); // 100

还有用公约 _前缀的 , 用特权方法的(在构造函数中写闭包), 用Symbol的, WeekMap

public private 和 protected

getter 和 setter

您可以添加以 get 或 set 为前缀的方法来创建 getter 和 setter,这两个代码是根据您正在执行的操作执行的:访问变量或修改其值。

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
class Person {
constructor(name) {
this.name = name;
}
set name(value) {
this.name = value;
}
get name() {
return this.name;
}
}

如果您只有一个 getter,则无法设置该属性,并且将忽略任何尝试这样做:

JavaScript 代码:

1
2
3
4
5
6
7
8
class Person {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
}

如果您只有一个 setter ,则可以更改该值,但不能从外部访问它:

JavaScript 代码:

1
2
3
4
5
6
7
8
class Person {
constructor(name) {
this.name = name;
}
set name(value) {
this.name = value;
}
}

关于 Classes(类)的更多详细信息可以查看 面向对象的 JavaScript – 深入了解 ES6 类

参考

如何使用 JavaScript 中的 Classes(类)
浅谈 ES6 中 super 关键字
面向对象的 JavaScript – 深入了解 ES6 类

javascript-Prototype

发表于 2019-05-11 | 分类于 JavaScript完全手册(2018版)

javascript-Prototype

看这个就行,JavaScript Prototype(原型) 新手指南

6 步

参考

JavaScript Prototype(原型) 新手指南

javascript-原型继承

发表于 2019-05-10 | 分类于 JavaScript完全手册(2018版)

javascript-原型继承

JavaScript 在流行的编程语言中非常独特,因为它使用了原型继承。 让我们找出这意味着什么。

虽然大多数面向对象的语言使用基于类的继承模型,但 JavaScript 基于原型继承模型。

这是什么意思呢?

每个 JavaScript 对象都有一个名为 prototype 的属性,它指向不同的对象。

这个不同的对象就是 对象原型 。

我们的对象使用该对象原型来继承属性和方法。

假设您使用对象字面量语法创建了一个对象:

JavaScript 代码:

1
const car = {};

JavaScript 代码:

1
const car = new Object();

在任何情况下,car 的 prototype(原型) 是 Object :

如果初始化一个数组,数组其实也是一个对象:

JavaScript 代码:

1
2
3
const list = [];
//or
const list = new Array();

这里 list 的 prototype(原型) 是 Array :

您可以通过检查 __proto__ getter 来验证这一点:

JavaScript 代码:

1
2
3
4
5
car.__proto__ === Object.prototype; //true
car.__proto__ === new Object().__proto__; //true
list.__proto__ === Object.prototype; //false
list.__proto__ === Array.prototype; //true
list.__proto__ === new Array().__proto__; //true

我在这里使用 __proto__ 属性,这是历史遗留的非标准的语法,但在现代浏览器中广泛实现。获得原型的更可靠方法是使用 Object.getPrototypeOf(new Object());例如:

JavaScript 代码:

1
2
3
4
5
const car = {};
const list = [];

console.log(Object.getPrototypeOf(car));
console.log(Object.getPrototypeOf(list));

我们可以在控制台中看到,他们的 constructor 属性分别是 Object() 和 Array();

getPrototypeOf.png

原型中的所有属性和方法对于拥有原型的对象都是可用的:

list.png

Object.prototype 是所有对象的基本原型:

JavaScript 代码:

1
Array.prototype.__proto__ == Object.prototype; //true

如果你想知道 Object.prototype 的原型是什么,那就没有原型。 这是一种特殊的,独一无二的的对象。(❄️)

您看到的上面的示例是工作中的原型链的示例。

我可以创建一个对象来扩展 Array 的对象,和任何我用它实例化的对象,在其原型链中将包含 Array 和 Object,并从所有祖先继承属性和方法。

除了使用 new 运算符创建对象,或使用对象和数组的字面量语法之外,还可以使用 Object.create() 实例化对象。

3 种方式实例化对象

传递的第一个参数是用作原型的对象:

JavaScript 代码:

1
2
const car = Object.create({});
const list = Object.create(Array);

您可以使用 isPrototypeOf() 方法检查对象的原型:

JavaScript 代码:

1
2
Array.isPrototypeOf(list); //true
Object.isPrototypeOf(list); //false

请注意,因为您可以使用以下方式实例化一个数组

JavaScript 代码:

1
const list = Object.create(Array.prototype);

在这种情况下,Array.isPrototypeOf(list) 为 false,而 Array.prototype.isPrototypeOf(list) 为 true 。

关于 JavaScript prototype(原型) 的相关知识,可以查看 JavaScript Prototype(原型) 新手指南 详细了解。

6 步 从一个对象, 到封装成函数, 用Object.create(), prototype, new, class

再看 Object.create()这个是原型继承, 也可不用, 自己 =, 注意constructor自己设置

然后是Object.create()的原理呗, 不支持的浏览器用代替的, 一起记了. 和 new 区别

1
2
3
4
5
6
7
8
if (Object.create) {
return Object.create(obj);
} else {
// 创建构造函数 Fun
function Fun() {}
Fun.prototype = obj;
return new Fun();
}

看完再看 补充

javascript原型

看完了class的是原型的糖, 那么可以知道 extends 也是原型糖, 即son.prototype = new F() 子的原型指向父的一个实例

参考

原型继承 – JavaScript 完全手册(2018 版)

javascript-数据类型判断

发表于 2019-05-09 | 分类于 JavaScript完全手册(2018版)

javascript-数据类型判断

JavaScript 数据类型判断 666

javascript 由于各种各样的原因,在判断一个变量的数据类型方面一直存在着一些问题,其中最典型的问题恐怕就是 typeof null 会返回 object 了吧。因此在这里简单的总结一下判断数据类型时常见的陷阱,以及正确的处理姿势。

javascript 数据类型

MDN 数据类型

更详细, 除了 5+1 还有 Symbol, 以及对象的特性, 新数据解构 Map, Set

数据类型

这里先谈一下 JavaScript 这门语言的数据类型。JavaScript 中有七种数据类型,其中有六种简单数据类型(原始烈性),一种复杂数据类型。

首字母大写的Undefined表示的是一种数据类型,首字母小写的undefined表示的是属于这种数据类型的唯一的一个值。

六种简单数据类型

  • String
  • Number
  • Boolean
  • Null
  • Undefined
  • Symbol (ECMAScript 6 新定义)

复杂数据类型

  • Object 是唯一的复杂数据类型。 Object , Array , Function 这些引用类型值最终都可以归结为 Object 复杂数据类型。

各种陷阱

typeof 的陷阱

MDN typeof

typeof 是用来检测变量数据类型的操作符,对一个值使用 typeof 操作符可能会返回下列某个字符串

  • “undefined” — 如果这个变量只定义没初始化, 用 typeof 如果这个变量未定义或全局的undefined属性
  • “string” — 如果这个变量初始化为String字符串类型
  • “boolean” — 如果这个变量初始化为Boolean布尔类型值
  • “number” — 如果这个变量初始化为Number数值类型
  • “symbol” — 如果这个变量初始化为Symbol数值类型
  • “object” — 如果这个变量初始化为Object对象或 Array数组 或者 Null类型的 null
  • “function” — 如果这个变量初始化为Function函数

数组确实是对象, 但我们想更具体区分 是不是一个数组.

示例, MDN 666666 展示很多易错点

例如注意NAN 还是number, 还有不要使用包装类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
typeof Number(1) === 'number'; // 但不要使用这种形式!

// Strings
typeof '' === 'string';
typeof 'bla' === 'string';
typeof typeof 1 === 'string'; // typeof总是返回一个字符串
typeof String('abc') === 'string'; // 但不要使用这种形式!

// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!

// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';

// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';

// Objects
typeof { a: 1 } === 'object';

// 使用Array.isArray 或者 Object.prototype.toString.call
// 区分数组,普通对象
typeof [1, 2, 4] === 'object';

typeof new Date() === 'object';

// 下面的容易令人迷惑,不要使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';

// 函数
typeof function() {} === 'function';
typeof class C {} === 'function';
typeof Math.sin === 'function';
typeof new Function() === 'function';

1. Object 对象检测的陷阱

JavaScript 代码:

1
2
3
4
5
6
function isObj(obj) {
if (typeof obj === 'object') {
return 'It is object';
}
return 'It is not object';
}

这个函数的本意是想检测传入的参数是否是 Object 对象。但是这个函数其实是非常不安全的。

比如

JavaScript 代码:

1
2
3
4
5
var a = [1, 2, 3];
isObj(a); // 'It is object'

var b = null;
isObj(b); // 'It is object'

这样明显是不对的,因为 typeof [] 和 typeof null 都是是会返回 ‘object‘ 的。

2. Array 对象检测的陷阱

JavaScript 代码:

1
typeof []; //  'object'

上面说到了对一个数组使用 typeof 操作符也是会返回 'object',因此 typeof 并不能判断数组对象的类型

typeof 在判断复杂数据类型不够细致

instanceof 的陷阱 与 基本包装类型

1. instanceof

MDN instanceof

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象的原型链中的任何位置

从实例往上走和从构造函数往上走能不能到同一个原型.
看原型链那张图

2. 基本包装类

《Javascript》高级程序设计 第五章第六节 基本包装类型

javascript 为了方便操作基本类型值,ECMAscript 提供了 3 个特殊的引用类型:Boolean、Number 和 String。 每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。

注意不是永久有方法的, 只是暂时的

JavaScript 代码:

1
2
var s1 = 'some text';
var s2 = s1.substring(2);

上面的代码中,先创建了一个字符串保存在了变量 s1,字符串当然是基本类型值。但是在下一行中我们又调用了 s1 的方法。我们知道基本类型值不是对象,理论上它不应该拥有方法(但它们确实有方法)。其实,为了让我们实现这种直观的操作,后台已经帮助我们完成了一系列的操作。当我们在第二行代码中访问 s1 变量时,访问过程处于读取模式,而在读取模式中访问字符串时,后台都会自动完成下列处理。

  1. 创建 String 类型的一个实例;
  2. 在实例上调用指定的方法;
  3. 销毁这个实例。

可以将以上三个步骤想像成是执行了下列代码

JavaScript 代码:

1
2
3
var s1 = new String('some text');
var s2 = s1.substring(2);
s1 = null;

3. instanceof 判断基本类型值的陷阱

上面提到 3 种基本包装类,就是为了说明 instanceof 这个陷阱

JavaScript 代码:

1
2
var str = 'text';
str instanceof String; // false

本来我也是想当然的认为 str instanceof String 会使 str 变量处于读取模式,自动建立基本包装类。但是根据上述代码所体现表象来看,instanceof 运算符是直接访问的变量的原始值。

因此 instanceof 并不能用来判断五种基本类型值

4. instanceof 判断 Object 类型的陷阱

这里先说一下,用 instanceof 判断 Array 类型基本上是非常 ok的

JavaScript 代码:

1
2
var arr = [1, 2, 3];
arr instanceof Array; // true

但是 instanceof 却不能安全的判断 Object 类型,因为 Array 构造函数是继承自 Object 对象的,因此在 arr 变量上是可以访问到 Object 的 prototype 属性的。如下例所示:

JavaScript 代码:

1
2
3
var arr = [1, 2, 3];
arr instanceof Object; // true
// 会返回 true ,是因为 Object 构造函数的 prototype 属性存在与 arr 这个数组实例的原型链上。

所以 instanceof 只用来判断 Function么

一个高效但危险的变量类型判断方法

用对象的 constructor 来判断对象类型

stack overflow上有人做了实验,说是目前运算最快的判断变量类型的方式。

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function cstor(variable) {
var cst = variable.constructor;

switch (cst) {
case Number:
return 'Number';
case String:
return 'String';
case Boolean:
return 'Boolean';
case Array:
return 'Array';
case Object:
return 'Object';
case Function:
return 'Function';
}
}

上面是一个判断变量类型的方法,工作的非常高效完美。但是用 constructor 判断变量类型有一个致命的缺陷,就是当检测 null 或者 undefined 类型的 constructor 属性时,js 会报错!

也就是说下面代码会报错!

JavaScript 代码:

1
2
cstor(null); // 若传入 null 或者 undefined 作为参数时
// cstor 函数第一行就会报错,因为 null 和 undefined 根本就没有 constructor 属性

因此我们在利用变量的 constructor 属性来判断变量类型时,必须要先保证变量有 不会是 null 或者 undefined。

改造以上函数如下:

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function cstor(variable) {
if (variable === null || variable === undefined) {
return 'Null or Undefined';
}

var cst = variable.constructor;

switch (cst) {
case Number:
return 'Number';
case String:
return 'String';
case Boolean:
return 'Boolean';
case Array:
return 'Array';
case Object:
return 'Object';
case Function:
return 'Function';
}
}

所以说使用 constructor 来判断对象类型时要无时无刻不伴随着排除 null 和 undefined 的干扰,否则就会产生致命的问题,因此本人并不推荐。

正确判断变量类型的姿势

一个万金油方法 Object.prototype.toString.call()

MDN reference

Object.prototype.toString.call(variable) 用这个方法来判断变量类型目前是最可靠的了,它总能返回正确的值。

该方法返回 “[object type]“, 其中type是对象类型。

JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Object.prototype.toString.call(123); //  "[object Number]"

Object.prototype.toString.call('123'); // "[object String]"

Object.prototype.toString.call(false); // "[object Boolean]"

Object.prototype.toString.call(undefined); // "[object Undefined]"

Object.prototype.toString.call(null); // "[object Null]"

Object.prototype.toString.call([]); // "[object Array]"

Object.prototype.toString.call(function a() {}); // "[object Function]"

Object.prototype.toString.call({}); // "[object Object]"

String Boolean Number Undefined 四种基本类型的判断

除了 Null 之外的这四种基本类型值,都可以用 typeof 操作符很好的进行判断处理。

当然也可以用 Object.prototype.toString.call(null)

Symbol 类型 和 引用类型 Function 也可以

JavaScript 代码:

1
2
3
4
5
6
7
typeof 'abc'; // "string"

typeof false; // "boolean"

typeof 123; // "number"

typeof undefined; // "undefined"

Null 类型的判断

除了 Object.prototype.toString.call(null) 之外,目前最好的方法就是用 variable === null 全等来判断了。

JavaScript 代码:

1
2
3
4
5
6
7
var a = null;

if (a === null) {
console.log('a is null');
}

// a is null

检测变量是否是一个 Array 数组

typeof [] 会返回 object 因此明显是不能够用 typeof 操作符进行数组类型判断的。目前常用的方法有以下几种

1. Object.prototype.toString.call()

万金油方法是一种。

2. ECMAscript5 新增 Array.isArray()

JavaScript 代码:

1
Array.isArray([]); // true

3. instanceof 运算符 陷阱

MDN reference

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。但前面说了 这个不准确.

javascript原型

因此可以检测一个对象的原型链中是否存在 Array 构造函数的 prototype 属性来判断是不是数组。

JavaScript 代码:

1
[] instanceof Array; // true

检测变量是否是一个 Object 对象

typeof 和 instanceof 都不能安全的判断变量是否是 Object 对象。

目前判断变量是否是对象的最安全的方法就只有 Object.prototype.toString.call() 了。

Function 这块可以继续总结补充, 补充 Symbol 类型

用 typeof 可以, 用 instanceof 可以, 用Object.prototype.toString.call()也可以

instanceof 主要用来判断引用类型的, 不能判断 Symbol 类型

参考

JavaScript 数据类型判断 666

javascript-数据类型

发表于 2019-05-09 | 分类于 JavaScript完全手册(2018版)

javascript-数据类型

数据类型 – JavaScript 完全手册(2018 版)6666

您有时可能会读到 JS 是无类型的,但这是不正确的。 确实,您可以将各种不同类型分配给变量,但 JavaScript 具有类型。 特别是,它提供了原始类型和对象类型。

原始类型

原始类型包括:5+1(Symbol)

Number(数字)
String(字符串)
Boolean(布尔)
还有两种特殊的原始类型:

Null(空值)
Undefined(未定义)
让我们在这里详细介绍它们。

Number(数字)

在内部,JavaScript 只有一种数字类型:每个数字都是一个浮点数。

数字字面量是源代码中表示的数字,并且取决于它的编写方式,它可以是整数字面量或浮点数字面量。

整数:

1
2
3
4
JavaScript 代码:
10
5354576767321
0xCC //hex

浮点数:

1
2
3
4
JavaScript 代码:
3.14
.1234
5.2e4 //5.2 * 10^4

实际工作中你会碰到很多不可思议的问题,特别是浮点数运算的精度问题,请查看以下几篇文章,了解相关问题及解决方案:

JavaScript 浮点数运算的精度问题
JavaScript 中科学计数法转化为数值字符串形式
JavaScript 格式化数字、金额、千分位、保留几位小数、舍入舍去…

理解IEEE 754 的结构对理解最大值, 最小值很有用. 但注意安全整数这一回事, 还涉及指数为0是正负0和指数为2047的表示无穷大2个和NAN有2^53-2, 就是去掉2个无穷
ECMAScript中的Number Type与 IEEE 754-2008 安全整数

String(字符串)

字符串类型是一系列字符。它在源代码中定义为字符串字面量,用单引号或双引号括起来:

JavaScript 代码:

1
2
'A string';
'Another string';

通过使用反斜杠 \ ,字符串可以换行

只是输入的时候可以换行输入, 而不是输出的时候显示是换行的
要做到输出时候是换行的要用字符串模板, 或使用\n换行

JavaScript 代码:

1
2
'A \
string';

字符串可在打印字符串时解析转义序列,例如 \n 以创建一个新行。当您需要在引号括起的字符串中输入引号时,反斜杠也很有用,以防止将字符解释为结束引号:

JavaScript 代码:

1
'I\'m a developer';

可以使用 + 运算符连接字符串:

JavaScript 代码:

1
'A ' + 'string';

模板字符串

在 ES2015(ES6) 中引入,模板字符串是字符串字面量,允许更强大的方式来定义字符串。

JavaScript 代码:

1
`a string`;

您可以执行字符串替换,嵌入任何 JavaScript 表达式的结果:

JavaScript 代码:

1
2
`a string with ${something}``a string with ${something +
somethingElse}``a string with ${obj.something()}`;

您可以轻松拥有多行字符串:, 不用加转义的\n

JavaScript 代码:

1
2
3
`a string
with
${something}`;

Boolean(布尔)

JavaScript 为布尔值定义了两个保留字:true 和 false 。 许多比较操作 == === < >(依此类推)返回一个布尔值。

if ,while 语句和其他控制结构使用布尔值来确定程序的流程。

他们不仅接受true 或 false,还接受 真值 和 假值。

假值,值被解析为 false,有

JavaScript 代码:

1
2
3
4
5
0 - 0;
NaN;
undefined;
null;
(''); //empty string

其余所有的值都被解析为 真值(truthy) 。

实际工作中我们还会碰到等值比较,请查看 JavaScript 等值比较 == ,=== 和 Object.is() 了解详情。

JavaScript-Equality-Table

Null

null 是一个特殊值,表示缺少值,Null这种类型就只有一个值 null。 这也是其他语言中的常见概念,例如在 Python 中可以称为 nil 或 None 。

Undefined

undefined 表示变量尚未初始化且值不存在。

它通常由没有返回值的函数返回。 当一个函数接受一个但不是由调用者设置的参数时,它是未定义的。

要检测值是否未定义,请使用构造:

JavaScript 代码:

1
typeof variable === 'undefined';

JavaScript 新手很容易混淆 undefined 和 null ,请阅读 JavaScript 中 undefined 和 null 的区别 666 了解。

首字母大写的Undefined表示的是一种数据类型,首字母小写的undefined表示的是属于这种数据类型的唯一的一个值。

Object(对象) 类型

任何不是原始类型的东西都是对象类型。

函数,数组和我们称之为对象的是对象类型。 它们本身是特殊的,但是它们继承了对象的许多属性,比如具有原型,并且还有对这些属性起作用的方法。

Object 是唯一的复杂数据类型。 Object , Array , Function 这些引用类型值最终都可以归结为 Object 复杂数据类型。

看 js的数组 里面还有介绍对象的特性, 访问器属性.

然后涉及Map set JSON这些

类型判断

实际开发工作中,我们会经常碰到 JavaScript 数据类型判断,阅读 JavaScript 数据类型判断 666 了解 JavaScript 数据类型判断的陷阱 与 最佳的处理方式。

对象类型

参考

数据类型 – JavaScript 完全手册(2018 版)6666

JavaScript 浮点数运算的精度问题
JavaScript 中科学计数法转化为数值字符串形式
JavaScript 格式化数字、金额、千分位、保留几位小数、舍入舍去…

JavaScript 等值比较 == ,=== 和 Object.is() 666
JavaScript-Equality-Table
JavaScript 中 undefined 和 null 的区别 66666
JavaScript 数据类型判断 666

javascript-变量

发表于 2019-05-09 | 分类于 JavaScript完全手册(2018版)

javascript-变量

变量 – JavaScript 完全手册(2018 版)6666

变量是分配给标识符的字面量,因此您可以稍后在程序中引用和使用它。 我们将学习如何使用 JavaScript 声明一个变量。

JavaScript 变量简介

变量是分配给标识符的字面量,因此您可以稍后在程序中引用和使用它。

JavaScript 中的变量没有附加任何类型。 将特定字面量类型分配给变量后,您可以稍后重新分配该变量,以持有任何其他类型,而不会出现类型错误或任何问题。

这就是 JavaScript 有时被称为 “无类型” 的原因。
但不正确. 和javascript-数据类型中说的 有类型 捋一捋

建议先声明变量再使用它。 有 3 种方法可以做到:使用 var,let 或 const。 这三种方式在以后如何与变量进行交互方面有所不同。

let 或 const必须先声明变量才能使用它, 而var有变量提升
JavaScript 中的 Hoisting (变量提升和函数声明提升) 666 这里看提升的处理方式
由变量提升谈谈 JavaScript Execution Context.
JavaScript 中作用域和作用域链的简单理解(变量提升)

使用 var

在 ES2015 之前,var 是唯一可用于定义变量的构造。

JavaScript 代码:

1
var a = 0;

如果您忘记添加 var ,您将为未声明的变量分配值,结果可能会有所不同。

在现代环境中,启用严格模式后,您将收到错误。 在较旧的环境中(或禁用严格模式),这将简单地初始化变量并将其分配给全局(global)对象,在浏览器中,全局对象是 window,在 Node.js 中,全局对象是 global 。

注意分配给全局对象和声明变量一个全局变量是不一样的, 就看 Hoist 的问题, 会不会提升, 虽然最后都是当做 window 的一个属性, 但声明的要执行到那条语句才有. 看了 execution context 就大致懂

如果在声明变量时没有初始化变量,则在为其赋值之前,它将具有 undefined (未定义) 的值。

JavaScript 代码:

1
var a; //typeof a === 'undefined'

您可以多次重新声明变量,以覆盖它:(注意这里和仅仅 hoist 不同, hoist时, 对函数声明是按覆盖来, 对变量就是忽略, 反正都是 undefined. 这里肯定是执行时才覆盖的.)

JavaScript 代码:

1
2
var a = 1;
var a = 2;

您还可以在同一语句中一次性声明多个变量:

JavaScript 代码:

1
2
var a = 1,
b = 2;

作用域是代码中变量的可见性。

使用任何函数外部的 var 初始化的变量将分配给全局对象,具有全局作用域并且是任何地方可见。
在函数内部用 var 初始化的变量,被赋值变量的作用域是该函数,它被称为 local(本地)作用域 或 函数作用域,只在函数内可见,就像函数参数一样。

函数中定义与全局变量名称的任何变量,可见性优先于全局变量,并将全局变量隐藏。

作用域链的知识点

重要的是要理解一个 block(块)(由一对花括号{}标识)没有定义新的作用域。在用 let 和 const 后, 那么就有块作用域了.

只有在创建函数时才会创建新作用域,因为 var 没有块作用域,而是函数作用域。

在函数内部,其中定义的任何变量在所有函数代码中都是可见的(前后顺序无关),即使变量是在函数末尾声明的,它仍然可以在开头引用,因为 JavaScript 在执行代码之前实际上将所有变量都移到了顶层(被称为 hoisting(提升) )。为避免混淆,请始终在函数开头声明变量。

作用域对于新手来说很容易混淆,你可以查看 深入理解 JavaScript 中的作用域和上下文 和 实例分析 JavaScript 作用域 来深入理解作用域。

另外 Hoisting(提升) 这个词是用来解释 变量 和 函数声明 是如何被提升到 函数或全局 作用域顶部的。

你在任何的 JavaScript 文档中找不到这个术语,我们说的 Hoisting(提升) 只是使用了其字面含义来做个比喻。如果你已经对 JavaScript 作用域工作原理有基本的了解,那么更深入的了解 JavaScript 中的 Hoisting (变量提升和函数声明提升) 有助于你建立更强大的基础知识。

也可以看总结的 再谈js作用域

使用 let

let 是 ES2015 中引入的新功能,它本质上是 var 的块作用域版本。 它的作用域仅限于定义它的 block(块)(由一对花括号标识),语句或表达式,以及所有包含的内部块。

现代 JavaScript 开发人员可能会选择仅使用 let 并完全放弃使用 var。

let 也可以在任何函数之外定义 – 与 var 相反 – let 不会创建全局变量。

使用 const

用 var 或 let 声明的变量可以稍后在程序中更改,然后重新分配。 初始化 const 后,其值永远不会再次更改,并且不能重新分配给不同的值。

JavaScript 代码:

1
const a = 'test';

我们不能为 a 常量指定不同的字面量。然而,如果 a 是一个提供方法的对象,那么我们可以更改 a 内容。

可以改 a 的内容, 不是改 a 的引用的值

const 不提供不可变性(immutability),只是确保不能更改引用。

const 具有块范围,与 let 相同。

现代 JavaScript 开发人员可能会选择始终将 const 用于不需要在程序中稍后重新分配的变量。

为什么? 因为我们应该始终使用最简单的结构,以避免在未来发生错误。

参考

变量 – JavaScript 完全手册(2018 版)6666

深入理解 JavaScript 中的作用域和上下文
JavaScript 核心概念之作用域和闭包
实例分析 JavaScript 作用域
JavaScript 中的 Hoisting (变量提升和函数声明提升)

再谈js作用域

typescript代码检查

发表于 2019-05-08 | 分类于 前端教程

typescript 代码检查

主要用来统一代码风格

tslint 被弃用了

代码检查

目前 TypeScript 的代码检查主要有两个方案:使用 TSLint 或使用 ESLint + typescript-eslint-parser。

什么是代码检查

代码检查主要是用来发现代码错误、统一代码风格。

在 JavaScript 项目中,我们一般使用 ESLint 来进行代码检查。它通过插件化的特性极大的丰富了适用范围,搭配 typescript-eslint-parser 之后,甚至可以用来检查 TypeScript 代码。

TSLint 与 ESLint 类似,不过除了能检查常规的 js 代码风格之外,TSLint 还能够通过 TypeScript 的语法解析,利用类型系统做一些 ESLint 做不到的检查。

为什么需要代码检查

有人会觉得,JavaScript 非常灵活,所以需要代码检查。而 TypeScript 已经能够在编译阶段检查出很多问题了,为什么还需要代码检查呢?

因为 TypeScript 关注的重心是类型的匹配,而不是代码风格。当团队的人员越来越多时,同样的逻辑不同的人写出来可能会有很大的区别:

  • 缩进应该是四个空格还是两个空格?
  • 是否应该禁用 var?
  • 接口名是否应该以 I 开头?
  • 是否应该强制使用 === 而不是 ==?
  • 这些问题 TypeScript 不会关注,但是却影响到多人协作开发时的效率、代码的可理解性以及可维护性。

下面来看一个具体的例子:

配置

先看链接中各个链接的内容

How do I configure my project to use typescript-eslint? 666

在 eslint-plugin 中设置的 rules

Supported Rules

点击去就能看具体设置, 比如indent, 默认是4个space, 我们改为改2个space

1
2
3
4
5
{
// note you must disable the base rule as it can report incorrect errors
"indent": "off",
"@typescript-eslint/indent": ["error", 2, {"SwitchCase": 1}]
}

参考

代码检查 666666
TSLint Deprecated to Focus Support on typescript-eslint
The future of TypeScript on ESLint
Eslint 和 Tslint 使用指南
使用 ESLint+Prettier 规范 React+Typescript 项目 666
How do I configure my project to use typescript-eslint? 666

2019前端练级攻略

发表于 2019-05-07 | 分类于 年计划

2019 前端练级攻略

对于前端的学习和提高,我的基本思路是这样的。首先,前端的三个最基本的东西 HTML5、CSS3 和 JavaScript(ES6)是必须要学好的。这其中有很多很多的技术,比如,CSS3 引申出来的 Canvas(位图)、SVG(矢量图) 和 WebGL(3D 图),以及 CSS 的各种图形变换可以让你做出非常丰富的渲染效果和动画效果。

ES6 简直就是把 JavaScript 带到了一个新的台阶,JavaScript 语言的强大,大大释放了前端开发人员的生产力,让前端得以开发更为复杂的代码和程序,于是像 React 和 Vue 这样的框架开始成为前端编程的不二之选。

我一直认为学习任何知识都要从基础出发,所以我会有很大的篇幅在讲各种技术的基础知识和基本原理,尤其是如下的这些知识,都是前端程序员需要一块一块啃掉的硬骨头。

  • JavaScript 的核心原理。这里我会这里重点需要掌握的知识点而不是书。
  • 浏览器的工作原理。这也是一块硬骨头,我觉得这是前端程序员需要了解和明白的东西,不然,你将无法深入下去。
  • 网络协议 HTTP。也是要着重了解的,尤其是 HTTP/2,还有 HTTP 的几种请求方式:短连接、长连接、Stream 连接、WebSocket 连接。
  • 前端性能调优。有了以上的这些基础后,你就可以进入前端性能调优的主题了,我相信你可以很容易上手各种性能调优技术的。
  • 框架学习。我只给了 React 和 Vue 两个框架。就这两个框架来说,Virtual DOM 技术是其底层技术,组件化是其思想,管理组件的状态是其重点。而对于 React 来说,函数式编程又是其编程思想,所以,这些基础技术都是你需要好好研究和学习的。
  • UI 设计。设计也是前端需要做的一个事,比如像 Google 的 Material UI,或是比较流行的 Atomic Design 等应该是前端工程师需要学习的。

原文链接给出的都是要看的文章或图书, 我这里整理各个知识点
程序员练级攻略(2018):前端基础和底层原理 666

JavaScript 的核心原理

变量

  1. 数据类型、判断方法
  2. 执行上下文
  3. 变量对象、活动对象
  4. 原型、原型链 javascript原型
  5. 作用域、作用域链 js作用域链和闭包 再谈js作用域 静态作用域与动态作用域
  6. 闭包、垃圾回收机制
  7. this 指向 javascript中this指向由函数调用方式决定
  8. 类和模块
  9. 继承
  10. 函数式编程
  11. 同步异步 JavaScript-的-async-await async-function-await 使用Promise
  12. JS 正则表达式
  13. 事件模型 js事件处理
  14. Ajax、跨域访问 前端的网络请求方式和http
  15. DOM
  16. BOM
js函数 js的数组

CSS3

HTML

浏览器的工作原理

这个文章说的总纲 从输入URL到页面加载发生了什么
chrome的console功能

网络协议 HTTP

http3xx重定向状态码 CDN原理 DHCP原理

前端性能调优

框架学习

React

react-router-v4 react-router React项目结构和组件命名之道 travis配置文件的编写 tsconfig-json配置解析 webpack简单入门

UI 设计

总结下不同实际项目开始的准备, 不用 CLI

比如用 typescript 和 webpack 来写 react 项目.

prettier代码格式美化

其他

docker: docker的简单使用

git: git入门中 常用git命令总结

参考

程序员练级攻略(2018):前端基础和底层原理 666
2019-TODO-list
JavaScript 完全手册(2018版)这网站真的很不错6666666

mac下用键盘控制程序窗口大小位置

发表于 2019-05-06 | 分类于 mac技巧

mac 下用键盘控制程序窗口大小位置

mac 上使用鼠标来拖动程序窗口大小和位置有点麻烦, 用 spectacle 的默认设置就方便很多

下载后打开记得要勾上
security.png

使用方法就用默认的好了, 配合系统自带的ctl+cmd+f全屏, 它的option+cmd+f是最大化
spectacle.png

参考

spectacle

mac在多个屏幕间切换焦点

发表于 2019-05-06 | 分类于 mac技巧

mac 在多个屏幕间切换焦点

想用键盘来控制屏幕的切换, 尤其是我们使用了多个屏幕的时候.
如果使用 mac 自带的ctrl+1和ctrl+2虽然也可以在两个桌面之间切换, 但鼠标还是失去焦点的, 所以使用ctrl+←或ctrl+→切换 space 时还是只在有鼠标焦点的屏幕上切换.

所以我们只是需要用来切换两个屏幕之间鼠标焦点, 推荐用CatchMouse

使用前记得要取消 mac 系统设置的ctrl+1和ctrl+2

keyboard.png

换上 CatchMouse 的

catchMouse.png

参考

Mac 下双屏切换
CatchMouse

1…345…14
Henry x

Henry x

this is description

133 日志
25 分类
135 标签
GitHub E-Mail
Links
  • weibo
© 2019 Henry x