javascript中的一些坑

来源:互联网 发布:期货投资分析 知乎 编辑:程序博客网 时间:2024/05/18 00:01

1.对象使用和属性
JavaScript 中所有变量都可以当作对象使用,除了两个例外 null 和 undefined。
一个常见的误解是数字的字面值(literal)不能当作对象使用。这是因为 JavaScript 解析器的一个错误, 它试图将点操作符解析为浮点数字面值的一部分。

2.toString(); // 出错:SyntaxError

有很多变通方法可以让数字的字面值看起来像对象。

2..toString(); // 第二个点号可以正常解析2 .toString(); // 注意点号前面的空格(2).toString(); // 2先被计算

2.删除属性
删除属性的唯一方法是使用 delete 操作符;设置属性为 undefined 或者 null 并不能真正的删除属性, 而仅仅是移除了属性和值的关联。

var obj = {    bar: 1,    foo: 2,    baz: 3};obj.bar = undefined;obj.foo = null;delete obj.baz;for(var i in obj) {    if (obj.hasOwnProperty(i)) {        console.log(i, '' + obj[i]);    }}

上面的输出结果有 bar undefined 和 foo null - 只有 baz 被真正的删除了,所以从输出结果中消失。

3.原型属性
当原型属性用来创建原型链时,可以把任何类型的值赋给它(prototype)。 然而将原子类型赋给 prototype 的操作将会被忽略。

function Foo() {}Foo.prototype = 1; // 无效

而将对象赋值给 prototype,正如上面的例子所示,将会动态的创建原型链。

4.for in 循环
和 in 操作符一样,for in 循环同样在查找对象属性时遍历原型链上的所有属性。

注意: for in 循环不会遍历那些 enumerable 设置为 false 的属性;比如数组的 length 属性。

// 修改 Object.prototypeObject.prototype.bar = 1;var foo = {moo: 2};for(var i in foo) {    console.log(i); // 输出两个属性:bar 和 moo}

由于不可能改变 for in 自身的行为,因此有必要过滤出那些不希望出现在循环体中的属性, 这可以通过 Object.prototype 原型上的 hasOwnProperty 函数来完成。
使用 hasOwnProperty 过滤

// foo 变量是上例中的for(var i in foo) {    if (foo.hasOwnProperty(i)) {        console.log(i);    }}

这个版本的代码是唯一正确的写法。由于我们使用了 hasOwnProperty,所以这次只输出 moo。 如果不使用 hasOwnProperty,则这段代码在原生对象原型(比如 Object.prototype)被扩展时可能会出错。

5.工厂模式
为了不使用 new 关键字,构造函数必须显式的返回一个值。

function Bar() {    var value = 1;    return {        method: function() {            return value;        }    }}Bar.prototype = {    foo: function() {}};new Bar();Bar();

上面两种对 Bar 函数的调用返回的值完全相同,一个新创建的拥有 method 属性的对象被返回, 其实这里创建了一个闭包。

还需要注意, new Bar() 并不会改变返回对象的原型,也就是返回对象的原型不会指向 Bar.prototype)。 因为构造函数的原型会被指向到刚刚创建的新对象,而这里的 Bar 没有把这个新对象返回,而是返回了一个包含 method 属性的自定义对象。

在上面的例子中,使用或者不使用 new 关键字没有功能性的区别。

上面两种方式创建的对象不能访问 Bar 原型链上的属性,如下所示:

var bar1 = new Bar();typeof(bar1.method); // "function"typeof(bar1.foo); // "undefined"var bar2 = Bar();typeof(bar2.method); // "function"typeof(bar2.foo); // "undefined"

6.作用域与命名空间
尽管 JavaScript 支持一对花括号创建的代码段,但是并不支持块级作用域; 而仅仅支持 函数作用域。

function test() { // 一个作用域    for(var i = 0; i < 10; i++) { // 不是一个作用域        // count    }    console.log(i); // 10}

如果 return 对象的左括号和 return 不在一行上就会出错。

// 输出 undefinedfunction add(a, b) {    return         a + b;}console.log(add(1, 2));

7.Array 构造函数
由于 Array 的构造函数在如何处理参数时有点模棱两可,因此总是推荐使用数组的字面语法 - [] - 来创建数组。

[1, 2, 3]; // 结果: [1, 2, 3]new Array(1, 2, 3); // 结果: [1, 2, 3][3]; // 结果: [3]new Array(3); // 结果: [] new Array('3') // 结果: ['3']// 下面的代码将会使人很迷惑new Array(3, 4, 5); // 结果: [3, 4, 5] new Array(3) // 结果: [],此数组长度为 3

由于只有一个参数传递到构造函数中(指的是 new Array(3); 这种调用方式),并且这个参数是数字,构造函数会返回一个 length 属性被设置为此参数的空数组。 需要特别注意的是,此时只有 length 属性被设置,真正的数组并没有生成。

var arr = new Array(3);arr[1]; // undefined1 in arr; // false, 数组还没有生成

这种优先于设置数组长度属性的做法只在少数几种情况下有用,比如需要循环字符串,可以避免 for 循环的麻烦。

new Array(count + 1).join(stringToRepeat);

8.内置类型的构造函数
内置类型(比如 Number 和 String)的构造函数在被调用时,使用或者不使用 new 的结果完全不同。

new Number(10) === 10;     // False, 对象与数字的比较Number(10) === 10;         // True, 数字与数字的比较new Number(10) + 0 === 10; // True, 由于隐式的类型转换

使用内置类型 Number 作为构造函数将会创建一个新的 Number 对象, 而在不使用 new 关键字的 Number 函数更像是一个数字转换器。
9.

0 0