1. JavaScript 变量
JavaScript 的变量是松散型变量,和之前在 python 中的 动静机 很相似,这让我想起了之前的一篇讲 python 变量的文章,松散型指的是变量能够存任何类型数据,所谓变量只是仅仅是存值的占位符而已。如下操作齐全没问题,数据类型动静扭转。
var temp = 123;
temp = "west";
注 :应用var
定义的变量将成为定义该变量的的作用域中的局部变量
如果不必 var 代表变量是一个全局变量,这里又波及到了暗示全局变量。
也就是说 在函数中定义的变量在函数退出后即会销毁,这里之前的作用域链 提到过。
注 :这里再次强调var temp = 123;
的步骤,并不是间接赋值,波及到了 预编译,只有调用该变量时才会给他赋值,之后立刻被销毁。
【例】猜它会怎么报错?
function dc() {
var temp = 123;
temp = "west";
}
dc();
alert(temp);
【Error】:Uncaught ReferenceError: temp is not defined
2. 数据类型
ECMAScript 有五种根本数据类型,如下
undefined
null
boolean
number
string
bigint
symbol
最新版的 ECMAScript 的根本数据类型新增了:
- Symbol
- BigInt
还有一种简单数据类型 Object
,当然相似于 Function、Number、Error、RegExp 也是简单数据类型。
ECMAScript 不反对任何创立自定义类型的机制,就好比 C 语言的自定义构造体是不反对的。
reference:MDN——最新的 ECMAScript 规范定义了 8 种数据类型
2.1. undefined 和 null
实际上 undefined
值派生自 null
值,所以undefined == null //true
,undefined 类型只有一个值,即 undefined,引入它是为了辨别空对象指针和未经初始化的变量。
null 示意一空对象指针,如果定义的变量未来用于保留对象,那么最好将该变量初始化为 null,这样只有查看 null 值就能够晓得相应的变量是否曾经保留了一个对象的援用。
还有,没初始化的和没申明的变量应用 typeof 会返回 undefined,然而倡议都对数据进行初始化,这样返回 undefined 时就会晓得变量时还没申明而不是没初始化。
【例】
var car = null;
if (car != null) {// 操作}
注 :只管 null 和 undefined 又有非凡关系,但他们齐全不同,任何状况都 没有必要 把一个变量值显式地设置为 undefined,但对 null 并不实用,只有意在保留对象的变量还没有真正保留对象,就应该明确保留变量为 null 值。这样不仅体现 null 作为空对象指针的常规,也有助于进一步辨别 null 和 undefined。
2.2. Boolean
留神 true、false
辨别大小写
存在 Boolean()
函数将一个值转换为对应的 Boolean 值。
2.3. Number
- 八进制在严格模式下有效,会抛出
Uncaught SyntaxError: Octal literals are not allowed in strict mode
,在进行算术运算时所有八进制和十六进制示意的数值都会转换为十进制。 - 对于小数点前面没有数字的浮点数,ECMAScript 会把它转换为整数保留。
- 对于浮点数值的精度计算远不如整数值,比方
0.1+0.2==0.30000000000000004
,因而永远不要测试某个特定得浮点数值。 - Infinity 是不能加入计算的数值,如果数值超出范围会返回
Infinity
表无穷,可应用isFinite()
查看数值是否在范畴内,如果在最大与最小数值之间会返回true
。 NaN
,即非数值,任何波及 NaN 的操作都会返回 NaN,它用来示意本要返回数值的操作数未返回数值的状况(这样就不会报错了)。其次 NaN 与任何数值都不相等,包含本人。有isNaN()
函数可承受一个任意类型的参数,它会尝试把值转换为数值,比方字符串“10”
和 Boolean 值,而不能转换为数值的值会返回true
。- JS 中 number 就是 number,并没有申明浮点数、整型数的关键字,浮点数最高精度是 17 位小数
2.4. 数值转换
Number()
可用于任何数据类型parseFloat()
(只解析十进制的值,故只有一个参数), 用于把字符串转换为数值parseInt()
(有两个参数,后者为进制参数)用于把字符串转换为数值
留神(parseInt(string [, radix])
)是把 string 转换成数字,让后把它当作 radix 进制的数字转换成十进制。例如 parseInt('321',2)
这样的操作会返回 NaN,因为 321 不可能是 2 进制的。
与 parseInt
相似,parseFloat
从第一个字符开始(地位 0)解析字符串,直到开端或者解析到遇见一个有效的浮点数字字符为止。还要记住字符串中的第一个小数点无效而第二个是有效的。
因为 Number()
函数在转换字符时比较复杂并且不够正当,因而在解决整数时更罕用的时 parseInt()
,还有 ES3 和 ES5 对于八进制字面量的字符串进行解析时存在一致,在 ES3 中console.log(parseInt("070"));
会输入 56,然而 ES5 中会输入 70,起因是 ES5 中的 parseInt 曾经不具备解析八进制的能力。这个时候加上 parseInt 的第二个参数就能够扭转这状况,实际上带上了第二个参数之后都不再须要在字符串中应用进制字面量,比方 console.log(parseInt("70", 8));
不再须要写 070 了。
parseFloat
始终会疏忽前导的 0。十六进制始终会被转换为 0。相比于 parseInt 多解析了一个小数点,而且它没有第二个参数,只解析十进制。
console.log(Number("Hello,Word!")); //NaN
console.log(Number("")); //0
console.log(Number("000011")); //11
console.log(Number(true)); //1
console.log(parseInt("1234blue")); //1234
console.log(parseInt("")); //NaN
console.log(parseInt("0xA")); //10
console.log(parseInt("22.5")); //22
console.log(parseInt("070")); //70
console.log(parseInt("70")); //70
console.log(parseInt("0xf")); //15
console.log(parseInt("0xAF", 16)); //175
console.log(parseInt("AF")); //NaN
console.log(parseInt("10", 2)); //2
console.log(parseInt("10", 8)); //8
console.log(parseInt("10", 10)); //10
console.log(parseInt("10", 16)); //16
console.log(parseFloat("1234blue")); //1234
console.log(parseFloat("0xA")); //0
console.log(parseFloat("22.5")); //22.5
console.log(parseFloat("22.34.5")); //22.34
console.log(parseFloat("0908.5")); //908.5
console.log(parseFloat("3.125e7")); //31250000
2.5. String
注:
- PHP 中双引号与单引号会影响对字符串解释形式的不同
- 字符串的值不可扭转,要扭转变量存的字符串只能销毁原来的字符串,再用蕴含新值的字符串填充该变量。
var test = "Java";
test = test + "Script";
alert(test);
看似是拼接字符串,实际上不是,零碎在后盾创立了一个新的可包容 JavaScript 的变量,再把 JavaScript 填充进去,,最初再销毁原来的两个字符串。
转换为字符串:
toString()
、String()
但需注意二者的不同以及对于undefined、null
二者的特殊性(因为它俩没有 toString 办法)
console.log(null.toString());
//Uncaught TypeError: Cannot read property 'toString' of null
在不晓得要转换的值是否是 null、undefined 的状况下,为避免报错可应用 String 对其进行转换。
百度百科_字面量
| 字面量(也叫转义序列)| 含意 |
| :——————–: | :—————————————————————————-: |
| n
| 换行 |
| t
| 制表 |
| b
| 空格 |
| r
| 回车 |
| f
| 进纸(走纸换页)|
| “ | 斜杠 |
| '
| 单引号 |
| "
| 双引号 |
| xnn
| 以十六进制代码 nn 示意的一个字符(其中 n 为 0~F)
例:x41 示意“A”|
| unnnn
| 以十六进制代码 nnnn 示意的一个 Unicode 字符(其中 n 为 0~F)
例:u03a3 表希腊字符 Σ |
2.6. Object
一组数据和性能的汇合
创立:var test = Object(); // 在不给构造函数传递参数的状况下‘()’可省略
重要思维
在 ECMAScript 中(就像 Java 中的 java.lang.Object 对象一样)Object 类型是所有它的实例和根底. 换句话说,Object 类型所具备的所有属性和办法也同样存在于更具体的对象中, 和 Java 创建对象相似。
Object 的每个实例都具备下列属性和办法:
- Construor
- hasOwnProperty(propertyName)
- isPrototypeof(object)
- propertyIsEnumerable(propertyName)
- toLocaleString()
- toString()
- valueOf()
附:JS 中 toString()、toLocaleString()、valueOf()的区别
在数里讲的很具体了。
2.7. 附加:typeof
参考:typeof 返回值
应用 typeof 操作符可返回下列某个 字符串
"undefined"
——值未定义"boolean"
——值为布尔值"string"
——值为字符串"number"
——值为数值"object"
——值为对象或 null,或者其余援用类型数据"function"
——值为函数
因为最新的 ES 又新增了一些内容,所以当初它还能够返回
"bigint"
"symbol"
从技术角度来讲,function 在 JS 中是一个对象,而不是一种数据类型,然而函数的确有一些非凡的属性,因而通过 typeof 来辨别它们是有必要的。
注 :强调 typeof 是一个操作符而不是一个函数,括号不是必须的,null 之所以会返回Object
是因为 null 最后是作为空对象的占位符的应用的,被认为是空对象的援用。在对正则表达式调用 typeof 时,Safari5 及之前的版本、Chrome7 及之前的版本会返回"function"
,其余浏览器会返回"object"
因为 typeof 只能返回这几种字符串,所以它是不欠缺的,比方在面对 object 和 array 时,都只会返回
"object"
,对这一缺点能够应用以下办法补救
// typeof 的欠缺
function type(target) {var ret = typeof (target);
var template = {"[object Array]": "array",
"[object Object]": "object",
"[object Number]": "number - object",
"[object Boolean]": "boolean - object",
"[object String]": "string - object",
}
if (target === null) {return "null";}
if (ret == "object") {var str = Object.prototype.toString.call(target);
return template[str];
} else {return ret;}
}
3. JavaScript 变量的问题
JavaScript 变量松散型的实质, 决定了他只是在特定工夫用于保留特定值的一个名字而已。不存在定义某个变量必须要保留某种数据类型值的规定,变量的值及数据类型能够在脚本的生命周期内扭转。
ECMAScript 不认为字符串是援用类型的,这点与其余语言不同。
ECMAScript 变量可能蕴含两种不同数据类型的值:
- 根本数据类型
- 援用型
4. 以下为来自 MDN 的摘抄
其实内容和下面的很多事反复的,次要是想看英文的,所以摘抄重要的点。
参考:Grammar and types
4.1. Basics
- case-sensitive(辨别大小写)
- uses the Unicode character set(汇合)
- instructions are called statements and are separated by semicolons (;).
对于语句开端到底要不要加分号?MDN_ASI 给出了答复
4.2. Declarations
JavaScript has three kinds of variable declarations.
- var:Declares a variable, optionally initializing it to a value.
- let:Declares a block-scoped(块作用域), local variable(局部变量), optionally initializing it to a value.
- const:Declares a block-scoped, read-only named constant(只读命名常量).
With the keyword
var
. For example, var x = 42. This syntax can be used to declare both local and global variables, depending on the execution context.With the keyword
const
orlet
. For example, let y = 13. This syntax can be used to declare a block-scope local variable. (See Variable scope below.)
4.3. Evaluating variables
- The undefined value behaves as false when used in a boolean context.
- The undefined value converts to NaN when used in numeric context.
- When you evaluate a null variable, the null value behaves as 0 in numeric contexts and as false in boolean contexts.
4.4. Variable scope
- When you declare a variable outside of any function, it is called a global variable, it is available to any other code in the current document.
- When you declare a variable within a function, it is called a local variable, because it is available only within that function.
- JavaScript before ECMAScript 2015 does not have block statement scope. Rather, a variable declared within a block is local to the function (or global scope) that the block resides within.(在块中申明的变量是该块所驻留的函数(或全局范畴)的局部变量)
- The scope of x is not limited to the immediate
if{}
statement block.
注:This behavior changes when using the let declaration (introduced in ECMAScript 2015).
if (true) {let y = 5;}
console.log(y); // ReferenceError: y is not defined
4.5. Variable hoisting
Variable hoisting involves pre-compilation(预编译),you can refer to a variable declared later, without getting an exception.
Because of hoisting, all var statements in a function should be placed as near to the top of the function as possible. This best practice increases the clarity of the code(代码清晰度).
In ECMAScript 2015, let and const are hoisted but not initialized. Referencing the variable in the block before the variable declaration results in a ReferenceError, because the variable is in a “temporal dead zone” from the start of the block until the declaration is processed.
4.6. Function hoisting
In the case of functions, only function declarations are hoisted—but not the function expressions.
(只有函数申明会被晋升,函数表达式不会被晋升)
var b = function () {} // 函数表达式
function myFun() {} // 函数申明
在 Javscript 中,解析器在向执行环境中加载数据时,对函数申明和函数表达式并非是厚此薄彼的,解析器会率先读取函数申明,并使其在执行任何代码之前可用(能够拜访——预编译)。
至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。
4.7. Global variables
对于 GO 和 window 的关系在上一篇文章中提过:window 对象
Global variables are in fact properties of the global object.
In web pages, the global object is window, so you can set and access global variables using the window.variable
syntax.
因而,你能够通过指定 window 或 frame 的名字,在以后 window 或 frame 拜访另一个 window 或 frame 中申明的变量。例如,在文档里申明一个叫 phoneNumber 的变量,那么你就能够在子框架里应用 parent.phoneNumber 的形式来援用它。
这里所说的子框架指的是 iframe
HTML 内联框架元素 (
<iframe>
) 示意嵌套的 browsing context。它可能将另一个 HTML 页面嵌入到以后页面中。每个嵌入的浏览上下文(embedded browsing context)都有本人的会话历史记录 (session history) 和 DOM 树。蕴含嵌入内容的浏览上下文称为父级浏览上下文。顶级浏览上下文(没有父级)通常是由 Window 对象示意的浏览器窗口。
4.8. Constants
You can create a read-only, named constant with the const keyword.
A constant cannot change value through assignment(调配)or be re-declared while the script is running. It must be initialized to a value.
尝试更改常量的值将会导致:Uncaught TypeError: Assignment to constant variable.
在同一个范畴内也不能申明常量和函数同名。
However, the properties of objects assigned to constants are not protected, so the following statement is executed without problems.
(调配给常量的对象的属性不受爱护,因而能够从新赋值),同样的如果调配给常量的是一个数组,数组中的值也不受爱护,也能够像对象的属性一样批改。
const a = {tt: "Tian"};
a = 2;
//Uncaught TypeError: Assignment to constant variable.
a.tt = 23 //23
// 数组同理
4.9. Data structures and types
-
Seven data types that are primitives(原始):
Boolean
. true and false.null
. A special keyword denoting a null value. (Because JavaScript is case-sensitive,null is not the same as Null, NULL, or any other variant.)undefined
. A top-level property whose value is not defined.Number
. An integer or floating point number. For example: 42 or 3.14159.BigInt
. An integer with arbitrary(任意)precision(精度). For example:9007199254740992n
.String
. A sequence of characters that represent a text value. For example: “Howdy”Symbol
(new in ECMAScript 2015). A data type whose instances are unique and immutable(不可变).
- and
Object
4.10. Data type conversion
JavaScript is a dynamically(动静地)typed language, 所以你申明变量是不用指明数据类型,并且数据类型还能够主动地转换。
4.11. Numbers and the ‘+’ operator
用 +
算子连贯数字和字符串,数字将会变成字符。但有些时候 JS 不会将数字转换成字符。比方'3' - 2 //1
可应用 parseInt()
、parseFloat()
将用字符串存储的数字转换为数字。
另一种另类的解决办法是应用 +
(一元运算符) 从字符串中提取数字
'1.1' + '1.1' // '1.11.1'
(+'1.1') + (+'1.1') // 2.2
// Note: the parentheses(括号) are added for clarity(清晰度), not required.
5. Literals
Literals 应该翻译成什么?字面量?字符?文字?我了解成能间接看进去是什么类型的数据“的”这种申明的模式。
它代表了 JS 中的值,是在脚本中本人提供的固定的值,而不是变量。翻译总有偏差,所以它只叫 Literals。
5.1. Array literals
是 0 个或者多个表达式组成的列表,每个表达式代表一个数组元素,括在方括号中([]
),你能够用 Array literals 创立一个数组,它的元素被初始化成指定值。
Note : An array literal is a type of object initializer
5.2. Boolean literals
The Boolean type has two literal values: true and false.
var bool = new Boolean()
// bool = Boolean {false}
typeof bool // "object"
bool == false // true
bool === false //false
5.3. Floating-point literals
3.1415926
-.123456789
-3.1E+12
.1e-23
5.4. Numeric literals
Number and BigInt types can be expressed in decimal (十进制), hexadecimal (16 进制), octal (8 进制) and binary (2 进制).
5.5. Object literals
An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}
).
5.6. RegExp literals
A regex literal is a pattern enclosed between slashes. The following is an example of a regex literal.
var re = /ab+c/;
5.7. String literals
A string literal is zero or more characters enclosed in double (“) or single (‘) quotation marks.
You can call any of the String object’s methods on a string literal value. JavaScript automatically converts the string literal to a temporary(长期)String object, then discards the temporary String object.
5.8. 解构赋值
参考:https://zh.javascript.info/de…
5.9. 数组解构
解构赋值是一种非凡且简洁的语法,让咱们能够拆分简单数据类型中的须要的内容到一系列变量中。解构操作对那些具备很多参数和默认值等的函数也很见效。
let arr = ["Ilya", "Kantor"]
// 解构赋值
let [firstName, surname] = arr;
console.log(firstName); // Ilya
console.log(surname); // Kantor
// 联合 split
let [firstName1, surname1] = "Ilya Kantor".split(' ');
console.log(firstName1); // Ilya
console.log(surname1); // Kantor
- 解构并没有毁坏原有的数组。
- 对于数组中不想要的元素能够通过多加逗号滤除,
// 不须要第二个元素
let [firstName, , title] = ["Julius", "Caesar", "Consul", "Republic"];
alert(title); // Consuls
- 等号右侧能够是任何可迭代对象
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
- 赋值给等号左侧的任何内容
let user = {};
[user.name, user.surname] = "Ilya Kantor".split(' ');
alert(user.name); // Ilya
- 与 .entries() 办法进行循环操作
这写法十分简洁。
let user = {
name: "John",
age: 30
};
// 循环遍历键—值对
for (let [key, value] of Object.entries(user)) {alert(`${key}:${value}`); // name:John, then age:30
}
与 map 联合
let user = new Map();
user.set("name", "John");
user.set("age", "30");
for (let [key, value] of user) {alert(`${key}:${value}`); // name:John, then age:30
}
- 替换变量技巧
let guest = "Jane";
let admin = "Pete";
let marry = "HuiD";
[guest, marry, admin] = [admin, guest, marry];
console.log(guest, admin, marry); // Pete HuiD Jane
- 残余的‘…’
let arr = ["Jane", "HuiD", "Pete", "Caoke"];
let [one, ...two] = ["Jane", "HuiD", "Pete", "Caoke"];
console.log(one); //Jane
console.log(two); //["HuiD", "Pete", "Caoke"]
- 默认值
如果赋值语句中,变量的数量多于数组中理论元素的数量,赋值不会报错。未赋值的变量被认为是 undefined
let [firstName, surname] = [];
console.log(firstName); // undefined
console.log(surname); // undefined
// 默认值
let [name = "Guest", surname1 = "Anonymous"] = ["Julius"];
console.log(name); // Julius(来自数组的值)console.log(surname1); // Anonymous(默认值被应用了)
默认值能够是更加简单的表达式甚至能够是函数调用,这些表达式或函数只会在这个变量未被赋值的时候才会被计算。
// 只会提醒输出姓氏
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; //Juliu 对应到 name
console.log(name); // Julius(来自数组)console.log(surname); // 你输出的值
5.10. 对象解构
对象构造和数组构造的区别在于哪里?
let options = {
title: "Menu",
width: 100,
height: 200
};
// 留神这里变量名和对象中的键雷同,等号左侧蕴含了对象相应属性的一个“模式(pattern)”,变量的程序并不重要。let {
title,
width,
height
} = options;
console.log(title); // Menu
console.log(width); // 100
console.log(height); // 200
如果咱们想把一个属性赋值给另一个名字的变量,比方把 options.width 属性赋值给变量 w,那么咱们能够应用冒号来指定:
let options = {
title: "Menu",
width: 100,
height: 200
};
// {sourceProperty: targetVariable}
let {
width: w,
height: h,
title
} = options;
// width -> w
// height -> h
// title -> title
console.log(title); // Menu
console.log(w); // 100
console.log(h); // 200
对于可能缺失的属性,咱们能够应用 “=” 设置默认值。就像数组或函数参数一样,默认值能够是任意表达式甚至能够是函数调用。它们只会在未提供对应的值时才会被计算 / 调用。
咱们还能够将冒号和等号联合起来:
let options = {title: "Menu"};
let {
width: w = 100,
height: h = 200,
title = "Defult"
} = options;
console.log(title); // Menu
console.log(w); // 100
console.log(h); // 200
同数组解构相似,咱们能够只取其中的某一些属性,而后把“残余的”赋值到其余中央。
咱们能够应用残余模式(pattern),就像咱们对数组那样。一些较旧的浏览器不反对此性能(例如,应用 Babel 对其进行填充),但能够在古代浏览器中应用。
let obj = {
name: "Hui",
age: 22,
heigh: 168
};
let {
name,
...per
} = obj;
console.log(name); //Hui
console.log(per); //{age: 22, heigh: 168}
留神:JavaScript 把主代码流的 {…} 当作一个代码块,所以
let title, width, height;
// 这一行产生了谬误,js 会把 {} 当作代码块,但实际上它是对象解构
{title, width, height} = {title: "Menu", width: 200, height: 100};
// 通过把整个赋值表达式用括号 (...) 包起来解决
({title, width, height} = {title: "Menu", width: 200, height: 100});
5.11. 嵌套解构
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true
};
// 为了清晰起见,解构赋值语句被写成多行的模式
let {
size: { // 把 size 赋值到这里
width,
height
},
items: [item1, item2], // 把 items 赋值到这里
title = "Menu" // 在对象中不存在(应用默认值)} = options;
console.log(title); // Menu
console.log(width); // 100
console.log(height); // 200
console.log(item1); // Cake
console.log(item2); // Donut
let arr = [{
name: "Hui",
age: 22,
info: [178, 18]
}, "DT", ["Jane", "Pete"]];
let [{
name,
age,
info: [heigh, length]
}, str, [J, P]] = arr;
console.log(name); //Hui
console.log(age); //22
console.log(heigh); //178
console.log(length); //18
console.log(str); //DT
console.log(J); //Jane
console.log(P); //Pete
5.12. 智能函数参数
参考:https://zh.javascript.info/de…
次要针对函数传参进行代码清洁
我本人写解构时呈现的几次谬误都是因为搞混了数组与对象应用的括号,还有冒号、等号以及对象属性须要同名等,就这几点须要记住。
6. JSON
-
JSON 和语言无关,是纯数据的标准,因而一些 JavaScript 特定的属性会被 JSON.stringify 跳过,比方:
- 函数属性(办法)。
- Symbol 类型的属性。
- 存储 undefined 的属性。
这在借助 JSON 做 deepClone 的时候须要留神。
let obj = {
name: "DT",
age: 23,
[Symbol.toPrimitive](hint) {alert(`hint: ${hint}`);
return hint == "string" ? `{name: "${this.name}"}` : this.age;
},
wife: undefined,
say: function () {console.log("Hui");
},
}
console.log((JSON.stringify(obj))); //{"name":"DT","age":23}
参考:Symbol.toPrimitive
- 反对嵌套解构
重要的限度:不得有循环援用。
let meetup = {
title: "Conference",
room: {
number: 23,
participants: ["john", "ann"]
}
};
console.log(JSON.stringify(meetup));
/* 整个解构都被字符串化了
{
"title": "Conference",
"room": {
"number": 23,
"participants": ["john", "ann"]
}
}
*/
let room = {number: 23};
meetup.place = room; // meetup 援用了 room
room.occupiedBy = meetup; // room 援用了 meetup
// 在这里,转换失败了,因为循环援用:room.occupiedBy 援用了 meetup,meetup.place 援用了 room
console.log(JSON.stringify(meetup));; // Uncaught TypeError: Converting circular structure to JSON