JavaScript Garden2

Types

Equality and Comparisons

JavaScript has two different ways of comparing the values of objects for equality.

The Equality Operator

The equality operator consists of two equal signs: ==

JavaScript features weak typing. This means that the equality operator coerces types in order to compare them.

""           ==   "0"           // false
0            ==   ""            // true
0            ==   "0"           // true
false        ==   "false"       // false
false        ==   "0"           // true
false        ==   undefined     // false
false        ==   null          // false
null         ==   undefined     // true
" \t\r\n"    ==   0             // true

The above table shows the results of the type coercion, and it is the main reason why the use of == is widely regarded as bad practice. It introduces hard-to-track-down bugs due to its complicated conversion rules.

Additionally, there is also a performance impact when type coercion is in play; for example, a string has to be converted to a number before it can be compared to another number.

The Strict Equality Operator

The strict equality operator consists of three equal signs: ===.

It works like the normal equality operator, except that strict equality operator does not perform type coercion between its operands.

""           ===   "0"           // false
0            ===   ""            // false
0            ===   "0"           // false
false        ===   "false"       // false
false        ===   "0"           // false
false        ===   undefined     // false
false        ===   null          // false
null         ===   undefined     // false
" \t\r\n"    ===   0             // false

The above results are a lot clearer and allow for early breakage of code. This hardens code to a certain degree and also gives performance improvements in case the operands are of different types.

Comparing Objects

While both == and === are called equality operators, they behave differently when at least one of their operands is an Object.

{} === {};                   // false
new String(‘foo‘) === ‘foo‘; // false
new Number(10) === 10;       // false
var foo = {};
foo === foo;                 // true

Here, both operators compare for identity and not equality; that is, they will compare for the same instance of the object, much like is in Python and pointer comparison in C.

In Conclusion

It is highly recommended to only use the strict equality operator. In cases where types need to be coerced, it should be done explicitly and not left to the language‘s complicated coercion rules.

The typeof Operator

The typeof operator (together with instanceof) is probably the biggest design flaw of JavaScript, as it is almost completely broken.

Although instanceof still has limited uses, typeof really has only one practical use case, which does not happen to be checking the type of an object.

Note: While typeof can also be called with a function like syntax, i.e. typeof(obj), this is not a function call. The parentheses behave as normal and the return value will be used as the operand of the typeof operator. There is no typeof function.

The JavaScript Type Table

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

In the above table, Type refers to the value that the typeof operator returns. As can be clearly seen, this value is anything but consistent.

The Class refers to the value of the internal [[Class]] property of an object.

From the Specification: The value of [[Class]] can be one of the following strings.ArgumentsArrayBoolean,DateErrorFunction,JSONMathNumber,ObjectRegExpString.

In order to retrieve the value of [[Class]], one has to make use of the toString method of Object.prototype.

The Class of an Object

The specification gives exactly one way of accessing the [[Class]] value, with the use of Object.prototype.toString.

function is(type, obj) {
    var clas = Object.prototype.toString.call(obj).slice(8, -1);
    return obj !== undefined && obj !== null && clas === type;
}

is(‘String‘, ‘test‘); // true
is(‘String‘, new String(‘test‘)); // true

ES5 Note: For convenience the return value of Object.prototype.toString for both null and undefined was changed from Object to Null and Undefined in ECMAScript 5.

In the above example, Object.prototype.toString gets called with the value of this being set to the object whose [[Class]] value should be retrieved.

Testing for Undefined Variables

typeof foo !== ‘undefined‘

The above will check whether foo was actually declared or not; just referencing it would result in a ReferenceError. This is the only thingtypeof is actually useful for.

In Conclusion

In order to check the type of an object, it is highly recommended to use Object.prototype.toString because this is the only reliable way of doing so. As shown in the above type table, some return values of typeof are not defined in the specification; thus, they can differ between implementations.

Unless checking whether a variable is defined, typeof should be avoided.

The instanceof Operator

The instanceof operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.

Comparing Custom Objects

function Foo() {}
function Bar() {}
Bar.prototype = new Foo();

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true

// This just sets Bar.prototype to the function object Foo,
// but not to an actual instance of Foo
Bar.prototype = Foo;
new Bar() instanceof Foo; // false

Using instanceof with Native Types

new String(‘foo‘) instanceof String; // true
new String(‘foo‘) instanceof Object; // true

‘foo‘ instanceof String; // false
‘foo‘ instanceof Object; // false

One important thing to note here is that instanceof does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object.

In Conclusion

The instanceof operator should only be used when dealing with custom made objects that originate from the same JavaScript context. Just like the typeof operator, every other use of it should be avoided.

Type Casting

JavaScript is a weakly typed language, so it will apply type coercion wherever possible.

// These are true
new Number(10) == 10; // Number.toString() is converted
                      // back to a number

10 == ‘10‘;           // Strings gets converted to Number
10 == ‘+10 ‘;         // More string madness
10 == ‘010‘;          // And more
isNaN(null) == false; // null converts to 0
                      // which of course is not NaN

// These are false
10 == 010;
10 == ‘-10‘;

ES5 Note: Number literals that start with a 0 are interpreted as octal (Base 8). Octal support for these has been removed in ECMAScript 5 strict mode.

To avoid the issues above, use of the strict equal operator is highly recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript‘s weak typing system.

Constructors of Built-In Types

The constructors of the built in types like Number and String behave differently when being used with the new keyword and without it.

new Number(10) === 10;     // False, Object and Number
Number(10) === 10;         // True, Number and Number
new Number(10) + 0 === 10; // True, due to implicit conversion

Using a built-in type like Number as a constructor will create a new Number object, but leaving out the new keyword will make the Number function behave like a converter.

In addition, passing literals or non-object values will result in even more type coercion.

The best option is to cast to one of the three possible types explicitly.

Casting to a String

‘‘ + 10 === ‘10‘; // true

By prepending an empty string, a value can easily be cast to a string.

Casting to a Number

+‘10‘ === 10; // true

Using the unary plus operator, it is possible to cast to a number.

Casting to a Boolean

By using the not operator twice, a value can be converted a boolean.

!!‘foo‘;   // true
!!‘‘;      // false
!!‘0‘;     // true
!!‘1‘;     // true
!!‘-1‘     // true
!!{};      // true
!!true;    // true

 

时间: 2024-10-11 07:48:41

JavaScript Garden2的相关文章

Javascript中call的使用

call 方法应用于:Function 对象调用一个对象的一个方法,以另一个对象替换当前对象.call([thisObj[,arg1[, arg2[,   [,.argN]]]]])参数:thisObj 可选项.将被用作当前对象的对象. arg1, arg2, , argN 可选项.将被传递方法参数序列. 说明:call 方法可以用来代替另一个对象调用一个方法.call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象.如果没有提供 thisObj 参数,那么 G

你不知道的javascript 之 >>

?远大于符号 在数学公式中,">>"代表远大于符号,表示一个数远大于另一个数,如76>>3,-2>>-99等.庞加莱与波莱尔1901年首先使用了它,很快被数学界所接受,沿用至今. 折叠编辑本段右移运算符 在许多计算机编程语言(例如:C语言.C++语言.Java语言.JavaScript语言.Pascal语言等)中,">>"代表右移运算符,就相当于"shr".该运算符为双目运算符,结合方向为从左到右,

初识JavaScript

JavaScript简介 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能.因为JavaScript兼容于ECMA标准,因此也称为ECMAScript. ECMAScript,描述了该语javascript组成言的语法和基本对象. 文档对象模型(DOM),描述处理网页内容的方法

最全解析如何正确学习JavaScript指南,必看!

划重点 鉴于时不时,有同学私信问我:怎么学前端的问题.这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了. "前端怎么学"应该因人而异,别人的方法未必适合自己.就说说我的学习方法吧:我把大部分时间放在学习js上了.因为这个js的学习曲线,先平后陡.项目实践和练习啥的,我不说了,主要说下工作之外的时间利用问题.我是怎么学的呢,看书,分析源码.个人这几天统计了一下,前端书籍目前看了50多本吧,大部分都是js的.市面上的书基本,差不多都看过. 第一个问题:看书有啥好处

JavaScript数据类型检测

一.JavaScript 数据类型 1.基本数据类型(6种) Undefined Null Boolean Number String Symbol (ES6新增) 2.引用数据类型: Object 二.数据类型检测 1. typeof 可以检测除null 外的基本类型.null 和所有对象的typeof都是"object", 不能用于检测用户自定义类型. 比如Date, RegExp, Array, DOM Element的类型都是"object". var s

JavaScript的进阶之路(二)函数简介,变量、作用域和内存问题

<h3>ECMAScript中函数不存在函数签名的概念,没有重载</h3><h3>无需指定返回值,可以在任何时候返回任何值.未指定返回值的函数,返回的是一个特殊的undefined值</h3> <script type="text/javascript"> function sayHi(){ console.log("Hi"); }; sayHi(); function sayName(name,age){

JavaScript 二进制的 AST

本文和大家分享的主要是javascript中二进制的 AST相关内容,一起来看看吧,希望对大家学习javascript有所帮助. 背景介绍 多年来,JavaScript 已经从最慢的脚本语言之一,从老爷车发展为兰博基尼,不管是通过 Web 浏览器还是其他环境.它都能够快到可以运行桌面.服务器.移动甚至嵌入式应用程序. 随着 JavaScript 的增长,应用程序的复杂程度和规模都越来越复杂.然而,二十年前,少数使用过 JavaScript 的网站也就加载几千字节的 JavaScript,许多网站

JavaScript 对象

JavaScript 中的所有事物都是对象:字符串.数值.数组.函数... 此外,JavaScript 允许自定义对象. JavaScript 对象 JavaScript 提供多个内建对象,比如 String.Date.Array 等等. 对象只是带有属性和方法的特殊数据类型. 建 JavaScript 对象 通过 JavaScript,您能够定义并创建自己的对象. 创建新对象有两种不同的方法: 定义并创建对象的实例 使用函数来定义对象,然后创建新的对象实例

实现一个函数clone,使JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number.String.Object.Array.Boolean)进行值复制. 1 /** 对象克隆 2 * 支持基本数据类型及对象 3 * 递归方法 */ 4 function clone(obj) { 5 var o; 6 switch (typeof obj) { 7 case "undefined": 8 break; 9 case "string": o = obj + &q