你不知道的 JavaScript (中)

前端之家收集整理的这篇文章主要介绍了你不知道的 JavaScript (中)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

类型

JavaScript 中有七种内置类型: null,undefined,boolean,number,string,object,其他的类型称为基本类型

变量没有类型, 只有变量的值有类型。

可以使用 typeof 运算符查看值的类型。 需要注意的是 typeof null 的结果是 object

undefined 和 undeclared

变量声明后在未持有值的时候为 undefined,但是如果没有在作用域中声明变量,却使用了变量是 undeclared 的。

var a;
a //undefined
b //undeclared

使用 undeclared 的变量会导致浏览器报错。
可以使用下面两种方法来避免报错。

if (DEBUG) { // DEBUG is not defined.    
}

if (typeof DEBUG !== "undefined") {
}

或者是

if (window.DEBUG) {}

数组

可以使用 delete 运算符删除数组中的元素, 但是删除后该数组的 length 不会发生变化。

稀疏数组

稀疏数组是含有空白或者空缺单元的数组。

var a = [];
a[0] = 1;
a[2] = 3;
a[1] // undefined

a.length // 3

空白单元可能会产生意想不到的结果, 虽然与 a[1] = undefined 直接赋值的结果一致, 但是还是有所区别。
使用非数字的键值作为数组的索引,会导致数组的 length 属性不会增加

类数组

选取 DOM 元素的方法多是返回的是类数组, 但是有时候我们想调用 Array 上的函数来处理它, 这时候我们需要转换。

var doc = document.querySelectorAll('*');
doc = Array.prototype.slice.call(doc,0);

或者是使用 ES6 的内置函数也能实现下面的功能

doc = Array.from(doc);

字符串

JavaScript 中的字符串是不可变的, 而数组是可变的。

var a = "foo";
var b = ["f","o","o"];

a[1] = "O";
b[1] = "O";

a // "foo"
b // ["f","O","o"]

并且a[1]并不总是合法的语法,正确的方式是应该使用 a.charAt(1)

多数字符串的成员函数不会修改原有的字符串, 而是重新返回一个新的字符串。
许多数组的函数来处理字符串很方便, 虽然字符串没有这些函数, 但是可以通过将字符串转换数组的方式, 进行调用

var c = Array.prototype.join.call(a,"-");
var d = Array.prototype.map.call(a,function (v) {
    return v.toUpperCase() + '.';
});

c // "f-o-o"
d // "F.O.O"

数字

数字的部分语法

特别大的和特别小的数字用指数格式显示

var a = 5E10;
a // 50000000000
a.toExponential(); // "5e+10" 这是个字符串...

使用 toFixed 方法可以指定小数部分的显示位数:

var a = 42.59;

a.toFixed(0); // 43
a.toFixed(1); // 42.6
a.toFixed(2); // 42.59
a.toFixed(3); // 42.590

使用 toPrecision 方法制定有效位数的显示位数:

var a = 42.59;

a.toPrecision(1); // "4e+1"
a.toPrecision(2); // "43"
a.toPrecision(3); // "42.6"
a.toPrecision(4); // "42.59"
a.toPrecision(5); // "42.590"

上面方法不仅适用于数字变量, 而且还适用于数字常量。 不过对于 . 运算符需要注意, 它首先会被识别成数字常量的一部分,然后才会被认为是对象属性访问运算符。

42.toFixed(0); // Syntax Error

(42).toFixed(0);
0.42.toFixed(0);
42..toFixed(0);

较小的数字

应该如何在 JavaScript 当中判断 0.1 + 0.2 时候和 0.3 相等。
常见的方法是设置一个误差范围值, 从 ES6 开始这个值被定义在 Number.EPSILON 中。

特殊的数字

不是数字的数字

NaN 是一个数字类型, 但是它代表的意思却不是一个数字。

 var a = 2 / "foo" // NaN
typeof a === "number" // true

NaN 是唯一一个与自身不相等的值。
判断一个值是否是 NaN 方法是 使用 ES6Number.isNaN(), 现在已经不推荐使用 window.isNaN()

if (!Number.isNaN)  {
    Number.isNaN = function (n) {
        return n !== n;
    }
}

生成

打破完整运行

ES6 之前的语法中, 函数的运行不会被任何其他代码能够打断它的运行, 但是在 ES6 里, 新的 Generator 语法, 能够打断函数的执行。

var x = 1;

function *foo () {
x++;
yield;
console.log("x:",x);
}

function bar () {
x++;
}

我们要如何运行前面这段代码

var it = foo();

it.next(); // 在这条语句启动 foo
x; // 2
bar();
x; //3
it.next(); // x: 3

上面的代码做了这些事:

  1. it = foo() 运算并没有执行生成*foo(), 而是构造了一个迭代器, 这个迭代器会控制它的执行。

  2. 第一个 it.next() 启动了生成*foo(),并且运行了 *foo() 第一行的 x++

  3. *foo()yield 语句处暂停, 这一点上第一个 it.next() 调用结束。 此时 *foo() 仍在运行并且是活跃的, 但处在暂停状态。

  4. 查看 x 的值。

  5. 我们调用 bar() ,它通过 x++ 再次递增。

  6. 再次查看 x 的值。

  7. 最后的 it.next() 调用从暂停处恢复生成*foo() 的执行, 并且运行 console.log() 语句。

输入和输出

生成函数是一种特殊的函数, 但是它依然是一个函数, 这意味着它仍有一些函数的基本特性, 比如接受参数和有返回值。

function *foo(x,y) {
    return x * y;
}

var it = foo(6,7);
var res = it.next();
res.value; // 42

每次调用 it.next() 都会返回一个对象,里面包含一个 value 属性, 是函数的返回值。 对象中其他属性后面有介绍。

迭代消息传递

除了能够接受参数并接受返回值外, 生成器提供了内建消息输入输出能力。

function *foo(x) {
    var y = x * (yield);
    return y;
}
// 启动 foo()
var it = foo(6);

it.next();

var res = it.next(7);

res.value; // 42

首先, 将 6 作为参数传入。 然后调用 it.next(), 启动 *foo()

*foo() 内部, 开始执行语句 var y = x .., 但是随后就遇到了一个 yield 表达式。 它就停在了这个赋值语句的中间。 并且要求调用代码yield 语句提供一个结果值。 接下来, 调用 it.next(7), 这条语句将作为结果, 把 7 传回被暂停 yield 表达式。

然后 return y 作为返回值, 体现在 res.value 中。

根据你的视角不同, yieldnext 调用有一个不匹配。 一般来说, next调用要比 yield 语句多一个。 第一个 next() 调用总是启动一个生成器。

yield 的双向消息传递

yield 作为一个表达式可以发出接受从 next() 来的消息, 也能够从向 next() 返回一些值。

function *foo(x) {
    var y = x * (yield "hello");
    return y;
}

var it = foo(6);

var res = it.next(); // 第一个 next() ,并不传入任何东西
res.value; // "hello"

res = it.next(7);
res.value; // 42

只有暂停的 yield 才能接受从 next() 传递的值, 而在生成器的起始处并没有这样的 yield。 规范和兼容的浏览器都会静默丢弃传递给第一个 next() 的任何值。

多个迭代器

其实, 我们每次构建一个迭代器时, 实际上隐式构建了生成器的一个实例, 通过这个迭代器来控制的是这个生成器的实例。

function *foo() {
    var x = yield 2;
    z++;
    var y = yield (x * z);
    console.log(x,y,z);
}

var z = 1;

var it1 = foo();
var it2 = foo();

var val1 = it1.next().value; // 2 -- yield 2;
var val2 = it2.next().value; // 2 -- yield 2;

val1 = it1.next(val2 10).value; // 40 -- x: 20,z: 2
val2 = it2.next(val1
5).value; // 600 -- x: 200,z: 3

it1.next(val2 / 2); // x: 20,y: 300,z: 3
it2.next(val1 / 4); // x: 200,y: 10,z: 3

猜你在找的JavaScript相关文章