gzl的博客

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

JS强制类型转换

发表于 2019-08-06 更新于 2019-08-07 分类于 JavaScript

显式强制类型转换

字符串和数字之间的显式转换

1
2
3
4
5
6
7
8
let a = 42;
let b = String(a);

let c = "3.14";
let d = Number(c);

console.log(b); // "42"
console.log(d); // 3.14

除了 String() 和 Number() 以外,还有其他方法:

1
2
3
4
5
6
7
8
let a = 42;
let b = a.toString();

let c = "3.14";
let d = +c;

console.log(b); // "42"
console.log(d); // 3.14

日期显式转换为数字

1
2
let d = new Date();
console.log(+d); // 1565074622713

我们下面的方法获取当前的时间戳:

1
2
3
let timestamp1 = +new Date();
let timestamp2 = new Date().getTime();
let timestamp3 = Date.now();

奇特的 ~ 运算符

~ 可以和 indexOf() 一起将结果强制类型转换:如果 indexOf() 返回 -1,~ 将其转换为假值0,其他情况一律转换为真值。

1
2
3
4
5
6
7
let a = "Hello World";
console.log(~a.indexOf("H")); // -1
console.log(~a.indexOf("lo")); // -4
console.log(~a.indexOf("ol")); // 0
if (~a.indexOf("lo")) {
// 找到匹配
}

显式解析数字字符串

1
2
3
4
let a = "42";
let b = "42px";
console.log(Number(a)); // 42
console.log(parseInt(a)); // 42

显式转换为布尔值

虽然Boolean是显式的,但并不常用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a = "0";
let b = [];
let c = {};

let d = "";
let e = 0;
let f = null;
let g;

Boolean(a) // true
Boolean(b) // true
Boolean(c) // true

Boolean(d) // false
Boolean(e) // false
Boolean(f) // false
Boolean(g) // false

常用的是 !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a = "0";
let b = [];
let c = {};

let d = "";
let e = 0;
let f = null;
let g;

console.log(!!a) // true
console.log(!!b) // true
console.log(!!c) // true

console.log(!!d) // false
console.log(!!e) // false
console.log(!!f) // false
console.log(!!g) // false

隐式强制类型转换

字符串和数字之间的隐式转换

1
2
3
4
5
6
7
8
let a = "42";
let b = "0";

let c = 42;
let d = 0;

console.log(a + b); // "420"
console.log(c + d); // 42
1
2
3
let a = [1,2];
let b = [3,4];
console.log(a + b); // "1,23,4"

简单来说,如果 + 的其中一个操作数是字符串(或者经过一系列操作得到字符串),则执行字符串的拼接,否则执行数字加法。

1
2
3
let a = "3.14";
let b = a - 0;
console.log(b); // 3.14

a - 0 会将 a 强制类型转换为数字。执行减法运算,a 和 b 都需要转换为数字。

隐式转换为布尔值

  1. if() 语句中的条件判断表达式
  2. for() 语句中的条件判断表达式(第二个)
  3. while() 和 do.while() 中的条件判断表达式
  4. ? : 中的条件判断表达式
  5. 逻辑运算符 || 和 && 左边的操作数

在以上情况中,非布尔值会被隐式强制类型转换为布尔值。

JS函数传参

发表于 2019-08-05 更新于 2019-11-30 分类于 JavaScript

首先,函数传参不论是传递基本类型值还是引用类型值,都相当于最基本的赋值语句 x = a

When we pass primitive values into a function, the function copies the values into its parameters. It’s effectively the same as using =.

函数传参-基本类型值

1
2
3
4
5
6
function foo(x) {
x = x + 1;
}
let a = 2;
foo(a);
console.log(a); // 2

上面的传参过程就相当于基本的赋值 x = a,然后 x ++,a 不会随之改变。

如果想要改变基本类型值,需要这样借助引用类型值:

1
2
3
4
5
6
7
8
function foo(wrapper) {
wrapper.a = 42;
}
let obj = {
a: 2
}
foo(obj);
console.log(obj); // {a: 42}

函数传参-引用类型值

1
2
3
4
5
6
7
8
9
10
11
function foo(x) {
x.push(4);
console.log(x); // [1, 2, 3, 4]
x = [4,5,6]; // 赋值新数组改变了 x 的引用
x.push(7);
console.log(x); // [4, 5, 6, 7]
}
let a = [1,2,3];
foo(a);
console.log(a); // [1, 2, 3, 4]
// 这段代码相当于 x = a 然后 x.push(4),然后 x = b

观察上面的代码可以看到,a 在 x.push(4) 之后变为 [1,2,3,4] 。 x = [4,5,6] 并不能影响 a 的指向,所以 a 仍然指向 [1,2,3,4]。相当于下面这样(其实就是引用类型的赋值操作):

1
2
3
4
5
6
7
8
9
let a = [1,2,3];
let x = a;
x.push(4);
console.log(x); // [1, 2, 3, 4]
console.log(a); // [1, 2, 3, 4]
x = [4,5,6]; // 这里的重新赋值改变了 x 的指向
x.push(7);
console.log(x); // [4, 5, 6, 7]
console.log(a); // [1, 2, 3, 4]

如果要将 a 的值变为[4,5,6,7],必须更改 x 原本指向的数组,而不是为 x (更改指向)赋值一个新的数组。

1
2
3
4
5
6
7
8
9
function foo(x) {
x.length = 0; // 清空数组 没有赋值新数组所以没有改变 x 的引用,x 和 a 的指向相同
x.push(4,5,6,7);
console.log(x); // [4, 5, 6, 7]
}
let a = [1,2,3];
foo(a);
console.log(a); // [4, 5, 6, 7]
// 这段代码相当于 x = a 然后的操作并未将 x 指向新的引用

如果我们传递一个 a.slice(),那么这个过程就相当于 x = a.slice(),即进行了一次浅拷贝。

1
2
3
4
5
6
7
8
9
function foo(x) {
x[1] = 4;
x[3].name = "JS";
console.log(x); // [1, 4, 3, {name: "JS"}]
}
let a = [1,2,3,{name:"gzl"}];
foo(a.slice());
console.log(a); // [1, 2, 3, {name: "JS"}]
// 这段代码中使用了slice

JS基本包装类型

发表于 2019-08-05 更新于 2019-08-06 分类于 JavaScript

基本包装类型

由于基本类型值没有 .length 和 .toString() .toFixed()这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为基本类型值包装一个封装对象。

1
2
3
let s1 = "some text";
let s2 = s1.substring(2);
console.log(s2) // me text

上面的代码其实在后台进行了下面的一系列处理:

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

可以想象成是执行了下列的 ECMAScript 代码

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

上面的三个步骤也适用于 Boolean 和 Number 类型对应的布尔值和数字值。

引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法。比如下面这个例子:

1
2
3
let s1 = "some text";
s1.color = "red";
console.log(s1.color); // undefined

问题就在于 第二行创建的 String 对象在执行 第三行代码时已经被销毁了,第三行代码又创建自己的 String 对象,而该对象没有 color 属性。

不推荐主动进行 new String、new Number、new Boolean 的操作。

1…202122…32

gzl

96 日志
14 分类
37 标签
© 2020 gzl
由 Hexo 强力驱动 v3.7.1
|
主题 – NexT.Pisces v7.2.0