javascript错误

常见错误1:对“ this'错误引用 (Common Mistake #1: Incorrect references to 'this')

As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of “this/that confusion”.

多年来,随着JavaScript编码技术和设计模式变得越来越复杂,回调和闭包内自引用范围的泛滥也相应增加,这是“此/该混乱”的相当普遍的来源。

Consider this example code snippet:

考虑以下示例代码片段:

Game.prototype.restart = function () {  this.clearLocalStorage();  this.timer = setTimeout(function() {    this.clearBoard();    // what is "this"?  }, 0);};

Executing the above code results in the following error:

执行上面的代码将导致以下错误:

Uncaught TypeError: undefined is not a function

Why?

为什么?

It’s all about context. The reason you get the above error is because, when you invoke setTimeout(), you are actually invoking window.setTimeout(). As a result, the anonymous function being passed to setTimeout() is being defined in the context of the window object, which has no clearBoard() method.

这都是关于上下文的。 出现上述错误的原因是,当调用setTimeout() ,实际上是在调用window.setTimeout() 。 结果,传递给setTimeout()的匿名函数是在没有clearBoard()方法的window对象的上下文中定义的。

A traditional, old-browser-compliant solution is to simply save your reference to this in a variable that can then be inherited by the closure; e.g.:

传统的,与浏览器兼容的解决方案是简单地将您this的引用保存在变量中,然后该变量可以由闭包继承。 例如:

Game.prototype.restart = function () {  this.clearLocalStorage();  var self = this;   // save reference to 'this'  this.timer = setTimeout(function(){    self.clearBoard();    // oh OK, I do know who 'self' is!  }, 0);};

Alternatively, in newer browsers, you can use the .bind() method to pass in the proper reference:

另外,在较新的浏览器中,您可以使用 bind()方法传递正确的引用:

Game.prototype.restart = function () {  this.clearLocalStorage();  this.timer = setTimeout.bind(this), 0)};Game.prototype.reset = function(){    this.clearBoard();    //back in the context of the right 'this'!};

常见错误2:认为存在块级范围 (Common Mistake #2: Thinking there is block-level scope)

Assuming that JavaScript creates a new scope for each code block. Although this is true in many other languages, it is not true in JavaScript. Consider, for example, the following code:

假定JavaScript为每个代码块创建一个新作用域。 尽管在许多其他语言中也是如此,但在JavaScript中却并非如此。 例如,考虑以下代码:

for (var i = 0; i < 10; i++) {  /* ... */}console.log(i);  // what will this output?

If you guess that the console.log() call would either output undefined or throw an error, you guessed incorrectly. Believe it or not, it will output 10. Why?

如果您猜到console.log()调用将输出undefined或抛出错误,则您猜错了。 信不信由你,它会输出10 。 为什么?

In most other languages, the code above would lead to an error because the “life” (i.e., scope) of the variable i would be restricted to the for block.

在大多数其他语言中,上面的代码将导致错误,因为变量i的“寿命”(即作用域)将限于for块。

In JavaScript, though, this is not the case and the variable i remains in scope even after the for loop has completed, retaining its last value after exiting the loop. (This behavior is known, incidentally, as variable hoisting).

但是,在JavaScript中不是这种情况, 即使在 for 循环完成 后, 变量 i 仍在作用域内 ,在退出循环后仍保留其最后一个值。 (顺便说一下,这种行为被称为可变提升 )。

常见错误3:造成内存泄漏 (Common Mistake #3: Creating memory leaks)

Memory leaks are almost inevitable JavaScript problems if you’re not consciously coding to avoid them. There are numerous ways for them to occur, so we’ll just highlight a couple of their more common occurrences.

如果您不自觉地编写代码来避免内存泄漏,那么这几乎是不可避免JavaScript问题。 它们有多种发生方式,因此我们仅重点介绍它们中的几种较为常见的情况。

Memory Leak Example 1: Dangling references to defunct objects

内存泄漏示例1:悬挂对已失效对象的引用

Consider the following code:

考虑以下代码:

var theThing = null;var replaceThing = function () {  var priorThing = theThing;  // hold on to the prior thing  var unused = function () {    // 'unused' is the only place where 'priorThing' is referenced,    // but 'unused' never gets invoked    if (priorThing) {      console.log("hi");    }  };  theThing = {    longStr: new Array(1000000).join('*'),  // create a 1MB object    someMethod: function () {      console.log(someMessage);    }  };};setInterval(replaceThing, 1000);    // invoke `replaceThing' once every second

If you run the above code and monitor memory usage, you’ll find that you’ve got a massive memory leak, leaking a full megabyte per second! And even a manual GC doesn’t help. So it looks like we are leaking longStr every time replaceThing is called. But why?

如果运行上面的代码并监视内存使用情况,您将发现大量内存泄漏,每秒泄漏整兆字节! 甚至手动GC也无济于事。 所以看起来我们正在泄漏longStr每次replaceThing被调用。 但为什么?

Let’s examine things in more detail:

让我们更详细地研究一下事情:

Each theThing object contains its own 1MB longStr object. Every second, when we call replaceThing, it holds on to a reference to the prior theThing object in priorThing. But we still wouldn’t think this would be a problem, since each time through, the previously referenced priorThing would be dereferenced (when priorThing is reset via priorThing = theThing;). And moreover, is only referenced in the main body of replaceThing and in the function unused which is, in fact, never used.

每个theThing对象都包含其自己的1MB longStr对象。 每隔一秒钟,当我们调用replaceThing ,它会保留对theThing中的先前theThing对象的priorThing 。 但是我们仍然不会认为这会成为问题,因为每次经过时,先前引用的priorThing都将被取消引用(当priorThing通过priorThing = theThing;重置时)。 而且,仅在replaceThing主体和unused的函数(实际上从未使用过)中引用。

So again we’re left wondering why there is a memory leak here!?

因此,我们再次想知道为什么这里有内存泄漏!?

To understand what’s going on, we need to better understand how things are working in JavaScript under the hood. The typical way that closures are implemented is that every function object has a link to a dictionary-style object representing its lexical scope. If both functions defined inside replaceThing actually used priorThing, it would be important that they both get the same object, even if priorThing gets assigned to over and over, so both functions share the same lexical environment. But as soon as a variable is used by any closure, it ends up in the lexical environment shared by all closures in that scope. And that little nuance is what leads to this gnarly memory leak. (More detail on this is available here.)

要了解发生了什么,我们需要更好地了解JavaScript在幕后的工作方式。 实现闭包的典型方式是,每个函数对象都有一个指向表示其词法范围的字典式对象的链接。 如果在replaceThing内部定义的两个函数replaceThing实际使用了priorThing ,那么即使priorThingpriorThing分配给它们,都必须获得相同的对象,这一点很重要,因此这两个函数共享相同的词法环境。 但是,一旦任何闭包使用了变量,该变量就会在该范围内的所有闭包共享的词法环境中结束。 正是这种细微差别导致了这种陈旧的内存泄漏。 (有关更多详细信息,请点击此处 。)

Memory Leak Example 2: Circular references

内存泄漏示例2:循环引用

Consider this code fragment:

考虑以下代码片段:

function addClickHandler(element) {    element.click = function onClick(e) {        alert("Clicked the " + element.nodeName)    }}

Here, onClick has a closure which keeps a reference to element (via element.nodeName). By also assigning onClick to element.click, the circular reference is created; i.e.: element -> onClick -> element -> onClick -> element

在这里, onClick有一个闭包,该闭包保留对element的引用(通过element.nodeName )。 通过还将onClick分配给element.click ,可以创建循环引用。 即: element -> onClick > element -> onClick > element

Interestingly, even if element is removed from the DOM, the circular self-reference above would prevent element and onClick from being collected, and hence, a memory leak.

有趣的是,即使将element从DOM中删除,上述循环自引用也将阻止elementonClick收集,从而导致内存泄漏。

Avoiding Memory Leaks: What you need to know

避免内存泄漏:您需要了解的内容

JavaScript’s memory management (and, in paticular, garbage collection) is largely based on the notion of object reachability.

JavaScript的内存管理(特别是垃圾收集 )在很大程度上基于对象可访问性的概念。

The following objects are assumed to be reachable and are known as “roots”:

假定以下对象是可到达的 ,并称为“根”:

  • Objects referenced from anywhere in the current call stack (that is, all local variables and parameters in the functions currently being invoked, and all the variables in the closure scope)

    从当前调用堆栈中任何位置引用的对象(即,当前正在调用的函数中的所有局部变量和参数,以及闭包作用域中的所有变量)

  • All global variables

    所有全局变量

Objects are kept in memory at least as long as they are accessible from any of the roots through a reference, or a chain of references.

对象至少要保留在内存中,只要它们可以通过引用或引用链从任何根访问。

There is a Garbage Collector (GC) in the browser which cleans memory occupied by unreachable objects; i.e., objects will be removed from memory if and only if the GC believes that they are unreachable. Unfortunately, it’s fairly easy to end up with defunct “zombie” objects that are in fact no longer in use but that the GC still thinks are “reachable”.

浏览器中有一个垃圾收集器(GC),用于清除无法访问的对象占用的内存。 即, 仅当 GC认为对象不可访问时,才会从内存中删除对象。 不幸的是,很容易以实际上已经不再使用但GC仍然认为是“可到达的”已失效的“僵尸”对象结束。

Related: JavaScript Best Practices and Tips by Toptal Developers

相关: Toptal开发人员JavaScript最佳实践和技巧

常见错误4:对平等的困惑 (Common Mistake #4: Confusion about equality)

One of the conveniences in JavaScript is that it will automatically coerce any value being referenced in a boolean context to a boolean value. But there are cases where this can be as confusing as it is convenient. Some of the following, for example, have been known to bite many a JavaScript developer:

JavaScript的便利之一是它会自动将布尔上下文中引用的任何值强制转换为布尔值。 但是在某些情况下,这样做可能会很容易造成混淆。 例如,已知以下某些内容会吸引许多JavaScript开发人员:

// All of these evaluate to 'true'!console.log(false == '0');console.log(null == undefined);console.log(" \t\r\n" == 0);console.log('' == 0);// And these do too!if ({}) // ...if ([]) // ...

With regard to the last two, despite being empty (which might lead one to believe that they would evaluate to false), both {} and [] are in fact objects and any object will be coerced to a boolean value of true in JavaScript, consistent with the ECMA-262 specification.

关于最后两个,尽管为空(这可能会导致一个人认为它们的计算结果为false ),但{}[]实际上都是对象,并且在JavaScript中任何对象都将被强制为布尔值true ,符合ECMA-262规范 。

As these examples demonstrate, the rules of type coercion can sometimes be clear as mud. Accordingly, unless type coercion is explicitly desired, it’s typically best to use === and !== (rather than == and !=), so as to avoid any unintended side-effects of type coercion. (== and != automatically perform type conversion when comparing two things, whereas === and !== do the same comparison without type conversion.)

如这些示例所示,强制类型的规则有时会变得很泥泞。 因此,除非明确需要类型强制,否则通常最好使用===!== (而不是==!= ),以避免类型强制的任何意外副作用。 ( ==!=在比较两件事时自动执行类型转换,而===!==进行相同的比较而不进行类型转换。)

And completely as a sidepoint — but since we’re talking about type coercion and comparisons — it’s worth mentioning that comparing NaN with anything (even NaN!) will always return false. You therefore cannot use the equality operators (==, ===, !=, !==) to determine whether a value is NaN or not. Instead, use the built-in global isNaN() function:

完全是一种观点-但由于我们正在谈论类型强制和比较-值得一提的是,将NaN任何内容 (甚至是NaN !)进行比较将始终返回false因此,您不能使用等号运算符( == === != !== )来确定值是否为 NaN 而是使用内置的全局isNaN()函数:

console.log(NaN == NaN);    // falseconsole.log(NaN === NaN);   // falseconsole.log(isNaN(NaN));    // true

常见错误5:无效的DOM操作 (Common Mistake #5: Inefficient DOM manipulation)

JavaScript makes it relatively easy to manipulate the DOM (i.e., add, modify, and remove elements), but does nothing to promote doing so efficiently.

JavaScript使操作DOM(即添加,修改和删除元素)相对容易,但是并不能促进这样做。

A common example is code that adds a series of DOM Elements one at a time. Adding a DOM element is an expensive operation. Code that adds multiple DOM elements consecutively is inefficient and likely not to work well.

一个常见的示例是一次添加一系列DOM元素的代码。 添加DOM元素是一项昂贵的操作。 连续添加多个DOM元素的代码效率低下,并且可能无法正常工作。

One effective alternative when multiple DOM elements need to be added is to use document fragments instead, thereby improving both efficiency and performance.

当需要添加多个DOM元素时,一种有效的替代方法是改为使用文档片段 ,从而提高效率和性能。

For example:

例如:

var div = document.getElementsByTagName("my_div");var fragment = document.createDocumentFragment();for (var e = 0; e < elems.length; e++) {     // elems previously set to list of elements    fragment.appendChild(elems[e]);}div.appendChild(fragment.cloneNode(true));

In addition to the inherently improved efficiency of this approach, creating attached DOM elements is expensive, whereas creating and modifying them while detached and then attaching them yields much better performance.

除了从本质上提高此方法的效率之外,创建附加的DOM元素很昂贵,而在分离时创建和修改它们,然后附加它们会产生更好的性能。

常见错误#6:在for循环中错误使用函数定义 (Common Mistake #6: Incorrect use of function definitions inside for loops)

Consider this code:

考虑以下代码:

var elements = document.getElementsByTagName('input');var n = elements.length;    // assume we have 10 elements for this examplefor (var i = 0; i < n; i++) {    elements[i].onclick = function() {        console.log("This is element #" + i);    };}

Based on the above code, if there were 10 input elements, clicking any of them would display “This is element #10”! This is because, by the time onclick is invoked for any of the elements, the above for loop will have completed and the value of i will already be 10 (for all of them).

根据上面的代码,如果有10个输入元素,则单击其中任何一个都会显示“ This is element#10”! 这是因为,当对任何元素调用onclick ,上述for循环将完成,并且i的值将为10(对于所有元素)。

Here’s how we can correct the above code problems, though, to achieve the desired behavior (by using, what is called CLOSURES):

但是,我们可以通过以下方法纠正上述代码问题,以实现所需的行为(通过使用所谓的CLOSURES ):

var elements = document.getElementsByTagName('input');var n = elements.length;    // assume we have 10 elements for this examplevar makeHandler = function(num) {  // outer function     return function() {   // inner function         console.log("This is element #" + num);     };};for (var i = 0; i < n; i++) {    elements[i].onclick = makeHandler(i+1);}

In this revised version of the code, makeHandler is immediately executed each time we pass through the loop, each time receiving the then-current value of i+1 and binding it to a scoped num variable. The outer function returns the inner function (which also uses this scoped num variable) and the element’s onclick is set to that inner function. This ensures that each onclick receives and uses the proper i value (via the scoped num variable).

在此代码的修订版中,每次我们通过循环时,都会立即执行makeHandler ,每次接收i+1的当前值并将其绑定到作用域num变量时。 外部函数返回内部函数(也使用此作用域num变量),并且元素的onclick设置为该内部函数。 这样可以确保每个onclick接收和使用适当的i值(通过作用域num变量)。

常见错误7:无法正确利用原型继承 (Common Mistake #7: Failure to properly leverage prototypal inheritance)

A surprisingly high percentage of JavaScript developers fail to fully understand, and therefore to fully leverage, the features of prototypal inheritance.

极高比例JavaScript开发人员无法完全理解原型继承的功能,因此无法充分利用它们。

Here’s a simple example. Consider this code:

这是一个简单的例子。 考虑以下代码:

BaseObject = function(name) {    if(typeof name !== "undefined") {        this.name = name;    } else {        this.name = 'default'    }};

Seems fairly straightforward. If you provide a name, use it, otherwise set the name to ‘default’; e.g.:

似乎相当简单。 如果提供名称,请​​使用它,否则将名称设置为“默认”。 例如:

var firstObj = new BaseObject();var secondObj = new BaseObject('unique');console.log(firstObj.name);  // -> Results in 'default'console.log(secondObj.name); // -> Results in 'unique'

But what if we were to do this:

但是,如果我们要这样做:

delete secondObj.name;

We’d then get:

然后,我们得到:

console.log(secondObj.name); // -> Results in 'undefined'

But wouldn’t it be nicer for this to revert to ‘default’? This can easily be done, if we modify the original code to leverage prototypal inheritance, as follows:

但是,将其恢复为“默认”会更好吗? 如果我们修改原始代码以利用原型继承,则可以轻松完成此操作,如下所示:

BaseObject = function (name) {    if(typeof name !== "undefined") {        this.name = name;    }};BaseObject.prototype.name = 'default';

With this version, BaseObject inherits the name property from its prototype object, where it is set (by default) to 'default'. Thus, if the constructor is called without a name, the name will default to default. And similarly, if the name property is removed from an instance of BaseObject, the prototype chain will then be searched and the name property will be retrieved from the prototype object where its value is still 'default'. So now we get:

在此版本中, BaseObject继承自其prototype对象的name属性,该对象在默认情况下被设置为'default' 。 因此,如果在没有名称的情况default调用构造函数,则该名称将默认为default 。 同样,如果从BaseObject实例中删除了name属性,则将搜索原型链,并从其值仍为'default'prototype对象中检索name属性。 现在我们得到:

var thirdObj = new BaseObject('unique');console.log(thirdObj.name);  // -> Results in 'unique'delete thirdObj.name;console.log(thirdObj.name);  // -> Results in 'default'

常见错误#8:创建对实例方法的不正确引用 (Common Mistake #8: Creating incorrect references to instance methods)

Let’s define a simple object, and create and instance of it, as follows:

让我们定义一个简单的对象,并创建它和实例,如下所示:

var MyObject = function() {}MyObject.prototype.whoAmI = function() {    console.log(this === window ? "window" : "MyObj");};var obj = new MyObject();

Now, for convenience, let’s create a reference to the whoAmI method, presumably so we can access it merely by whoAmI() rather than the longer obj.whoAmI():

现在,为方便起见,让我们创建对whoAmI方法的引用,大概是这样,我们只能通过whoAmI()而不是更长的obj.whoAmI()来访问它:

var whoAmI = obj.whoAmI;

And just to be sure everything looks copacetic, let’s print out the value of our new whoAmI variable:

并且为了确保所有内容看起来都是正常的,让我们打印出新的whoAmI变量的值:

console.log(whoAmI);

Outputs:

输出:

function () {    console.log(this === window ? "window" : "MyObj");}

OK, cool. Looks fine.

嗯不错。 看起来不错

But now, look at the difference when we invoke obj.whoAmI() vs. our convenience reference whoAmI():

但是,现在来看一下调用obj.whoAmI()与我们的便捷性参考whoAmI()

obj.whoAmI();  // outputs "MyObj" (as expected)whoAmI();      // outputs "window" (uh-oh!)

What went wrong?

什么地方出了错?

The headfake here is that, when we did the assignment var whoAmI = obj.whoAmI;, the new variable whoAmI was being defined in the global namespace. As a result, its value of this is window, not the obj instance of MyObject!

最令人头疼的是,当我们执行赋值操作时, var whoAmI = obj.whoAmI; ,即在全局名称空间中定义的新变量whoAmI 。 其结果是,它的价值thiswindow不是 obj的实例MyObject

Thus, if we really need to create a reference to an existing method of an object, we need to be sure to do it within that object’s namespace, to preserve the value of this. One way of doing this would be, for example, as follows:

因此,如果确实需要创建对对象现有方法的引用,则需要确保在该对象的名称空间中进行引用,以保留this的值。 一种方法是,例如,如下所示:

var MyObject = function() {}MyObject.prototype.whoAmI = function() {    console.log(this === window ? "window" : "MyObj");};var obj = new MyObject();obj.w = obj.whoAmI;   // still in the obj namespaceobj.whoAmI();  // outputs "MyObj" (as expected)obj.w();       // outputs "MyObj" (as expected)

常见错误#9:将字符串作为setTimeoutsetInterval的第一个参数 (Common Mistake #9: Providing a string as the first argument to setTimeout or setInterval)

For starters, let’s be clear on something here: Providing a string as the first argument to setTimeout or setInterval is not itself a mistake per se. It is perfectly legitimate JavaScript code. The issue here is more one of performance and efficiency. What is rarely explained is that, under the hood, if you pass in a string as the first argument to setTimeout or setInterval, it will be passed to the function constructor to be converted into a new function. This process can be slow and inefficient, and is rarely necessary.

首先,让我们在这里进行一些澄清:将字符串作为setTimeoutsetInterval的第一个参数本身本身并不是错误。 这是完全合法JavaScript代码。 这里的问题不仅仅是性能和效率之一。 很少解释的是,在幕后,如果将字符串作为第一个参数传递给setTimeoutsetInterval ,它将被传递给函数构造函数以转换为新函数。 此过程可能很慢且效率低下,几乎没有必要。

The alternative to passing a string as the first argument to these methods is to instead pass in a function. Let’s take a look at an example.

将字符串作为这些方法的第一个参数传递的替代方法是传递一个函数 。 让我们看一个例子。

Here, then, would be a fairly typical use of setInterval and setTimeout, passing a string as the first parameter:

那么,这里将是setIntervalsetTimeout的相当典型的用法,将字符串作为第一个参数传递:

setInterval("logTime()", 1000);setTimeout("logMessage('" + msgValue + "')", 1000);

The better choice would be to pass in a function as the initial argument; e.g.:

更好的选择是传入一个函数作为初始参数。 例如:

setInterval(logTime, 1000); // passing the logTime function to setIntervalsetTimeout(function() {       // passing an anonymous function to setTimeout    logMessage(msgValue);     // (msgValue is still accessible in this scope)  }, 1000);

常见错误10:无法使用“严格模式” (Common Mistake #10: Failure to use “strict mode”)

As explained in our JavaScript Hiring Guide, “strict mode” (i.e., including 'use strict'; at the beginning of your JavaScript source files) is a way to voluntarily enforce stricter parsing and error handling on your JavaScript code at runtime, as well as making it more secure.

如我们的JavaScript招聘指南中所述 ,“严格模式”(即,包括'use strict';在JavaScript源文件的开头)是一种在运行时自愿对JavaScript代码实施严格的解析和错误处理的方法使其更加安全。

While, admittedly, failing to use strict mode is not a “mistake” per se, its use is increasingly being encouraged and its omission is increasingly becoming considered bad form.

公认的是,虽然不使用严格模式本身并不是一个“错误”,但越来越多的人鼓励使用它,而忽略它也被认为是不好的形式。

Here are some key benefits of strict mode:

以下是严格模式的一些主要优点:

  • Makes debugging easier. Code errors that would otherwise have been ignored or would have failed silently will now generate errors or throw exceptions, alerting you sooner to problems in your code and directing you more quickly to their source.

    使调试更加容易。 现在,本来可以被忽略或以静默方式失败的代码错误将生成错误或引发异常,从而更快地提醒您代码中的问题,并更快地将您定向到其来源。

  • Prevents accidental globals. Without strict mode, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common errors in JavaScript. In strict mode, attempting to do so throws an error.

    防止意外的全局变量。 如果没有严格模式,则将值分配给未声明的变量会自动创建一个具有该名称的全局变量。 这是JavaScript中最常见的错误之一。 在严格模式下,尝试执行此操作将引发错误。

  • Eliminates this coercion. Without strict mode, a reference to a this value of null or undefined is automatically coerced to the global. This can cause many headfakes and pull-out-your-hair kind of bugs. In strict mode, referencing a a this value of null or undefined throws an error.

    消除了 this 强制性 。 如果没有严格模式,则this null或undefined的this值的引用将自动强制为全局值。 这可能会导致许多假冒和拔出头发的错误。 在严格模式,参照AA this空的值或未定义引发错误。

  • Disallows duplicate property names or parameter values. Strict mode throws an error when it detects a duplicate named property in an object (e.g., var object = {foo: "bar", foo: "baz"};) or a duplicate named argument for a function (e.g., function foo(val1, val2, val1){}), thereby catching what is almost certainly a bug in your code that you might otherwise have wasted lots of time tracking down.

    不允许重复的属性名称或参数值。 严格模式在检测到对象中重复的命名属性(例如var object = {foo: "bar", foo: "baz"}; )或函数的重复命名参数(例如, function foo(val1, val2, val1){} ),从而捕获几乎可以肯定的代码错误,否则您可能会浪费大量时间进行跟踪。

  • Makes eval() safer. There are some differences in the way eval() behaves in strict mode and in non-strict mode. Most significantly, in strict mode, variables and functions declared inside of an eval() statement are not created in the containing scope (they are created in the containing scope in non-strict mode, which can also be a common source of problems).

    使eval()更安全。 eval()在严格模式和非严格模式下的行为方式有所不同。 最显著,在严格模式下,变量和函数内部的的声明eval()包含范围内创建( 它们在非严格模式包含范围内,这也可以是问题的常见源创建)语句。

  • Throws error on invalid usage of delete. The delete operator (used to remove properties from objects) cannot be used on non-configurable properties of the object. Non-strict code will fail silently when an attempt is made to delete a non-configurable property, whereas strict mode will throw an error in such a case.

    无效使用 delete 引发错误 delete运算符(用于从对象中删除属性)不能用于对象的不可配置属性。 尝试删除不可配置的属性时,非严格代码将静默失败,而在这种情况下,严格模式将引发错误。

结语 (Wrap-up)

As is true with any technology, the better you understand why and how JavaScript works and doesn’t work, the more solid your code will be and the more you’ll be able to effectively harness to true power of the language. Conversely, lack of proper understanding of JavaScript paradigms and concepts is indeed where many JavaScript problems lie.

就像任何技术一样,您越能理解JavaScript为何起作用以及如何起作用以及不起作用的原因,您的代码越牢固,您就越能够有效地利用语言的真正力量。 相反,缺乏对JavaScript范例和概念的正确理解确实是许多JavaScript问题所在。

Thoroughly familiarising yourself with the language’s nuances and subtleties is the most effective strategy for improving your proficiency and increasing your productivity. Avoiding many common JavaScript mistakes will help when your JavaScript is not working.

全面熟悉该语言的细微差别和细微之处是提高您的熟练程度和提高生产率的最有效策略。 当您JavaScript无法运作时,避免许多常见JavaScript错误会有所帮助。

翻译自: https://medium.com/@anil.pace7/10-most-common-mistakes-javascript-developers-make-e31fdb348a84

javascript错误


http://www.taodudu.cc/news/show-4254674.html

相关文章:

  • PyCharm调试时一直显示collecting data
  • conda命令报错Collecting package metadata (repodata.json): failed
  • 报错:Collecting package metadata (current_repodata.json): failed
  • Collecting Bugs (DP期望)
  • 【网络】吐血整理-Java网络合集
  • iOS开发之网络通信(1)—— 计算机网络
  • 阿里云ACP云计算错题集1-40
  • 网络协议总结
  • 首页技术支持常见问题宽带外网IP显示为10、100、172开头,没有公网IP,如何解决?...
  • mysql学习日常操作
  • An error occurred while installing package ‘conda-forge::certif‘ FileNotFoundError(2, ‘系统找不到指定的文件‘)
  • AVUE 点击编辑按钮拉起弹窗前增加自己的操作
  • 【vue】avue-crud配置大全-持续更新
  • Linux引导过程和GRUB引导器
  • 存储过程的demo
  • linux7 etc下的grub2,Centos7安装 grub2 配置技巧:改变启动顺序
  • 二、CRUD操作以及配置解析
  • vue crud
  • linux grub error17,Ubuntu Grub 问题:提示 error17 修复方法
  • CoreData里的增删改查
  • Linux系统引导过程及排除启动故障
  • 在linux中如何修改保存gun文件_Linux下文件重命名、创建、删除、修改及保存文件...
  • 20.番外篇——Vue如何自定义组件并且进行全局配置
  • MyBatis学习(二)--利用MyBatis实现CRUD操作
  • 【HTML总复习】一文带你查漏补缺,暖你一整天
  • 【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-分箱
  • 【githubshare】开源的文件文档在线预览项目,支持主流办公文档的在线预览,如 doc、docx、Excel、pdf、txt、zip、rar、 图片等
  • 分享一个强大的在线写API接口文档的工具showdoc
  • 《科研伦理与学术规范》 期末考试,题目文档汇总(免费分享 )
  • Latex 数学符号和公式模板整理

javascript错误_JavaScript开发人员最常犯的10个错误相关推荐

  1. Java开发人员最常犯的10个错误,你犯过几个?

    点击蓝色"程序猿DD"关注我哟 加个"星标",不忘签到哦 来源:http://t.cn/EJscOju 阅读目录 Array转ArrayList 判断一个数组是 ...

  2. AngularJS开发人员最常犯的10个错误

    简介 AngularJS是目前最为活跃的Javascript框架之一,AngularJS的目标之一是简化开发过程, 这使得AngularJS非常善于构建小型app原型,但AngularJS对于全功能的 ...

  3. SearchHit转成java对象_Java开发中最常犯的10个错误,你中招了吗?

    http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/ 阅读目录 Array转ArrayList 判断一个数 ...

  4. Java开发中最常犯的10个错误,你中招了吗?

    http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/ 阅读目录 Array转ArrayList 判断一个数 ...

  5. Java开发最常犯的10个错误,打死都不要犯!

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 原文:http://www.programcreek.com/2014/05/top-10-m ...

  6. Java程序员最常犯的 10 个错误

    转载自 Java程序员最常犯的 10 个错误 这个列表总结了Java开发人员经常犯的10个错误. 一 .把数组转成ArrayList 为了将数组转换为ArrayList,开发者经常会这样做: List ...

  7. 一般编译器错误_Java程序员最容易犯的10个错误

    人非圣贤,孰能无过.都说Java语言是一门简单的编程语言,基于C++演化而来,剔除了很多C++中的复杂特性,但这并不能保证Java程序员不会犯错. 在开发 Java 软件时可能会遇到许多类型的错误,但 ...

  8. java构造函数_Java开发人员也会犯的十大错误

    今天我就给大家总结一下Java开发人员经常犯的10大错误. #1 将数组转换为ArrayList 要将数组转换为ArrayList,开发人员通常会这样做: List < String > ...

  9. ui设计 网络错误_UI设计人员常犯的10个错误

    ui设计 网络错误 重点 (Top highlight) 1.不考虑范围 (1. Disregarding scope) It's not uncommon for designers to intr ...

最新文章

  1. NOP 指令作用[转]
  2. 武汉计算机组成原理八校联盟考试,武汉理工大学《计算机组成原理》在线练习及考试题目.doc...
  3. Zend Studio 安装 PyDev 插件后报错
  4. java内存区域之程序计数器
  5. UVa12583 - Memory Overflow
  6. PHP读取远程文件并保存
  7. java.lang包—类加载器ClassLoader类
  8. 进程切换(上下文切换)
  9. AES加密算法的学习笔记
  10. exit()函数_complete函数
  11. windows 搭建kms服务器激活_windows下搭建MQTT服务器
  12. HIVE Sql 笛卡尔积关联导致查询过慢问题优化
  13. Laravel5.6 模块化公众号与小程序系统项目实战
  14. Profile Lookup任务详解
  15. uni-app 和H5页面视频播放flv格式视频监控
  16. 如何在excel多条件筛选
  17. MATLAB 立体绘图
  18. Matplotlib 画图如何取消图边框
  19. 实现a标签中的各种点击(onclick)事件的方法
  20. ubuntu lotus testnet-staging

热门文章

  1. Android APP中保持屏幕不自动灭屏的一种方法
  2. Spring Boot进阶(12):Spring Boot 如何获取Excel sheet页的数量?一文教会你 | 超级详细,建议收藏
  3. dma_alloc_coheren
  4. 领英工具领英精灵批量加人有哪些方法
  5. IE浏览器浏览网页提示证书错误,Chrome、360浏览器显示“不安全”的原因
  6. 数学运算符号的英文表达
  7. 支持小米java文件阅读器_小米多看电纸书MiReader 桌面LauncherApp(自制软件)
  8. CSAPP导读第3章 程序的机器级表示
  9. 2020.10.08丨全长转录组之参考基因组比对
  10. Android:检查通知权限并跳转到通知设置界面