1. Null and undefined

1. Description

Null and undefined can both mean “nothing” and have very similar meanings. Assigning a variable to undefined or null makes almost no difference syntactically, to be honest.

var a = undefined;
/ / or
var a = null;
Copy the code

In the above code, variable A is assigned to undefined and null, respectively, which are almost equivalent.

In an if statement, they are both automatically returned to false, and the equality operator (==) even reports that they are equal.

if(!undefined) {
console.log('undefied is false')}if (!null) {
console.log('null is false');
}
// null is false

console.log(undefined= =null) // true
console.log(undefined= = =null)// false
console.log(Number(null)) / / 0
console.log(5 + null) / / 5
Copy the code
1, 2 Usage and meaning

Null and undefined can be understood roughly as follows.

Null means null, that is, the value there is now null. When a function is called and no value is set for a parameter, null is passed to indicate that the parameter is null. For example, if a function accepts an error thrown by the engine as an argument, it passes null to indicate that no error occurred if no error occurred during execution.

Undefined means “undefined.” Here is a typical scenario for returning undefined.

// The variable is declared, but not assigned
var i;
i // undefined

// When calling a function, the argument that should be provided is not provided, which is equal to undefined
function f(x) {
  return x;
}
f() // undefined

// The object has no assigned attributes
var  o = new Object(a); o.p// undefined

If the function returns no value, undefined is returned by default
function f() {}
f() // undefined
Copy the code

The numerical

Integers and floating point numbers

Inside JavaScript, all numbers are stored as 64-bit floating-point numbers, even integers. So, 1 is the same thing as 1.0, it’s the same number.

1 === 1.0 // true
Copy the code

Because floating point numbers are not exact values, comparisons and operations involving decimals need to be done with extreme care.

0.1 + 0.2= = =0.3
// false
0.1 + 0.2 / / 0.30000000000000004
0.3 / 0.1
/ / 2.9999999999999996

(0.3 - 0.2) = = = (0.2 - 0.1)
// false
0.3 - 0.2 / / 0.09999999999999998
Number(0.3) - Number(0.2) / / 0.09999999999999998
Copy the code

Plus zero and minus zero

As mentioned earlier, one of the binary bits in JavaScript’s 64-bit floating point numbers is a sign bit. That means that every number has a negative value, even 0.

JavaScript actually has two zeros: a +0 and a -0, the difference being the sign bit of the 64-bit floating-point representation. They’re equivalent.

-0= = = +0 // true
0= = = -0 // true
0= = = +0 // true
Copy the code

In almost every situation, positive and negative zeros are treated as normal zeros.

+0 // 0
-0 // 0
(-0).toString() // '0'
(+0).toString() // '0'
Copy the code

The only difference is that +0 or -0 in the denominator will not return the same value.

(1 / +0) === (1 / -0) // false
Copy the code

The code above gives this result because dividing by positive zero gives +Infinity and dividing by negative zero gives -infinity, which are not equal (see more about Infinity below).

NaN

(1) Meaning

NaN is a special JavaScript value that stands for “Not a Number,” mostly when parsing a string to a Number fails.

5 - 'x' // NaN
Copy the code

When the code above runs, it automatically converts the string x to a number, but since x is not a number, it ends up with NaN, which means it is “not a number.”

In addition, some mathematical functions result in nans.

Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
Copy the code

0 divided by 0 also gives you NaN.

0 / 0 // NaN
Copy the code

Note that NaN is not a separate data type, but a special value whose data type is still Number, which is clearly visible using the Typeof operator.

typeof NaN // 'number'
Copy the code

algorithm

NaN is not equal to any value, including itself.

NaN === NaN // false
Copy the code

The indexOf method of arrays uses the strict equality operator internally, so it is not valid for NaN.

[NaN].indexOf(NaN) // -1
Copy the code

NaN is treated as false in Boolean operations.

Boolean(NaN) // false
Copy the code

NaN operations on any number, including itself, yield NaN.

NaN + 32 // NaN
NaN - 32 // NaN
NaN * 32 // NaN
NaN / 32 // NaN
Copy the code

Global methods associated with numerical values

parseInt()

(1) Basic usage

The parseInt method is used to convert a string to an integer.

parseInt('123') // 123
Copy the code

If there is a space at the head of the string, the space is automatically removed.

parseInt('   81') // 81
Copy the code

If parseInt is not a string, it is converted to a string and then converted.

ParseInt (1.23) // 1 = parseInt('1.23') // 1Copy the code

When a string is converted to an integer, it is converted one by one. If it encounters a character that cannot be converted to a number, it stops and returns the converted part.

ParseInt ('8a') // 8 parseInt('12**') // 12 parseInt('12.34') // 12 parseInt('15e2') // 15 parseInt('15px') // 15Copy the code

In the above code, parseInt takes strings and returns only the part of the string header that can be converted to a number.

NaN is returned if the first character of the string cannot be converted to a number (except if it is followed by a plus or minus sign of the number).

parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1
Copy the code

Therefore, the return value of parseInt can be either a decimal integer or a NaN.

If a string begins with 0x or 0x, parseInt parses it as a hexadecimal number.

parseInt('0x10') // 16
Copy the code

If the string begins with 0, parse it in base 10.

parseInt('011') // 11
Copy the code

For numbers that are automatically converted to scientific notation, parseInt treats the scientific notation representation as a string, resulting in some strange results.

ParseInt (1000000000000000000000.5) // 1 parseInt('1e+21') // 1 parseInt(0.0000008) // 8 // parseInt('8e-7') / / 8Copy the code

object

Each key name of an object is also called a property, and its “key value” can be any data type. If the value of an attribute is a function, the attribute is usually called a “method” and can be called like a function.

var obj = {
  p: function (x) {
    return 2* x; }}; obj.p(1) / / 2
Copy the code

Object reference

If different variable names refer to the same object, they are all references to that object, that is, to the same memory address. If you change one variable, it affects all the others.

var o1 = {};
var o2 = o1;

o1.a = 1;
o2.a // 1

o2.b = 2;
o1.b // 2
Copy the code

In the code above, o1 and O2 point to the same object, so if you add a property to either variable, the other variable can read and write that property.

In this case, if one variable is removed from the reference to the original object, the other variable is not affected.

var o1 = {};
var o2 = o1;

o1 = 1;
o2 // {}
Copy the code

In the code above, o1 and O2 point to the same object, and then o1 changes to 1, and o2 is still pointing to the same object.

Viewing properties

To view all the properties of an Object itself, use the object.keys method.

var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj);
// ['key1', 'key2']
Copy the code

Attribute exists: in operator

The in operator is used to check whether an object contains an attribute (note that it checks the key name, not the value) and returns true if it does, false otherwise. It has a string on the left, representing the property name, and an object on the right.

var obj = { p: 1 };
'p' in obj // true
'toString' in obj // true
Copy the code

One problem with the IN operator is that it does not recognize which attributes belong to the object itself and which are inherited. As in the code above, the object obj itself does not have a toString attribute, but the in operator returns true because the attribute is inherited.

In this case, you can use the object’s hasOwnProperty method to determine whether it is a property of the object itself.

var obj = {};
if ('toString' in obj) {
  console.log(obj.hasOwnProperty('toString')) // false
}
console.log(obj1.hasOwnProperty('toString')) // false
console.log(obj1.hasOwnProperty('p')) // true
Copy the code

Attribute traversal: for… In circulation

for… The in loop is used to iterate over all properties of an object.

var obj = {a: 1, b: 2, c: 3}; For (var I in obj) {console.log(' key: ', I); Console. log(' key: ', obj[I]); } // key name: A // key value: 1 // key name: b // key value: 2 // key name: C // key value: 3Copy the code

for… There are two usage considerations for the in loop.

  • It iterates over all of the object’s enumerable properties and skips those that are not.
  • It traverses not only the properties of the object itself, but also the inherited properties.

For example, objects inherit the toString attribute, but for… The in loop does not traverse this property.

var obj = {};

// The toString attribute exists
obj.toString // toString() { [native code] }

for (var p in obj) {
  console.log(p);
} // There is no output
Copy the code

In the code above, the object obj inherits the toString attribute, which is not used by the for… The in loop iterates through to because it is “non-traversal” by default.

function

Function scope

define

Scope refers to the scope within which a variable exists. In the ES5 specification, JavaScript has only two scopes: a global scope, where variables exist throughout the program and can be read anywhere; The other is function scope, where variables exist only inside a function. ES6 has added block-level scopes that are not covered in this tutorial.

For top-level functions, variables declared outside the function are called global variables, which can be read inside the function.

var v = 1;

function f() {
  console.log(v);
}

f()
// 1
Copy the code

The above code shows that the global variable v can be read from inside function f.

Variables defined inside a function that cannot be read from outside are called local variables.

function f(){
  var v = 1;
}

v // ReferenceError: v is not defined
Copy the code

In the above code, the variable v is defined inside the function, so it is a local variable that cannot be read outside the function.

A variable defined inside a function overrides a global variable of the same name in that scope.

var v = 1;

function f(){
  var v = 2;
  console.log(v);
}

f() / / 2
v / / 1
Copy the code

In the above code, the variable v is defined both outside and inside the function. As a result, defined inside the function, the local variable v overrides the global variable v.

A variable promotion inside a function

As with global scopes, “variable promotion” occurs within function scopes. A variable declared by the var command is promoted to the head of the function body no matter where it is located.

function foo(x) {
  if (x > 100) {
    var tmp = x - 100; }}/ / is equivalent to
function foo(x) {
  var tmp;
  if (x > 100) {
    tmp = x - 100;
  };
}
Copy the code

The scope of the function itself

The function itself is also a value and has its own scope. Its scope, like that of a variable, is the scope in which it is declared, independent of the scope in which it is run.

var a = 1;
var x = function () {
  console.log(a);
};

function f() {
  var a = 2;
  x();
}

f() / / 1
Copy the code

In the above code, function X is declared outside of function F, so its scope is bound outside. The inner variable A is not evaluated inside function F, so it prints 1 instead of 2.

In short, the scope in which a function executes is the scope in which it was defined, not the scope in which it was called.

It is easy to make A mistake if function A calls function B without considering that function B does not refer to the internal variables of function A.

var x = function () {
  console.log(a);
};

function y(f) {
  var a = 2;
  f();
}

y(x)
// ReferenceError: a is not defined
Copy the code

The above code takes function x as an argument and passes in function y. However, function x is declared outside of function y, so the internal variable A of function Y cannot be found, resulting in an error.

Similarly, functions declared inside the function body are scoped inside the function body.

function foo() {
  var x = 1;
  function bar() {
    console.log(x);
  }
  return bar;
}

var x = 2;
var f = foo();
f() / / 1
Copy the code

closure

Closures are a difficult and characteristic feature of JavaScript, and many advanced applications rely on closures.

To understand closures, you must first understand variable scope. As mentioned earlier, JavaScript has two types of scope: global scope and function scope. Global variables can be read directly from inside functions.

var n = 999;

function f1() {
  console.log(n);
}
f1() / / 999
Copy the code

In the above code, the function f1 can read the global variable n.

Normally, however, variables declared inside a function cannot be read outside the function.

function f1() {
  var n = 999;
}

console.log(n)
// Uncaught ReferenceError: n is not defined(
Copy the code

In the above code, the variable n declared inside the function f1 is unreadable outside the function.

Since F2 can read local variables of F1, if f2 is returned, we can read internal variables outside of F1.

function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); / / 999
Copy the code

Object

Object()

Object itself is a function that can be used as a utility method to convert arbitrary values into objects. This method is often used to ensure that a value must be an object.

If the argument is empty (or undefined and null), Object() returns an empty Object.

var obj = Object(a);/ / is equivalent to
var obj = Object(undefined);
var obj = Object(null);

obj instanceof Object // true
Copy the code

This code converts undefined and null to objects, resulting in an empty object obj.

The instanceof operator verifies that an object is an instanceof the specified constructor. Obj instanceof Object returns true, indicating that the obj Object is an instanceof Object.

If the parameter is a primitive type value, the Object method converts it to an instance of the corresponding wrapper Object (see the primitive Type wrapper Object chapter).

var obj = Object(1);
obj instanceof Object // true
obj instanceof Number // true

var obj = Object('foo');
obj instanceof Object // true
obj instanceof String // true

var obj = Object(true);
obj instanceof Object // true
obj instanceof Boolean // true
Copy the code

In the above code, the parameters of the Object function are values of various primitive types, and the converted objects are the corresponding wrapper objects of the primitive values.

If the Object method takes an Object, it always returns that Object, that is, no conversion.

var arr = [];
var obj = Object(arr); // Return the original array
obj === arr // true

var value = {};
var obj = Object(value) // Return the original object
obj === value // true

var fn = function () {};
var obj = Object(fn); // return the original function
obj === fn // true
Copy the code

Using this, you can write a function that determines whether a variable is an object.

function isObject(value) {
  return value === Object(value);
}

isObject([]) // true
isObject(true) // false
Copy the code

Object.prototype.valueOf()

The valueOf method returns the “value” of an object, which by default returns the object itself.

var obj = new Object(a); obj.valueOf() === obj// true
Copy the code

The code above compares obj.valueof () to obj itself, which is the same.

The main purpose of the valueOf method is that it is called by default when JavaScript automatic type conversions occur (see the Chapter on Data Type Conversions).

var obj = new Object(a);1 + obj // "1[object Object]"
Copy the code

The above code adds the object obj to the number 1. By default, JavaScript calls valueOf(), which evaluates obj and adds to 1. So, if you customize the valueOf method, you can get the result you want.

var obj = new Object(a); obj.valueOf =function () {
  return 2;
};

1 + obj / / 3
Copy the code

The above code customizes the valueOf method of the obj object, so 1 + obj gives 3. This method is equivalent to overriding Object.prototype.valueof with a custom obj.valueof.

Object.prototype.toString()

The toString method returns a string representation of an object. By default, it returns a type string.

var o1 = new Object(a); o1.toString()// "[object Object]"

var o2 = {a:1};
o2.toString() // "[object Object]"
Copy the code

The above code shows that calling the toString method on an object returns a string specifying the type of the object.

Object object by itself is not very useful, but by customizing the toString method, you can make an object get the desired string form when the automatic type conversion is performed.

var obj = new Object(a); obj.toString =function () {
  return 'hello';
};

obj + ' ' + 'world' // "hello world"
Copy the code

The above code shows that the toString method is automatically called when an object is used for string addition. Since the toString method is custom, the string hello World is returned.

Arrays, strings, functions, the Date Object is deployed custom toString method respectively, covering the Object. The prototype. The toString method.

[1.2.3].toString() / / "1, 2, 3"

'123'.toString() / / "123"

(function () {
  return 123;
}).toString()
// "function () {
// return 123;
// }"

(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
Copy the code

In the above code, arrays, strings, functions, and Date objects that call toString do not return object object because they all override the original toString method.

Use of toString() : Determine the data type

Object. The prototype. The toString method returns the Object type string, and therefore can be used to judge the type of a value.

var obj = {};
obj.toString() // "[object Object]"
Copy the code

The above code calls the toString method of the empty object, which returns a string object object, where the second object represents the constructor for the value. This is a very useful way to determine data types.

Due to the instance objects may be custom toString method, override the Object. The prototype. The toString method, so in order to get type string, use the Object directly. The best prototype. The toString method. The call method of a function can be called on any value, helping us determine the type of the value.

Object.prototype.toString.call(value)
Copy the code

The value of the above code said to call this value Object. The prototype. The toString method.

Different data type of the Object. The prototype. ToString method return values are as follows.

  • Value: return[object Number].
  • String: returns[object String].
  • Boolean: Returns[object Boolean].
  • Undefined: return[object Undefined].
  • Returns null[object Null].
  • Array: returns[object Array].
  • Arguments object: returns[object Arguments].
  • Function: return[object Function].
  • Error object: returns[object Error].
  • Date object: returns[object Date].
  • RegExp object: returns[object RegExp].
  • Other objects: Returns[object Object].

This means that the Object. The prototype. ToString can see what a value type.

Object.prototype.toString.call(2) // "[object Number]"
Object.prototype.toString.call(' ') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(Math) // "[object Math]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
Copy the code

Using this feature, you can write a more accurate type determination function than the Typeof operator.

var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/\[object (.*?)\]/) [1].toLowerCase();
};

type({}); // "object"
type([]); // "array"
type(5); // "number"
type(null); // "null"
type(); // "undefined"
type(/abcd/); // "regex"
type(new Date()); // "date"
Copy the code