JavaScript Tutorial - Internet Documentation Project

learning target:

  • Take a chapter of notes every day

Learning Content:

JavaScript 教程---互联网文档计划


Note time:

2023-6-5 --- 2023-6-11


Learning Outputs:

1. Getting Started

1. The core syntax of JavaScript contains parts

Basic syntax + standard library + host API
Basic syntax: such as operators, control structures, statements
Standard library: a series of objects with various functions such as Array Date Math
Host API: an interface that can only be used in this environment

Browser control class: operate browser
DOM class: operate various elements of web pages
Web class: realize various functions of the Internet

2. The relationship between ECMAScript and JavaScript is that the former is the specification of the latter, and the latter is an implementation of the former. In everyday situations, the two words are interchangeable.

3. The basic syntax of JavaScript

"1" statement

The execution unit of a JavaScript program is a line, that is, it is executed line by line. In general, each line is a statement.

var a = 1 + 3;

Statements end with a semicolon, and a semicolon signifies the end of a statement. Multiple statements can be written on one line.

var a = 1 + 3 ; var b = 'abc';

There can be nothing before the semicolon, and the JavaScript engine treats it as an empty statement.

;;;

"2" variable

A variable is a named reference to a "value"

var a = 1;

注意,JavaScript 的变量名区分大小写,A和a是两个不同的变量。
Just declare a variable without assigning a value, the value of the variable is undefined.
undefined is a special value that means "no definition".

var a;
a // undefined

JavaScript is a dynamically typed language, there are no restrictions on the type of variables, and variables can change types at any time.

var a = 1;
a = 'hello';

Variable hoisting (hoisting)
All variable declaration statements will be hoisted to the head of the code

console.log(a);
var a = 1;

There is variable promotion, and what actually runs is the following code

var a;
console.log(a); //undefined
a = 1;

"3" identifier

The first character can be any Unicode letter (including English letters and letters from other languages), as well as dollar signs ($) and underscores (_).
The second character and subsequent characters, in addition to Unicode letters, dollar signs and underscores, can also use numbers 0-9.

Notes on "4"

The part of the source code that is ignored by the JavaScript engine is called a comment

// 这是单行注释

/*
 这是
 多行
 注释
*/

由于历史上 JavaScript 可以兼容 HTML 代码的注释,所以<!--和-->也被视为合法的单行注释。

"5" block

JavaScript uses curly braces to group multiple related statements together, called "blocks"

{
    
    
  var a = 1;
}

a // 1

The block does not form a separate scope for the var command, and it is no different from the case where the block is not used

"6" conditional statement (if switch)

if structure

if (布尔值)
  语句;

// 或者
if (布尔值) 语句;

if...else structure

if (m === 3) {
    
    
  // 满足条件时,执行的语句
} else {
    
    
  // 不满足条件时,执行的语句
}

else代码块总是与离自己最近的那个if语句配对。
switch structure

switch (fruit) {
    
    
  case "banana":
    // ...
    break;
  case "apple":
    // ...
    break;
  default:
    // ...
}

Ternary operator?:

(条件) ? 表达式1 : 表达式2

"7" loop statement

A loop statement is used to repeatedly perform an operation
while loop

while (条件)
  语句;

// 或者
while (条件) 语句;

for loop

for (初始化表达式; 条件; 递增表达式)
  语句

// 或者

for (初始化表达式; 条件; 递增表达式) {
    
    
  语句
}

do...while loop

do
  语句
while (条件);

// 或者
do {
    
    
  语句
} while (条件);

break statement and continue statement

The break statement is used to jump out of the code block or the loop
continue statement is used to immediately terminate the current cycle, return to the head of the loop structure, and start the next cycle

label

label:
  语句
top:
  for (var i = 0; i < 3; i++){
    
    
    for (var j = 0; j < 3; j++){
    
    
      if (i === 1 && j === 1) break top;
      console.log('i=' + i + ', j=' + j);
    }
  }
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0

The above code is a double-loop block, and the top label is added after the break command (note that top does not need quotation marks). When the conditions are met, it will directly jump out of the double-layer loop. If no label is used after the break statement, it can only jump out of the inner loop and enter the next outer loop.

2. Data type

All data types contained in "1"

Primitive type: number, string, boolean
Composite type: object
Two special values: undefined, null
对象三个子类型

狭义的对象(object)
数组(array)
函数(function)

"2" Determine the data type of a value

typeof运算符可以返回一个值的数据类型

typeof //运算符
instanceof //运算符
Object.prototype.toString //方法

insert image description here
instanceof运算符可以区分数组和对象
insert image description here

Taking advantage of this, typeof can be used to check an undeclared variable without reporting an error

v
// ReferenceError: v is not defined

typeof v
// "undefined"

//实际编程中,这个特点通常用在判断语句
// 错误的写法
if (v) {
    
    
  // ...
}
// ReferenceError: v is not defined

// 正确的写法
if (typeof v === "undefined") {
    
    
  // ...
}

insert image description here
null的类型是object,这是由于历史原因造成的。1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑null,只把它当作object的一种特殊值。后来null独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。

//detail each data type

《3》null and undefined

The historical reason for the two:
When JavaScript was born in 1995, like Java, it only set null to mean "nothing". According to the C language tradition, null can be automatically converted to 0.

Number(null) // 0
5 + null // 5

However, Brendan Eich, the designer of JavaScript, felt that this was not enough. First of all, in the first version of JavaScript, null was treated as an object just like in Java, and Brendan Eich felt that the value representing "nothing" had better not be an object. Secondly, JavaScript at that time did not include an error handling mechanism. Brendan Eich felt that if null was automatically converted to 0, it would be very difficult to find errors.

Therefore, he designed another undefined. The difference is this: null is an object representing "empty", and it is 0 when converted to a value; undefined is a primitive value representing "no definition here", and it is NaN when converted to a value.

Usage and meaning
null means empty value, that is, the value here is now empty
undefined means "undefined"

// 变量声明了,但没有赋值
var i;
i // undefined

// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
    
    
  return x;
}
f() // undefined

// 对象没有赋值的属性
var  o = new Object();
o.p // undefined

// 函数没有返回值时,默认返回 undefined
function f() {
    
    }
f() // undefined

"4" Boolean value

The following operators return Boolean values:

前置逻辑运算符: ! (Not)
相等运算符:===!====!=
比较运算符:>>=<<=

The conversion rule is that except the following six values ​​are converted to false, other values ​​​​are regarded as true

undefined
null
false
0
NaN
""''(空字符串)

"5" value

Internally in JavaScript, all numbers are stored as 64-bit floating point numbers, even integers. So, 1 and 1.0 are the same, the same number.
JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)
insert image description here
Floats are not exact values

0.1 + 0.2 === 0.3
// false

0.3 / 0.1
// 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)
// false

Numerical precision

1位:符号位,0表示正数,1表示负数2位到第12位(共11位):指数部分13位到第64位(共52位):小数部分(即有效数字)

Value range

Math.pow(2, 1024) // Infinity
Math.pow(2, -1075) // 0

Special Numerical Values
正零和负零
​​In almost all cases, positive and negative zeros are treated as normal zeros.
The only difference is: +0 or -0 is used as the denominator, and the returned values ​​are not equal

-0 === +0 // true
0 === -0 // true
0 === +0 // true

NaN
mainly occurs when parsing a string into a number makes an error

5 - 'x' // NaN

NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number

typeof NaN // 'number'

NaN is not equal to any value, including itself

NaN === NaN // false
数组的indexOf方法内部使用的是严格相等运算符,所以该方法对NaN不成立。
NaN在布尔运算时被当作false。
NaN与任何数(包括它自己)的运算,得到的都是NaN。

Infinity
Infinity compared with NaN, always returns false
Infinity's four operations, in line with infinite mathematical calculation rules

5 * Infinity // Infinity
5 - Infinity // -Infinity
Infinity / 5 // Infinity
5 / Infinity // 0

Global methods related to values

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

parseInt('123') // 123

Automatically remove spaces

parseInt('   81') // 81

If the parameter of parseInt is not a string, it will be converted to a string first and then converted

parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1

When converting a string to an integer, it converts characters one by one in turn. If a character that cannot be converted to a number is encountered, it does not continue and returns the part that has been converted.

parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15

If the first character of the string cannot be converted to a number (except for a sign followed by a number), NaN is returned.

parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1

Hexadecimal conversion
The parseInt method can also accept the second parameter (between 2 and 36), which indicates the hexadecimal of the value being parsed, and returns the decimal number corresponding to the value. By default, the second parameter of parseInt is 10, that is, the default is to convert decimal to decimal.
If the second parameter is not a number, it will be automatically converted to an integer. Only when this integer is between 2 and 36 can meaningful results be obtained. If it is outside this range, NaN will be returned. If the second parameter is 0, undefined or null, it will be ignored directly.

parseInt('10', 37) // NaN
parseInt('10', 1) // NaN
parseInt('10', 0) // 10
parseInt('10', null) // 10
parseInt('10', undefined) // 10

2.parseFloat converts a string to a floating point number

parseFloat('3.14') // 3.14
parseFloat('') // NaN

3.isNaN() Determines whether a value is NaN

isNaN(NaN) // true
isNaN(123) // false

The value of isNaN is true, it may not be NaN, but a string

isNaN('Hello') // true
// 相当于
isNaN(Number('Hello')) // true

For the same reason, isNaN also returns true for objects and arrays

isNaN({
    
    }) // true
// 等同于
isNaN(Number({
    
    })) // true

isNaN(['xzy']) // true
// 等同于
isNaN(Number(['xzy'])) // true

However, isNaN returns false for empty arrays and arrays with only one numeric member

isNaN([]) // false
isNaN([123]) // false
isNaN(['123']) // false

使用isNaN之前,最好判断一下数据类型

function myIsNaN(value) {
    
    
  return typeof value === 'number' && isNaN(value);
}

The isNaN function is used to test whether a value is not a number (NaN). When the argument passed to it is not a number, the function converts it to a number. Returns true if the result of the conversion is a non-numeric value.
However, unexpected behavior occurs when the argument passed to the isNaN function is of a non-string type. For example, if the arguments passed to the isNaN function are objects, arrays, booleans, etc., they will be converted to numbers and false will be returned. In this case, the isNaN function returns false even if the argument itself is not of numeric type.

4.isFinite() returns a Boolean value indicating whether a value is a normal value

isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(undefined) // false
isFinite(null) // true
isFinite(-1) // true

isFinite returns true for all values ​​except Infinity, -Infinity, NaN and undefined which return false.

"4" string
A string is zero or more characters lined up together, placed in single quotes or double quotes
单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号

'key = "value"'
"It's a long journey"

If you want to use single quotes inside a single quote string, you must add a backslash in front of the inner single quotes to escape. The same goes for using double quotes inside a double-quoted string.

'Did she say \'Hello\'?'
// "Did she say 'Hello'?"

"Did she say \"Hello\"?"
// "Did she say "Hello"?"

Escape
special characters that need to be escaped with a backslash

\0 :null(\u0000)
\b :后退键(\u0008)
\f :换页符(\u000C)
\n :换行符(\u000A)
\r :回车键(\u000D)
\t :制表符(\u0009)
\v :垂直制表符(\u000B)
\' :单引号(\u0027)
\" :双引号(\u0022)
\\ :反斜杠(\u005C)

"6" string

Strings can be viewed as arrays of characters, so you can use the array square bracket operator to return the character at a position (position numbers start at 0).

var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"

// 直接对字符串使用方括号运算符
'hello'[1] // "e"

Returns undefined if the number in square brackets exceeds the length of the string, or if the number in square brackets is not a number at all.

'abc'[3] // undefined
'abc'[-1] // undefined
'abc'['x'] // undefined

字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。

var s = 'hello';

delete s[0];
s // "hello"

s[1] = 'a';
s // "hello"

s[5] = '!';
s // "hello"

length attribute
returns the length of the string, the attribute cannot be changed

var s = 'hello';
s.length // 5

s.length = 3;
s.length // 5

s.length = 7;
s.length // 5

"7" object

An object is a collection of "key-value pairs" (key-value), which is an unordered composite data collection.

var obj = {
    
    
  foo: 'Hello',
  bar: 'World'
};

All keys of an object are strings (ES6 introduces Symbol values ​​that can also be used as keys), so it doesn’t matter whether you add quotes or not.

var obj = {
    
    
  'foo': 'Hello',
  'bar': 'World'
};

If the key name is a value, it will be automatically converted to a string.
If the key name does not meet the conditions of the identification name (such as the first character is a number, or contains spaces or operators), and it is not a number, you must add quotation marks, otherwise an error will be reported.

// 报错
var obj = {
    
    
  1p: 'Hello World'
};

// 不报错
var obj = {
    
    
  '1p': 'Hello World',
  'h w': 'Hello World',
  'p+q': 'Hello World'
};

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

var obj = {
    
    
  p: function (x) {
    
    
    return 2 * x;
  }
};

obj.p(1) // 2

Chained references
If the value of the property is still an object, a chained reference is formed.

var o1 = {
    
    };
var o2 = {
    
     bar: 'hello' };

o1.foo = o2;
o1.foo.bar // "hello"

In the above code, the property foo of the object o1 points to the object o2, and the properties of o2 can be referenced in a chain.
The properties of the object are separated by commas, and a comma (trailing comma) may or may not be added after the last property.

var obj = {
    
    
  p: 123,
  m: function () {
    
     ... },
}

Attributes can be created dynamically without having to be specified when the object is declared

var obj = {
    
    };
obj.foo = 123;
obj.foo // 123

Object reference
If different variable names point to the same object, then they are all references to this object, that is to say, they point to the same memory address. Modifying one of the variables will affect all other variables

var o1 = {
    
    };
var o2 = o1;

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

o2.b = 2;
o1.b // 2

If you cancel a variable's reference to the original object, it will not affect the other variable

var o1 = {
    
    };
var o2 = o1;

o1 = 1;
o2 // {}

This kind of reference is only limited to objects, if the two variables point to the same primitive type value. Then, the variables are all copies of the value at this time.

var x = 1;
var y = x;

x = 2;
y // 1

If the line starts with a curly brace, is it an expression or a statement (block of code)?

{
    
     foo: 123 }

为了避免这种歧义,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。

{
    
     console.log(123) } // 123

The above statement is a code block, and it can only be executed if it is interpreted as a code block.

If it is to be interpreted as an object, it is better to put parentheses before the curly braces. Because inside the parentheses, there can only be expressions, so make sure that the curly braces can only be interpreted as objects.

({
    
     foo: 123 }) // 正确
({
    
     console.log(123) }) // 报错

This difference is most evident in the eval statement, which evaluates a string.

eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}

Operations on properties
use the dot operator
use the bracket operator

var obj = {
    
    
  p: 'Hello World'
};

obj.p // "Hello World"
obj['p'] // "Hello World"

Expressions can also be used inside square bracket operators

obj['hello' + ' world']
obj[3 + 3]

注意,数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运算符。

var obj = {
    
    
  123: 'hello world'
};

obj.123 // 报错
obj[123] // "hello world"

Attribute
assignment The dot operator and the square bracket operator can not only be used to read values, but also can be used to assign values.

var obj = {
    
    };

obj.foo = 'Hello';
obj['bar'] = 'World';

JavaScript allows "back-binding" of properties

var obj = {
    
     p: 1 };

// 等价于

var obj = {
    
    };
obj.p = 1;

property view
Object.keys

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

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

Deletion of attributes: the delete command returns true after successful deletion

var obj = {
    
     p: 1 };
Object.keys(obj) // ["p"]

delete obj.p // true
obj.p // undefined
Object.keys(obj) // []

注意,删除一个不存在的属性,delete不报错,而且返回true。

var obj = {
    
    };
delete obj.p // true

只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除

var obj = Object.defineProperty({
    
    }, 'p', {
    
    
  value: 123,
  configurable: false
});

obj.p // 123
delete obj.p // false

delete命令只能删除对象本身的属性,无法删除继承的属性

var obj = {
    
    };
delete obj.toString // true
obj.toString // function toString() { [native code] }

Whether the attribute exists: in operator The in operator
is used to check whether the object contains a certain attribute (note that the key name is checked, not the key value), and it returns true if it contains it, otherwise it returns false.

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

它不能识别哪些属性是对象自身的,哪些属性是继承的
You can use the object's hasOwnProperty method to determine whether it is an object's own property

var obj = {
    
    };
if ('toString' in obj) {
    
    
  console.log(obj.hasOwnProperty('toString')) // false
}

Traversal of attributes: for...in loop
for...in循环用来遍历一个对象的全部属性

var obj = {
    
    a: 1, b: 2, c: 3};

for (var i in obj) {
    
    
  console.log('键名:', i);
  console.log('键值:', obj[i]);
}
// 键名: a
// 键值: 1
// 键名: b
// 键值: 2
// 键名: c
// 键值: 3

它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。 它不仅遍历对象自身的属性,还遍历继承的属性。

For example, all objects inherit the toString property, but the for...in loop will not traverse this property, which is "not traversable" by default.

var obj = {
    
    };

// toString 属性是存在的
obj.toString // toString() { [native code] }

for (var p in obj) {
    
    
  console.log(p);
} // 没有任何输出

Better practice:

var person = {
    
     name: '老张' };

for (var key in person) {
    
    
  if (person.hasOwnProperty(key)) {
    
    
    console.log(key);
  }
}
// name

"8" function

Function declaration
(1) function command

function print(s) {
    
    
  console.log(s);
}

(2) Function expression

var print = function(s) {
    
    
  console.log(s);
};

采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。

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

x
// ReferenceError: x is not defined

print()
// function

(3) Function constructor

var add = new Function(
  'x',
  'y',
  'return x + y'
);

// 等同于
function add(x, y) {
    
    
  return x + y;
}

Duplicate declaration of function
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明

function f() {
    
    
  console.log(1);
}
f() // 2

function f() {
    
    
  console.log(2);
}
f() // 2

上面代码中,后一次的函数声明覆盖了前面一次。而且,由于函数名的提升(参见下文),前一次声明在任何时候都是无效的

first class citizen

Functions are treated on an equal footing with other data types (like string boolean number)

function add(x, y) {
    
    
  return x + y;
}

// 将函数赋值给一个变量
var operator = add;

// 将函数作为参数和返回值
function a(op){
    
    
  return op;
}
a(add)(1, 1)
// 2

Hoisting of function names
JavaScript 引擎将函数名视同变量名

//1.不会报错
f();

function f() {
    
    }

//2.会报错
f();
var f = function (){
    
    };
// TypeError: undefined is not a function

var f;
f();
f = function () {
    
    };

//3 f() // 1
var f = function () {
    
    
  console.log('1');
}

function f() {
    
    
  console.log('2');
}

f() // 1

Function properties and methods

name attribute (returns the name of the function)

function f1() {
    
    }
f1.name // "f1"

function defined by variable assignment, then the name attribute returns the variable name (only if the value of the variable is an anonymous function)

var f2 = function () {
    
    };
f2.name // "f2"

If the value of the variable is a named function, the name attribute returns the name of the function after the function keyword

var f3 = function myName() {
    
    };
f3.name // 'myName'

name属性的一个用处,就是获取参数函数的名字

var myFunc = function () {
    
    };

function test(f) {
    
    
  console.log(f.name);
}

test(myFunc) // myFunc

length property

function f(a, b) {
    
    }
f.length // 2

length属性提供了一种机制,判断定义时和调用时参数的差异,以便实现面向对象编程的“方法重载”(overload)

toString() (returns a string whose content is the source code of the function)

function f() {
    
    
  a();
  b();
  c();
}

f.toString()
// function f() {
    
    
//  a();
//  b();
//  c();
// }

对于那些原生的函数,toString()方法返回function (){[native code]}
Taking advantage of this, multi-line strings can be implemented in disguise

var multiline = function (fn) {
    
    
  var arr = fn.toString().split('\n');
  return arr.slice(1, arr.length - 1).join('\n');
};

function f() {
    
    /*
  这是一个
  多行注释
*/}

multiline(f);
// " 这是一个
//   多行注释"

function scope

Refers to the scope where variables exist:
"1" global scope
"2" function scope
"3" block-level scope
For top-level functions, variables declared outside the function are global variables (global variable), which can be read inside the function.

var v = 1;

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

f()
// 1

Variables defined inside a function, which cannot be read outside, are called "local variables"

function f(){
    
    
  var v = 1;
}

v // ReferenceError: v is not defined

Variables defined inside the function will overwrite global variables with the same name in this scope

var v = 1;

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

f() // 2
v // 1

注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量

if (true) {
    
    
  var x = 5;
}
console.log(x);  // 5

Variable hoisting inside
functions Like the global scope, "variable hoisting" occurs inside function scopes. The variable declared by the var command, no matter where it is, the variable declaration will be promoted to the head of the function body

function foo(x) {
    
    
  if (x > 100) {
    
    
    var tmp = x - 100;
  }
}

// 等同于
function foo(x) {
    
    
  var tmp;
  if (x > 100) {
    
    
    tmp = x - 100;
  };
}

the scope of the function itself

The scope in which the function is executed is the scope in which it was defined, not the scope in which it was called

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

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

f() // 1

If function A calls function B, without considering that function B will not refer to function A's internal variables

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

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

y(x)
// ReferenceError: a is not defined

The function declared inside the function body, the scope is bound inside the function body

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

var x = 2;
var f = foo();
f() // 1

Parameters
When a function is running, sometimes it is necessary to provide external data. Different external data will get different results. This kind of external data is called parameters.

function square(x) {
    
    
  return x * x;
}

square(2) // 4
square(3) // 9

omission of parameters

function f(a, b) {
    
    
  return a;
}

f(1, 2, 3) // 1
f(1) // 1
f() // undefined

//函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
f.length // 2

没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined

function f(a, b) {
    
    
  return a;
}

f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined

Transfer mode
Value transfer: the original type modifies the parameter value in the function body, which will not affect the outside of the function
insert image description here
Pass by reference: the function parameter is a composite type value (array, object, other functions)

var obj = {
    
     p: 1 };

function f(o) {
    
    
  o.p = 2;
}
f(obj);

obj.p // 2

,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值

var obj = [1, 2, 3];

function f(o) {
    
    
  o = [2, 3, 4];
}
f(obj);

obj // [1, 2, 3]

parameter with the same name
如果有同名的参数,则取最后出现的那个值
insert image description here

function f(a, a) {
    
    
  console.log(a);
}

f(1) // undefined

如果要获得第一个a的值,可以使用arguments对象。

function f(a, a) {
    
    
  console.log(arguments[0]);
}

f(1) // 1

arguments object
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来--只有在函数体内部,才可以使用

var f = function (one) {
    
    
  console.log(arguments[0]);
  console.log(arguments[1]);
  console.log(arguments[2]);
}

f(1, 2, 3)
// 1
// 2
// 3

In normal mode, the arguments object can be modified at runtime

var f = function(a, b) {
    
    
  arguments[0] = 3;
  arguments[1] = 2;
  return a + b;
}

f(1, 1) // 5

In strict mode, the arguments object has no linkage with function parameters.

var f = function(a, b) {
    
    
  'use strict'; // 开启严格模式
  arguments[0] = 3;
  arguments[1] = 2;
  return a + b;
}

f(1, 1) // 2

Through the length property of the arguments object, you can determine how many parameters are included in the function call

function f() {
    
    
  return arguments.length;
}

f(1, 2, 3) // 3
f(1) // 1
f() // 0

Relationship with arrays
虽然arguments很像数组,但它是一个对象。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用
The following are two commonly used conversion methods: the slice method and filling a new array one by one.

var args = Array.prototype.slice.call(arguments);

// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
    
    
  args.push(arguments[i]);
}

The arguments object has a callee attribute, which returns its corresponding original function

var f = function () {
    
    
  console.log(arguments.callee === f);
}

f() // true

Other knowledge points of functions
Closure
Closure refers to the combination of function and its related reference environment. That is, when a function accesses a variable inside another function, a closure is formed. Closures allow functions to access variables, parameters, and functions defined in the outer scope, and retain their values, even if these variables and functions have exceeded the scope of the original scope.

For example, in the following code, the inner function innerFunction is a closure, which can access the variable a in the outer function outerFunction:

function outerFunction() {
    
    
  var a = 1;
  function innerFunction() {
    
    
    console.log(a);
  }
  
  return innerFunction;
}

var myInnerFunction = outerFunction();
myInnerFunction(); // 输出1

In this code, calling the outerFunction function returns a reference to the innerFunction function and assigns it to myInnerFunction. After that, every call to myInnerFunction will output the value of the outer variable a referenced by the inner function (1). This is a typical closure pattern.
变量作用域

var n = 999;

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

Under normal circumstances, variables declared inside the function cannot be read outside the function

function f1() {
    
    
  var n = 999;
}

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

Solution:
Inside the function, define another function

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

上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是 JavaScript 语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

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

var result = f1();
result(); // 999

A closure is a function f2, a function that can read variables inside other functions.
可以把闭包简单理解成“定义在一个函数内部的函数”。
Closures make internal variables remember the result of the last call

function createIncrementor(start) {
    
    
  return function () {
    
    
    return start++;
  };
}

var inc = createIncrementor(5);

inc() // 5
inc() // 6
inc() // 7

Why can closures return the internal variables of the outer function? The reason is that the closure (inc in the above example) uses the outer variable (start), so the outer function (createIncrementor) cannot be released from memory. As long as the closure is not cleared by the garbage collection mechanism, the running environment provided by the outer function will not be cleared, and its internal variables will always save the current value for the closure to read.

Immediately invoked function expression (IIFE)
JavaScript stipulates that if the function keyword appears at the beginning of a line, it will be interpreted as a statement.
The solution to calling the function immediately after definition is not to let the function appear at the beginning of the line, so that the engine understands it as an expression. The easiest way to deal with it is to put it in parentheses

(function(){
    
     /* code */ }());
// 或者
(function(){
    
     /* code */ })();

That's it: an immediately invoked function expression

eval command
The eval command accepts a string as an argument and executes the string as a statement

eval('var a = 1;');
a // 1

If the parameter string cannot be run as a statement, an error will be reported.

eval('3x') // Uncaught SyntaxError: Invalid or unexpected token

The strings placed in eval should have their own meaning and cannot be used in conjunction with commands other than eval. For example, the following code will throw an error.

eval('return;'); // Uncaught SyntaxError: Illegal return statement

The above code will report an error because return cannot be used alone and must be used in a function.

If the argument to eval is not a string, it will be returned unchanged.

eval(123) // 123

eval does not have its own scope, and is executed in the current scope, so it may modify the value of variables in the current scope, causing security problems.

var a = 1;
eval('a = 2');

a // 2

In order to prevent this risk, JavaScript stipulates that if strict mode is used, variables declared inside eval will not affect the outer scope.

(function f() {
    
    
  'use strict';
  eval('var foo = 123');
  console.log(foo);  // ReferenceError: foo is not defined
})()

Even in strict mode, eval can still read and write variables in the current scope

(function f() {
    
    
  'use strict';
  var foo = 1;
  eval('foo = 2');
  console.log(foo);  // 2
})()

Alias ​​call for eval

var m = eval;
m('var x = 1');
x // 1

为了保证eval的别名不影响代码优化,JavaScript 的标准规定,凡是使用别名执行eval,eval内部一律是全局作用域

var a = 1;

function f() {
    
    
  var a = 2;
  var e = eval;
  e('console.log(a)');
}

f() // 1

"9" array

An array is a set of values ​​arranged in order

var arr = ['a', 'b', 'c'];
var arr = [];

arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';

Any type of data can be put into an array

var arr = [
  {
    
    a: 1},
  [1, 2, 3],
  function() {
    
    return true;}
];

arr[0] // Object {a: 1}
arr[1] // [1, 2, 3]
arr[2] // function (){return true;}

insert image description here
如果数组的元素还是数组,就形成了多维数组

var a = [[1, 2], [3, 4]];
a[0][1] // 2
a[1][1] // 4

The nature of arrays Arrays are a special kind of object. The typeof operator will return the type of the array is object

typeof [1, 2, 3] // "object"
var arr = ['a', 'b', 'c'];
Object.keys(arr)
// ["0", "1", "2"]

Array keys are actually strings. The reason why it can be read as a value is because the key name of the non-string will be converted to a string

var arr = ['a', 'b', 'c'];

arr['0'] // 'a'
arr[0] // 'a'

A value is always converted into a string first, and then assigned as a key

var a = [];

a[1.00] = 6;
a[1] // 6

,对象有两种读取成员的方法:点结构(object.key)和方括号结构(object[key])。但是,对于数值的键名,不能使用点结构

var arr = [1, 2, 3];
arr.0 // SyntaxError

length attribute
The length attribute of the array, returns the number of members of the array

['a', 'b', 'c'].length // 3

数组的数字键不需要连续,length属性的值总是比最大的那个整数键大1
数组是一种动态的数据结构,可以随时增减数组的成员

var arr = ['a', 'b'];
arr.length // 2

arr[2] = 'c';
arr.length // 3

arr[9] = 'd';
arr.length // 10

arr[1000] = 'e';
arr.length // 1001

The length property is writable. If you artificially set a value smaller than the current number of members, the number of members of the array will be automatically reduced to the value set by length

var arr = [ 'a', 'b', 'c' ];
arr.length // 3

arr.length = 2;
arr // ["a", "b"]

``An effective way to clear the array is to set the length property to 0

var arr = [ 'a', 'b', 'c' ];

arr.length = 0;
arr // []

If the artificially set length is greater than the current number of elements, the number of members of the array will increase to this value, and the newly added positions are all vacancies

var a = ['a'];

a.length = 3;
a[1] // undefined

If the length is artificially set to an illegal value, JavaScript will report an error

// 设置负值
[].length = -1
// RangeError: Invalid array length

// 数组元素个数大于等于2的32次方
[].length = Math.pow(2, 32)
// RangeError: Invalid array length

// 设置字符串
[].length = 'abc'
// RangeError: Invalid array length

值得注意的是,由于数组本质上是一种对象,所以可以为数组添加属性,但是这不影响length属性的值

var a = [];

a['p'] = 'abc';
a.length // 0

a[2.1] = 'abc';
a.length // 0

The value of the length attribute is equal to the largest numeric key plus 1, and this array has no integer keys, so the length attribute remains 0.

If the key name of the array is to add a value beyond the range, the key name will be automatically converted to a string

var arr = [];
arr[-1] = 'a';
arr[Math.pow(2, 32)] = 'b';

arr.length // 0
arr[-1] // "a"
arr[4294967296] // "b"

The in operator
is an operator in that checks whether a key name exists, which is applicable to objects and arrays

var arr = [ 'a', 'b', 'c' ];
2 in arr  // true
'2' in arr // true
4 in arr // false

注意,如果数组的某个位置是空位,in运算符返回false。

var arr = [];
arr[100] = 'a';

100 in arr // true
1 in arr // false

for...in loops and array traversal

var a = [1, 2, 3];

for (var i in a) {
    
    
  console.log(a[i]);
}
// 1
// 2
// 3

for...in不仅会遍历数组所有的数字键,还会遍历非数字键

var a = [1, 2, 3];
a.foo = true;

for (var key in a) {
    
    
  console.log(key);
}
// 0
// 1
// 2
// foo

Array traversal can consider using for loop or while loop

var a = [1, 2, 3];

// for循环
for(var i = 0; i < a.length; i++) {
    
    
  console.log(a[i]);
}

// while循环
var i = 0;
while (i < a.length) {
    
    
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
    
    
  console.log(a[l]);
}

The forEach method of the array can also be used to traverse the array

var colors = ['red', 'green', 'blue'];
colors.forEach(function (color) {
    
    
  console.log(color);
});
// red
// green
// blue

Vacancy of the array
When a certain position of the array is an empty element, that is, there is no value between two commas, it is said that the array has a hole (hole)

var a = [1, , 1];
a.length // 3

The above code shows that the empty space of the array does not affect the length property. Although this position has no value, the engine still considers this position to be valid.
如果最后一个元素后面有逗号,并不会产生空位。

var a = [1, 2, 3,];

a.length // 3
a // [1, 2, 3]

The vacancy of the array can be read, return undefined

var a = [, , ,];
a[1] // undefined

使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性

var a = [1, 2, 3];
delete a[1];

a[1] // undefined
a.length // 3

上面代码用delete命令删除了数组的第二个元素,这个位置就形成了空位,但是对length属性没有影响。也就是说,length属性不过滤空位。
A certain position of the array is empty, and a certain position is undefined, which is different.
If it is a vacancy, use the forEach method of the array, the for...in structure, and the Object.keys method to traverse, and the vacancy will be skipped.

var a = [, , ,];

a.forEach(function (x, i) {
    
    
  console.log(i + '. ' + x);
})
// 不产生任何输出

for (var i in a) {
    
    
  console.log(i);
}
// 不产生任何输出

Object.keys(a)
// []

If a position is undefined, it will not be skipped when traversing.

var a = [undefined, undefined, undefined];

a.forEach(function (x, i) {
    
    
  console.log(i + '. ' + x);
});
// 0. undefined
// 1. undefined
// 2. undefined

for (var i in a) {
    
    
  console.log(i);
}
// 0
// 1
// 2

Object.keys(a)
// ['0', '1', '2']

array-like object
如果一个对象的所有键名都是正整数或零,并且有length属性,那么这个对象就很像数组,语法上称为“类似数组的对象”(array-like object)。

var obj = {
    
    
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function

这种length属性不是动态值,不会随着成员的变化而变化

var obj = {
    
    
  length: 0
};
obj[3] = 'd';
obj.length // 0

Typical "array-like objects" are the arguments object of functions, and most DOM element sets, as well as strings.

// arguments对象
function args() {
    
     return arguments }
var arrayLike = args('a', 'b');

arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false

// DOM元素集
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false

// 字符串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false

The slice method of arrays can turn "array-like objects" into real arrays.

var arr = Array.prototype.slice.call(arrayLike);

In addition to converting to a real array, there is another way for "array-like objects" to use the method of the array, which is to put the method of the array on the object through call().

function print(value, index) {
    
    
  console.log(index + ' : ' + value);
}

Array.prototype.forEach.call(arrayLike, print);

In the above code, arrayLike represents an array-like object. Originally, the forEach() method of the array cannot be used, but through call(), forEach() can be grafted to arrayLike and called.

The following example uses this method to call the forEach method on the arguments object.

// forEach 方法
function logArgs() {
    
    
  Array.prototype.forEach.call(arguments, function (elem, i) {
    
    
    console.log(i + '. ' + elem);
  });
}

// 等同于 for 循环
function logArgs() {
    
    
  for (var i = 0; i < arguments.length; i++) {
    
    
    console.log(i + '. ' + arguments[i]);
  }
}

Strings are also array-like objects, so they can also be traversed with Array.prototype.forEach.call.

Array.prototype.forEach.call('abc', function (chr) {
    
    
  console.log(chr);
});
// a
// b
// c

3. Operators

《1》Arithmetic operators

overview

加法运算符:x + y
减法运算符: x - y
乘法运算符: x * y
除法运算符:x / y
指数运算符:x ** y
余数运算符:x % y
自增运算符:++x 或者 x++
自减运算符:--x 或者 x--
数值运算符: +x
负数值运算符:-x

Addition Operator
The addition operator (+) is the most common operator used to find the sum of two numbers.
JavaScript 允许非数值的相加

true + true // 2
1 + true // 2
//字符串+字符串=连接字符串
'a' + 'bc' // "abc"
//字符串+非字符串=连接字符串
1 + 'a' // "1a"
false + 'a' // "falsea"

加法运算符是在运行时决定,到底是执行相加,还是执行连接 ---‘重载’

'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"

除了加法运算符,其他算术运算符(比如减法、除法和乘法)都不会发生重载。它们的规则是:所有运算子一律转为数值,再进行相应的数学运算。

1 - '2' // -1
1 * '2' // 2
1 / '2' // 0.5

Addition of objects
If the operator is an object, it must first be converted to a value of the original type, and then added

var obj = {
    
     p: 1 };
obj + 2 // "[object Object]2"

Generally speaking, the valueOf method of an object always returns the object itself, and then automatically calls the toString method of the object to convert it into a string. The object's toString method returns [object Object] by default, so you get the result of the previous example.

var obj = {
    
    
  valueOf: function () {
    
    
    return 1;
  }
};

obj + 2 // 3
var obj = {
    
    
  toString: function () {
    
    
    return 'hello';
  }
};

obj + 2 // "hello2"
var obj = new Date();
obj.valueOf = function () {
    
     return 1 };
obj.toString = function () {
    
     return 'hello' };

obj + 2 // "hello2"

Remainder Operator
The remainder operator (%) returns the remainder when the previous operator is divided by the next operator.

12 % 5 // 2

运算结果的正负号由第一个运算子的正负号决定

-1 % 2 // -1
1 % -2 // 1

为了得到负数的正确余数值,可以先使用绝对值函数

// 错误的写法
function isOdd(n) {
    
    
  return n % 2 === 1;
}
isOdd(-5) // false
isOdd(-4) // false

// 正确的写法
function isOdd(n) {
    
    
  return Math.abs(n % 2) === 1;
}
isOdd(-5) // true
isOdd(-4) // false

The remainder operator can also be used for floating-point arithmetic. However, because floating-point numbers are not exact values, completely accurate results cannot be obtained.

6.5 % 2.1
// 0.19999999999999973

Increment and Decrement Operators

var x = 1;
++x // 2
x // 2

--x // 1
x // 1

运算的副作用(side effect):运算之后,变量的值发生变化
The increment and decrement operators are the only two operators that have side effects, and none of the other operators change the value of the variable.
放在变量之后,会先返回变量操作前的值,再进行自增/自减操作;放在变量之前,会先进行自增/自减操作,再返回变量操作后的值

var x = 1;
var y = 1;

x++ // 1
++y // 2

Numeric Operator, Negative Numeric Operator
数值运算符:可以将任何值转为数值(与Number函数的作用相同)。
数值运算符号和负数值运算符,都会返回一个新的值,而不会改变原始变量的值

+true // 1
+[] // 0
+{
    
    } // NaN

The negative value operator (-) also has the function of converting a value into a value, but the obtained value is positive and negative. Concatenating two negative numeric operators is equivalent to a numeric operator.

var x = 1;
-x // -1
-(-x) // 1

exponent operator

2 ** 4 // 16
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512

assignment operator

// 将 1 赋值给变量 x
var x = 1;

// 将变量 y 的值赋值给变量 x
var x = y;

赋值运算符还可以与其他运算符结合,形成变体

// 等同于 x = x + y
x += y

// 等同于 x = x - y
x -= y

// 等同于 x = x * y
x *= y

// 等同于 x = x / y
x /= y

// 等同于 x = x % y
x %= y

// 等同于 x = x ** y
x **= y

Here is the combination with the bitwise operators

// 等同于 x = x >> y
x >>= y

// 等同于 x = x << y
x <<= y

// 等同于 x = x >>> y
x >>>= y

// 等同于 x = x & y
x &= y

// 等同于 x = x | y
x |= y

// 等同于 x = x ^ y
x ^= y

《2》Comparison operator

Overview
Comparison operators are used to compare the magnitude of two values ​​and return a Boolean value
注意,比较运算符可以比较各种类型的值,不仅仅是数值。

2 > 1 // true

JavaScript provides a total of 8 comparison operators

> 大于运算符
< 小于运算符
<= 小于或等于运算符
>= 大于或等于运算符
== 相等运算符
=== 严格相等运算符
!= 不相等运算符
!== 严格不相等运算符

八个比较运算符分成两类:相等比较和非相等比较
For non-equal comparison, the algorithm first checks whether the two operators are both strings, and if so, compares them in lexicographical order (actually comparing Unicode code points); otherwise, converts both operators into numeric values, and then compares the numeric values

Non-Equality Operators: Comparison of Strings

'cat' > 'dog' // false
'cat' > 'catalog' // false
'cat' > 'Cat' // true'
'大' > '小' // false

Non-equality operator: comparison of non-strings
如果两个运算子之中,至少有一个不是字符串,需要分成以下两种情况

(1) Primitive type value
如果两个运算子都是原始类型的值,则是先转成数值再比较

5 > '4' // true
// 等同于 5 > Number('4')
// 即 5 > 4

true > false // true
// 等同于 Number(true) > Number(false)
// 即 1 > 0

2 > true // true
// 等同于 2 > Number(true)
// 即 2 > 1

任何值(包括NaN本身)与NaN使用非相等运算符进行比较,返回的都是false

1 > NaN // false
1 <= NaN // false
'1' > NaN // false
'1' <= NaN // false
NaN > NaN // false
NaN <= NaN // false

(2) Object
If the operator is an object, it will be converted to a value of the original type and then compared.

var x = [2];
x > '11' // true
// 等同于 [2].valueOf().toString() > '11'
// 即 '2' > '11'

x.valueOf = function () {
    
     return '1' };
x > '11' // false
// 等同于 (function () { return '1' })() > '11'
// 即 '1' > '11'

comparison between two objects

[2] > [1] // true
// 等同于 [2].valueOf().toString() > [1].valueOf().toString()
// 即 '2' > '1'

[2] > [11] // true
// 等同于 [2].valueOf().toString() > [11].valueOf().toString()
// 即 '2' > '11'

({
    
     x: 2 }) >= ({
    
     x: 1 }) // true
// 等同于 ({ x: 2 }).valueOf().toString() >= ({ x: 1 }).valueOf().toString()
// 即 '[object Object]' >= '[object Object]'

strict equality operator

相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为“同一个值”。
相等运算符(==)会将它们转换成同一个类型,再用严格相等运算符进行比较。

(1) Values ​​of different types
If the types of the two values ​​are different, return false directly

1 === "1" // false
true === "true" // false

(2) Primitive type values ​​of the same type
When comparing primitive type values ​​(numbers, strings, and Boolean values) of the same type, true is returned if the values ​​are the same, and false is returned if the values ​​are different.

1 === 0x1 // true

(3) Composite type value
比较它们是否指向同一个地址

{
    
    } === {
    
    } // false
[] === [] // false
(function () {
    
    } === function () {
    
    }) // false

Two variables are equal if they refer to the same object

var v1 = {
    
    };
var v2 = v1;
v1 === v2 // true

注意,对于两个对象的比较,严格相等运算符比较的是地址,而大于或小于运算符比较的是值

var obj1 = {
    
    };
var obj2 = {
    
    };

obj1 > obj2 // false
obj1 < obj2 // false
obj1 === obj2 // false

(4) undefined and null
undefined和null与自身严格相等

undefined === undefined // true
null === null // true

strict inequality operator
先求严格相等运算符的结果,然后返回相反值

1 !== '1' // true
// 等同于
!(1 === '1')

Equality operator
比较不同类型的数据时,相等运算符会先将数据进行类型转换,然后再用严格相等运算符比较。
(1) Primitive type value
The value of the primitive type will be converted into a value and then compared

1 == true // true
// 等同于 1 === Number(true)

0 == false // true
// 等同于 0 === Number(false)

2 == true // false
// 等同于 2 === Number(true)

2 == false // false
// 等同于 2 === Number(false)

'true' == true // false
// 等同于 Number('true') === Number(true)
// 等同于 NaN === 1

'' == 0 // true
// 等同于 Number('') === 0
// 等同于 0 === 0

'' == false  // true
// 等同于 Number('') === Number(false)
// 等同于 0 === 0

'1' == true  // true
// 等同于 Number('1') === Number(true)
// 等同于 1 === 1

'\n  123  \t' == 123 // true
// 因为字符串转为数字时,省略前置和后置的空格

(2) Object and primitive type value comparison

// 数组与数值的比较
[1] == 1 // true

// 数组与字符串的比较
[1] == '1' // true
[1, 2] == '1,2' // true

// 对象与布尔值的比较
[1] == true // true
[2] == true // false

(3) undefined and null
undefined和null只有与自身比较,或者互相比较时,才会返回true;与其他类型的值比较时,结果都为false

undefined == undefined // true
null == null // true
undefined == null // true

false == null // false
false == undefined // false

0 == null // false
0 == undefined // false

(4) Disadvantages of the equality operator
相等运算符隐藏的类型转换,会带来一些违反直觉的结果

0 == ''             // true
0 == '0'            // true

2 == true           // false
2 == false          // false

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

建议不要使用相等运算符(==),最好只使用严格相等运算符(===)
Inequality operator
Evaluates the result of the equality operator and returns the opposite value

1 != '1' // false

// 等同于
!(1 == '1')

"3" Boolean operators

Negation operator (!)
对于非布尔值,取反运算符会将其转为布尔值
The following six values ​​are negated to true, and all other values ​​are false
undefined
null
false
0
NaN
empty string ('')

!undefined // true
!null // true
!0 // true
!NaN // true
!"" // true

!54 // false
!'hello' // false
![] // false
!{
    
    } // false

If a value is negated twice in a row, it is equivalent to converting it into a corresponding Boolean value, which is the same as the Boolean function.

!!x
// 等同于
Boolean(x)

And operator (&&)
如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值

't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""

var x = 1;
(1 - 1) && ( x += 1) // 0
x // 1
if (i) {
    
    
  doSomething();
}

// 等价于

i && doSomething();

OR operator (||)
如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值

't' || '' // "t"
't' || 'f' // "t"
'' || 'f' // "f"
'' || '' // ""
var x = 1;
true || (x = 2) // true
x // 1

Ternary conditional operator (?:)

't' ? 'hello' : 'world' // "hello"
0 ? 'hello' : 'world' // "world"

if...else是语句,没有返回值;三元条件表达式是表达式,具有返回值。所以,在需要返回值的场合,只能使用三元条件表达式,而不能使用if..else。

《4》Binary operator

二进制或运算符(or):符号为|,表示若两个二进制位都为0,则结果为0,否则为1
二进制与运算符(and):符号为&,表示若两个二进制位都为1,则结果为1,否则为0
二进制否运算符(not):符号为~,表示对一个二进制位取反。
异或运算符(xor):符号为^,表示若两个二进制位不相同,则结果为1,否则为0
左移运算符(left shift):符号为<<,详见下文解释。
右移运算符(right shift):符号为>>,详见下文解释。
头部补零的右移运算符(zero filled right shift):符号为>>>

《5》Other operators, order of operation

void operator
void运算符的作用是执行一个表达式,然后不返回任何值,或者说返回undefined

void 0 // undefined
void(0) // undefined

The main purpose of this operator is the browser's bookmarklet (Bookmarklet), and inserting codes into hyperlinks to prevent web page jumps.

<script>
function f() {
    
    
  console.log('Hello World');
}
</script>
<a href="http://example.com" onclick="f(); return false;">点击</a>

In the above code, after the link is clicked, the code of onclick will be executed first. Since onclick returns false, the browser will not jump to example.com.
The void operator can replace the above writing.

<a href="javascript: void(f())">文字</a>

The user clicks the link to submit the form, but no page jump occurs.

<a href="javascript: void(document.form.submit())">
  提交
</a>

Comma operator
The comma operator is used to evaluate two expressions and return the value of the latter expression

'a', 'b' // "b"

var x = 0;
var y = (x++, 10);
x // 1
y // 10

insert image description here
In the above code, the operation before the comma is performed first, and then the value after the comma is returned.

Priority
Less than or equal to (<=), strict equality (===), or (||), ternary (?:), equal sign (=)

The function of parentheses
One is to put the expression in the parentheses to increase the priority of the operation;
the other is to follow the function and the function is to call the function

function f() {
    
    
  return 1;
}

(f) // function f(){return 1;}
f() // 1

In the above code, the function is placed in parentheses to return the function itself, and the parentheses follow the function to call the function.

left associative and right associative

a OP b OP c
// 方式一 左结合
(a OP b) OP c

// 方式二 右结合
a OP (b OP c)
x + y + z

// 引擎解释如下
(x + y) + z

4. Topics on Grammar

《1》Data type conversion

var x = y ? 1 : 'a';

(1) Force conversion of
Number()
使用Number函数,可以将任意类型的值转化成数值。
primitive type value

// 数值:转换后还是原来的值
Number(324) // 324

// 字符串:如果可以被解析为数值,则转换为相应的数值
Number('324') // 324

// 字符串:如果不可以被解析为数值,返回 NaN
Number('324abc') // NaN

// 空字符串转为0
Number('') // 0

// 布尔值:true 转成 1,false 转成 0
Number(true) // 1
Number(false) // 0

// undefined:转成 NaN
Number(undefined) // NaN

// null:转成0
Number(null) // 0

Number函数将字符串转为数值,要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN

parseInt('42 cats') // 42
Number('42 cats') // NaN
parseInt('\t\v\r12.34\n') // 12
Number('\t\v\r12.34\n') // 12.34

object
简单的规则是,Number方法的参数是对象时,将返回NaN,除非是包含单个数值的数组

Number({
    
    a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
var obj = {
    
    x: 1};
Number(obj) // NaN

// 等同于
if (typeof obj.valueOf() === 'object') {
    
    
  Number(obj.toString());
} else {
    
    
  Number(obj.valueOf());
}

In the above code, the Number function converts the obj object into a value. A series of operations occurred behind the scenes. First, the obj.valueOf method was called, and the result returned to the object itself; then, the obj.toString method was continued to be called, and the string [object Object] was returned at this time, and the Number function was used on this string to get NaN.

If the toString method returns a value that is not of the original type, an error will be reported as a result.

var obj = {
    
    
  valueOf: function () {
    
    
    return {
    
    };
  },
  toString: function () {
    
    
    return {
    
    };
  }
};

Number(obj)
// TypeError: Cannot convert object to primitive value

String()
String函数可以将任意类型的值转化成字符串
(1) primitive type value

Value: converted to the corresponding string.
String: the original value after conversion.
Boolean: true is converted to the string "true", and false is converted to the string "false".
undefined: converted to the string "undefined".
null: converted to the string "null".

String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"

(2) If the parameter of the Object
String method is an object, return a type string; if it is an array, return the string form of the array

String({
    
    a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
String({
    
    a: 1})
// "[object Object]"

// 等同于
String({
    
    a: 1}.toString())
// "[object Object]"

Boolean()
Boolean()函数可以将任意类型的值转为布尔值
except the conversion result of the following five values ​​is false, all other values ​​are true

undefined
null
0(包含-0+0
NaN
''(空字符串)
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false

Of course, the two boolean values ​​true and false will not change

Boolean(true) // true
Boolean(false) // false

注意,所有对象(包括空对象)的转换结果都是true,甚至连false对应的布尔对象new Boolean(false)也是true

Boolean({
    
    }) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true

(2) Automatic conversion
遇到以下三种情况时,JavaScript 会自动转换数据类型,即转换是自动完成的,用户不可见
In the first case, different types of data are mutually operated.

123 + 'abc' // "123abc"

In the second case, Boolean values ​​are calculated for non-Boolean data.

if ('abc') {
    
    
  console.log('hello')
}  // "hello"

In the third case, unary operators (i.e. + and -) are used on values ​​of non-numeric types.

+ {
    
    foo: 'bar'} // NaN
- [1, 2, 3] // NaN

Automatic conversion to boolean values
​​Except for the following five values, others are automatically converted to true

undefined
null
+0-0
NaN
''(空字符串)

Automatic conversion to string
The automatic conversion of strings mainly occurs during the addition of strings. When one value is a string and the other is a non-string, the latter is converted to a string

'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {
    
    } // "5[object Object]"
'5' + [] // "5"
'5' + function (){
    
    } // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"

Automatically convert to numeric

'5' - '2' // 3
'5' * '2' // 10
true - 1  // 0
false - 1 // -1
'1' - 1   // 0
'5' * []    // 0
false / '5' // 0
'abc' - 1   // NaN
null + 1 // 1
undefined + 1 // NaN

null转为数值时为0,而undefined转为数值时为NaN

《2》Error handling mechanism

(1) Error instance object
JavaScript 原生提供Error构造函数,所有抛出的错误都是这个构造函数的实例

var err = new Error('出错了');
err.message // "出错了"

Most JavaScript engines also provide name and stack attributes for Error instances, which respectively represent the name of the error and the error stack, but they are non-standard, not every implementation has message: error message name: error name (non-standard attribute) stack: error stack (non-
standard
attribute
)

if (error.name) {
    
    
  console.log(error.name + ': ' + error.message);
}

(2) Native error type
SyntaxError object
SyntaxError对象是解析代码时发生的语法错误。

// 变量名错误
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token

// 缺少括号
console.log 'hello');
// Uncaught SyntaxError: Unexpected string

ReferenceError object
ReferenceError对象是引用一个不存在的变量时发生的错误。

// 使用一个不存在的变量
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined

Another trigger scenario is to assign a value to an object that cannot be assigned, such as assigning a value to the running result of a function.

// 等号左侧不是变量
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment

RangeError object
RangeError对象是一个值超出有效范围时发生的错误。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。

// 数组长度不得为负数
new Array(-1)
// Uncaught RangeError: Invalid array length

TypeError object
TypeError对象是变量或参数不是预期类型时发生的错误。

new 123
// Uncaught TypeError: 123 is not a constructor

var obj = {
    
    };
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function

URIError object
URIError对象是 URI 相关函数的参数不正确时抛出的错误,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。

decodeURI('%2')
// URIError: URI malformed

When the eval function of the EvalError object
is not executed correctly, an EvalError error will be thrown. This error type is no longer used and is kept only for compatibility with previous code.

Summarize
以上这6种派生错误,连同原始的Error对象,都是构造函数

var err1 = new Error('出错了!');
var err2 = new RangeError('出错了,变量超出有效范围!');
var err3 = new TypeError('出错了,变量类型无效!');

err1.message // "出错了!"
err2.message // "出错了,变量超出有效范围!"
err3.message // "出错了,变量类型无效!"

(3) Custom errors

function UserError(message) {
    
    
  this.message = message || '默认信息';
  this.name = 'UserError';
}

UserError.prototype = new Error();
UserError.prototype.constructor = UserError;

new UserError('这是自定义的错误!');

(4) throw statement
throw语句的作用是手动中断程序执行,抛出一个错误。

var x = -1;

if (x <= 0) {
    
    
  throw new Error('x 必须为正数');
}
// Uncaught Error: x 必须为正数

throw can also throw custom errors.

function UserError(message) {
    
    
  this.message = message || '默认信息';
  this.name = 'UserError';
}

throw new UserError('出错了!');
// Uncaught UserError {message: "出错了!", name: "UserError"}

In fact, throw can throw any type of value. That is, its argument can be any value.

// 抛出一个字符串
throw 'Error!';
// Uncaught Error!

// 抛出一个数值
throw 42;
// Uncaught 42

// 抛出一个布尔值
throw true;
// Uncaught true

// 抛出一个对象
throw {
    
    
  toString: function () {
    
    
    return 'Error!';
  }
};
// Uncaught {toString: ƒ}

5) try...catch structure

try {
    
    
  throw new Error('出错了!');
} catch (e) {
    
    
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: 出错了!
//   at <anonymous>:3:9
//   ...

In order to catch different types of errors, judgment statements can be added to the catch code block.

try {
    
    
  foo.bar();
} catch (e) {
    
    
  if (e instanceof EvalError) {
    
    
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    
    
    console.log(e.name + ": " + e.message);
  }
  // ...
}

(6) finally code block
The try...catch structure allows adding a finally code block at the end, indicating that no matter whether there is an error or not, the statement must be run at the end

function cleansUp() {
    
    
  try {
    
    
    throw new Error('出错了……');
    console.log('此行不会执行');
  } finally {
    
    
    console.log('完成清理工作');
  }
}

cleansUp()
// 完成清理工作
// Uncaught Error: 出错了……
//    at cleansUp (<anonymous>:3:11)
//    at <anonymous>:10:1
function f() {
    
    
  try {
    
    
    console.log(0);
    throw 'bug';
  } catch(e) {
    
    
    console.log(1);
    return true; // 这句原本会延迟到 finally 代码块结束再执行
    console.log(2); // 不会运行
  } finally {
    
    
    console.log(3);
    return false; // 这句会覆盖掉前面那句 return
    console.log(4); // 不会运行
  }

  console.log(5); // 不会运行
}

var result = f();
// 0
// 1
// 3

result
// false

"3" programming style

It is recommended to always use braces for blocks

block {
    
    
  // ...
}

Because JavaScript will automatically add a semicolon at the end of the sentence, resulting in some undetectable errors

Parentheses

表示函数调用时,函数名与左括号之间没有空格。

表示函数定义时,函数名与左括号之间没有空格。

其他情况时,前面位置的语法元素与左括号之间,都有一个空格。

The semicolon at the end of the line, do not omit

Cases without semicolons
(1) for and while loops

for ( ; ; ) {
    
    
} // 没有分号

while (true) {
    
    
} // 没有分号

(2) Branch statement: if, switch, try

if (true) {
    
    
} // 没有分号

switch () {
    
    
} // 没有分号

try {
    
    
} catch {
    
    
} // 没有分号

(3) The declaration statement of the function

function f() {
    
    
} // 没有分号

JavaScript 最大的语法缺点,可能就是全局变量对于任何一个代码块,都是可读可写。这对代码的模块化和重复使用,非常不利
Consider capitalizing variable names to make it easier to see that this is a global variable, such as UPPER_CASE
variable declarations
JavaScript 会自动将变量声明“提升”(hoist)到代码块(block)的头部。

《4》console object and console

(1) The console object
is used to debug the program and display the error information when the webpage code is running
. It provides a command line interface for interacting with the webpage code

(2) Static method of console object
console对象提供的各种静态方法,用来与控制台窗口互动。

console.log(),console.info(),console.debug()
console.warn(),console.error()
console.table()
console.count()
console.dir(),console.dirxml()
console.assert()
console.time(),console.timeEnd()
console.group(),console.groupEnd(),console.groupCollapsed()
console.trace(),console.clear()
(3)控制台命令行 API
debugger 语句

5. Standard library

6. Object Oriented Programming

7. Asynchronous operation

8.DOM

9. Events

10. Browser model

11. Appendix: Web page element interface

Guess you like

Origin blog.csdn.net/Lixu_No_1/article/details/131143065
Recommended