《JavaScript高级程序设计》Chapter03 JavaScript语言基础
Syntax
类C
区分大小写,标识符可以字母、下划线
_
、美元符号$
开头语句以分号
;
结尾:虽然不加分号也是被允许的,但会导致性能的降低,也易出现问题严格模式(strict mode):对一些不规范写法进行处理,对不安全活动将抛出错误。
- 在脚本开头或函数体开头加上:
"use strict";
function do (){
"use strict";
// 函数体
}
- 在脚本开头或函数体开头加上:
Variable
var
var定义的变量会成为包含它的函数的局部变量,函数退出时即被销毁,即声明的范围为函数作用域
- 可以通过省略var来定义一个全局变量,但这样做是不被推荐的;严格模式下,这样做会抛出ReferenceError异常
var的声明提升(hoist):使用var关键字声明的变量会自动提升到函数作用域的顶部【将所有变量声明拉到函数作用域顶部】
// 以下二者是等价的,均不会报错,输出undefined
function foo() {
console.log(age); // undefined
var age = 20;
} function foo(){
var age;
console.log(age); // undefined
age = 20;
}
使用var反复多次声明同一个变量是被允许的
function foo(){
var age = 12;
var age = 15;
var age = 18;
var age = 21;
console.log(age); // 21
}
let
let与var作用类似,不同的是let声明的范围为块作用域
- 块作用域是函数作用域的子集,因此适用于var的作用域限制同样适用于let
if(true){
var name = "Leo";
console.log(name); // Leo
}
console.log(name); // Leo
-------------------------------
if(true){
let name = "Leo";
console.log(name); // Leo
}
console.log(name); // ReferenceError: name is not defined
在同一个块作用域中,let不允许进行冗余声明是(SyntaxError)
- 声明冗余报错不会因混用let和var受到影响:这两个关键字声明的不是不同类型的变量,只是指出变量在相关作用域如何存在
var num = 1;
console.log(num); // 1
{
let num = 2;
console.log(num); // 2
} let num = 1;
console.log(num);
{
var num = 2; // SyntaxError: Identifier 'num' has already been declared
console.log(num);
}
暂时性死区:let声明的变量不会在作用域中被提升(hoist),必须先声明后引用
- let声明之前的执行瞬间称为“暂时性死区”,此阶段引用任何后面才声明的变量都会抛出ReferenceError
全局声明:let在全局作用域中声明的变量不会成为window对象的属性,而var声明的变量会
for循环中的let声明:
用var定义迭代变量会渗透到循环体外部,let定义迭代变量的作用域仅局限于for循环块内部
for(var i=0; i<5; i++){
// 循环逻辑
}
console.log(i); // 5
--------------------------
for(let i=0; i<5; i++){
// 循环逻辑
}
console.log(i); // ReferenceError: i is not defined
使用let声明迭代变量,JavaScript引擎在后台为每个迭代循环都声明一个新的迭代变量。
for(var i=0;i<5;i++){
setTimeout(()=>console.log(i),0); // 5 5 5 5 5
}
---------------------------------------
for(let i=0;i<5;i++){
setTimeout(()=>console.log(i),0); // 0 1 2 3 4
}
const
与let行为基本相同
不允许重复声明,块声明作用域
区别:声明的同时必须初始化,切不可修改const声明的变量的值(TypeError)
- 此限制只适用于其指向的变量的引用(const变量引用的为一个对象时,修改const对象内部属性是被允许的)
- 不能用const声明迭代变量
Data Type
Undefined
使用var或let声明变量但未初始化时,变量会被赋予初始值undefined
具有值undefined的变量与未定义的变量是有区别的
赋值为undefined的变量是存在的,只是值为undefined;未定义的变量不存在,但对其typeof仍会返回undefined。二者是存在根本差别的
let message;
// let age; //确保未被声明过
console.log(message); // undefined
console.log(age); // ReferenceError: age is not defined
console.log(typeof message); // undefined
console.log(typeof age); // undefined
undefined是假值
Null
null表示一个空对象指针,typeof null会返回object
undefined由null派生而来,ECMA-262将他们定义为表面上相等
- undefined永远不必显示设置;但当变量需要保存一个对象且此时没有对象可以保存,就应当以null对变量进行填充,保持null的空对象指针语义,从而与undefined区别开来
null是假值
Boolean
转型函数:Boolean(param);
数据类型 转为true 转为false Boolean true false String 非空字符串 空字符串 Number 非零数值 0,NaN Object 任意对象 null Undefined \ undefined
Number
八进制字面量:以0o开头,后续数字均为0~7
- 后续数字一旦有超过0~7的范围,数字序列就被当做十进制解释
- 严格模式下,八进制字面量是无效的
十六进制字面量:以0x开头,后续数字为0~9和 a~f, 分别代表0~15
- a~f大小写均是被允许的
浮点值
ECMAScript会想方设法将值转换为整数值:小数点后面没有数字或只有0时,会被转换为整数进行处理
浮点值精度可达17位小数,但算数计算并不精准(IEEE 754数值造成的错误)
console.log( 0.1+0.2 == 0.3 ); // false 0.1+0.2得到结果为0.30000000000000004,出现舍入错误
数值的范围
- Number.MIN_VALUE(5e-324) ~ Number.MAX_VALUE(1.797693134862315e+308)
- 任何超出可表示范围的正负数会被表示为 ±Infinity
- 可以用函数 isFinite(param) 判断一个数是否在可表示范围内
NaN (Not a Number):表示本来要返回数值的操作失败了
任何涉及NaN的操作均返回NaN,NaN不等于包括NaN在内的任何值
利用 isNaN(param) 函数可以判断一个数是否“不是数值”:此函数会先将不是数值的值尝试转换成数值,任何不能转换为数值的值都会使这个函数返回true
console.log(isNaN(NaN)) // true
console.log(isNaN(10)) // false
console.log(isNaN("10")) // false 可转为数值10
console.log(isNaN("blue")) // true 不可转为数值
console.log(isNaN(true)) // false 可转为数值1
数值转换函数
Number(param):param可为任意数据类型
数据类型 转换规则 Boolean true转为1,false转为0 Number 直接返回 Null 0 Undefined NaN String 只包含数值字符,会被直接转换为数值(包括数字、正负号、小数点)
空字符串会转换为0
包含有效的十六进制格式(0x),会被由十六进制串转换为相对应的十进制数值Object 调用对象的valueOf( )方法,再按照上述规则转换返回值;若转换结果为NaN,则调用toString( )方法,按照转换字符串的规则转换 parseInt(param1,param2):param1为字符串,param2为进制
- 直接忽略最前面的空格,从第一个非空格字符串开始转换
- 第一个非空格字符不是数值字符、正负号,会立即返回NaN(意味着空字符串会返回NaN)
- 转换直到字符串尾或最后一个非数值字符
console.log(parseInt("1234hello")); // 1234 hello被忽略
console.log(parseInt("12.34")) // 12 .不是有效的整数字符
console.log(parseInt("")); // NaN
console.log(parseInt("0xaf")); // 175 被解释为十六进制
console.log(parseInt("af",16)); // 175 被解释为十六进制
parseFloat(param):与parseInt原理类似
console.log(parseFloat("1234hello")); // 1234 hello被忽略
console.log(parseFloat("12.34.56")); // 12.34
console.log(parseFloat("0123.45")); // 123.45
console.log(parseFloat("3.125e7")); // 31250000
String
表示零或多个16位Unicode字符序列,通过字符串的length属性可以获取其长度
ECMAScript中的字符串时不可变的,一旦修改某个变量中的字符串值,必须先销毁原字符串再将新的值存入该变量中
向字符串转换
几乎所有值都有方法 toString( ),返回当前值的字符串等价物
Number,Boolean,Object,String均有toString( )方法,null与undefined没有toString( )方法
对Number调用toString( )方法时,可以传一个底数参数,表示以什么底数输出数值的字符串表示
String(param)转型函数
- param存在toString()方法则直接调用
- 值为null则返回"null",值为undefined则返回"undefined"
模板字面量:使用反引号,会保留字面量内的换行字符,以跨行定义字符串
字符串插值:模板字面量常用以支持字符串插值,即在一个连续定义中插入一个或多个值
字符串插值通过在
${...}
中使用一个JavaScript表达式实现,插入的值会使用toString()强制转为字符串let value = 19;
let str = `<div>
<a href="#">
<span>Leo is ${value} years old</span>
</a>
</div>`;
console.log(str);
标签函数:自定义插值行为,前缀到模板字面量来应用自定义行为
- 第一个参数接收原始字符串被插值分割后形成的数组
- 由于插值表达式数量可变,应使用剩余操作符
...
将它们收集到一个数组中
let value = 19;
let exp = 'second';
function tagFunc(strings, ...exp){
console.log(strings);
console.log(exp);
}
tagFunc`${value} to the ${exp} power is ${value*value}`;
// [ '', ' to the ', ' power is ', '' ]
// [ 19, 'second', 361 ]
Symbol
ECMAScript6新增数据类型,确保对象属性使用唯一标识符,不会发生属性冲突的危险
Symbol(string):string为对符号的描述参数,与此符号的定义与标识完全无关
不能与new关键字一起作为构造函数使用,用以避免创建符号包装对象
let sym1 = Symbol('foo');
let sym2 = Symbol('foo');
console.log(sym1 == sym2); // false
全局符号注册表:运行时不同部分需要共享和重用符号实例时,以一个字符串作为键在全局符号注册表创建并重用符号
Symbol.for(string):使用某字符串调用时,检查全局运行时注册表,不存在相应符号则会创建一个新的符号实例,已存在则直接重用
即使采用相同的符号描述,全局注册表中定义的符号与Symbol()定义的符号也不等同
可以用Symbol.keyFor(param)查询全局注册表,param为符号实例,返回对应的描述字符串
let sym1 = Symbol.for('foo'); // 创建一个新的符号实例
let sym2 = Symbol.for('foo'); // 重用已有符号实例
console.log(sym1 === sym2); // true let sym3 = Symbol('foo');
console.log(sym1 === sym3); // false console.log(Symbol.keyFor(sym1)); // foo
console.log(Symbol.keyFor(sym3)); // undefined
符号添加为对象属性
let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux');
let obj = { [s1]:'foo val' }; // o[s1] = 'foo val';
Object.defineProperty(obj, s2,{ value: 'bar val', enumerable: true});
Object.defineProperties(obj, {
[s3] : {value:'baz val', enumerable: true},
[s4] : {value:'qux val', enumerable: true},
});
console.log(obj);
//{
// [Symbol(foo)]: 'foo val',
// [Symbol(bar)]: 'bar val',
// [Symbol(baz)]: 'baz val',
// [Symbol(qux)]: 'qux val'
//}
获取对象的符号属性
let s1 = Symbol('foo'),
s2 = Symbol('bar');
let obj = {
[s1]: 'foo val',
[s2]: 'bar val',
baz: 'baz val',
qux: 'qux val'
};
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(foo), Symbol(bar) ]
console.log(Object.getOwnPropertyNames(obj)); // [ 'baz', 'qux' ]
console.log(Object.getOwnPropertyDescriptors(obj));
//{
// baz: { value: 'baz val', writable: true, enumerable: true, configurable: true },
// qux: { value: 'qux val', writable: true, enumerable: true, configurable: true },
// [Symbol(foo)]: { value: 'foo val', writable: true, enumerable: true, configurable: true },
// [Symbol(bar)]: { value: 'bar val', writable: true, enumerable: true, configurable: true }
//}
console.log(Reflect.ownKeys(obj)); // [ 'baz', 'qux', Symbol(foo), Symbol(bar) ]
To be continued ......
Object
ECMAScript中的Object是所有对象的基类,任何对象都有这些属性与方法。每个Object实例都有如下属性与方法:
- constructor:创建当前对象的函数
- hasOwnProperty(propertyName):判断当前对象是否含有给定属性(String)
- propertyIsEnumerable(propertyName):判断当前属性是否可用for-in语句枚举
- toString():返回对象的字符串表示
- ......
Operator
一元操作符
递增/递减:
++
/--
前缀时,先改变变量的值再对表达式求值;后缀时,先对表达式求值再改变变量的值
不限于整数,也可作用于以下类型的值
数值类型 规则 String 对有效数值形式则转为数值在改变,变量类型变为Number
对非有效数值形式,变量值变为NaN,变量类型变为NumberBoolean 将false转为0,将true转为1,再进行递增递减操作,变量类型变为Number float 直接+1或-1(注意:浮点数的加减可能不精确,出现舍入错误) Object 先调用对象的valueOf()方法,取到的值可操作则直接应用上述规则
如果为NaN,则调用toString()并再次应用其他规则
变量类型从Object变为Number
一元加减:
+
/-
- 主要用于基本的算数操作,但也可以用于数据类型转换
- 对于数值,+/- 仅做正负的改变;对于非数值,会执行与Number()函数相同的改变,再根据 +/- 改变正负
位操作符
- 按位 与
&
或|
非~
异或^
- 左移
<<
:按指定位数将数字的所有位左移(右侧补0,左侧符号位保留) - 右移
- 有符号右移
>>
:将所有的32位右移指定位,符号位保留(空位以符号位补充) - 无符号右移
>>>
:将所有的32位右移指定位,空位以0补充(对于正数无差别,对于负数有很大差异)
- 有符号右移
布尔操作符
逻辑非
!
:现将操作数统一转为Boolean,再取反- 可以用于将任意值转为Boolean型,与Boolean()转型函数等效:!!operand
逻辑与
&&
:短路操作符,当第一个操作数为false时就不会对第二个操作数求值- 可用于任何类型操作数,不一定会返回Boolean值
- 第一个操作数为Object,则返回第二个操作数;第二个操作数为Object,仅当第一个操作数求值为true才返回该Object
- 两个操作数均为Object,则返回第二个操作数
- 有一个操作数为NaN/undefined/null,直接返回NaN/undefined/null
- 可用于任何类型操作数,不一定会返回Boolean值
逻辑或
||
:短路操作符,当第一个操作数为true时就不会对第二个操作数求值可用于任何类型操作数,不一定会返回Boolean值
第一个操作数为Object,则返回第一个操作数;第一个操作数求值为false,则返回第二个操作数
两个操作数均为Object,则返回第一个操作数
两个操作数均为NaN/undefined/null,则返回NaN/undefined/null
可以避免给变量赋值null或undefined
let obj = preferredObj || backupObj;
- preferredObj为首选值,其不为null则会被赋给obj;backupObj为备用值,preferredObj为null时,其就会被赋给obj
乘性操作符
- 乘
*
除/
取模%
- 注意对0,Infinity,NaN的处理
- 运算时,会对非数值的操作数进行类型转换
指数操作符
Math.pow(base,power):用于计算base的power次幂
ECMAScript 7新增指数操作符
**
,与Math.pow函数等效指数操作符同样支持复合赋值操作:
**=
console.log(Math.pow(11,2)); // 121
console.log(11**2); // 121
console.log(121**0.5); // 11
加性操作符
加
+
:计算数值时,需考虑Infinity,NaN,±0的情况对两个字符串操作时,将第二个字符串拼到第一个后面;只有一个为字符串时,将另一个转为字符串后再拼在一起
任一操作数为Object时,会调用对象的valueOf()方法,由返回值参与加法运算;没有valueOf则先调用toString,得到的字符串再转为数值参与计算
let obj1 = {
valueOf : function (){
return -1;
},
}, obj2 = {
valueOf : function (){
return "-2";
}
}, obj3 = {
valueOf : function (){
return -2;
}
};
console.log(obj1 + obj2); // -1-2
console.log(obj1 + obj3); // -3
减
-
:计算数值时,需考虑Infinity,NaN,±0的情况- 对字符串、布尔值、null、undefined,会调用Number()转为数值再计算
- 其他情况规则与加法相同
关系操作符
- 包括:
>
<
>=
<=
- 操作数都是数值,执行数值比较
- 操作数都是字符串,则逐个比较字符串中对应字符的编码
- 有一个操作数是数值,则将另一个操作数转为数值,再做数值比较
- 任一操作数为Object,则调用其valueOf方法,对结果进行比较;若没有valueOf方法,则调用toString方法,对结果进行比较
- 对布尔值,将其转为数值再比较
- 涉及NaN的所有比较都会返回false
相等操作符
等于
==
和不等于!=
:对比较的两操作数先进行强制类型转换,再比较是否相等- 任一操作数为Boolean,将其转为数值再比较是否相等
- String与Number比较,尝试将String转为Number,再比较是否相等
- Object和非Object比较,调用对象的valueOf方法获取其原始值,再比较是否相等
- null == undefined,且它们不能转换为其他类型的值进行比较
- 只要涉及NaN,立即返回false(NaN == NaN也返回false)
- 两个Object比较,仅当两操作数指向同一对象时返回true
全等
===
和不全等!==
:比较时不作任何强制类型转换- null === undefined 返回false,因为他们是不同类型的值
条件操作符
- variable = boolean_expression ? true_value : false_value ;
逗号操作符
用于在一条语句中执行多个操作
let num1 = 1, num2 = 2, num3 = 3;
赋值时用逗号操作符分隔值,最终会返回表达式中最后一个值
let num = (5,4,3,2,1,0); // num = 0
Statement
for-in
用于枚举对象中的非符号键属性
若迭代的变量是null或undefined,则不执行循环体
for (const propName in window){
console.log(propName);
}
for-of
用于遍历可迭代对象的元素
会按照可迭代对象的next( )方法产生值的顺序迭代元素
尝试迭代的变量不支持迭代时,语句会抛出错误
let arr = [1,2,3,4];
for (const num of arr){
console.log(num);
}
break,continue,label
break语句用于立即退出当前循环,强制执行当前循环后的下一条语句
continue语句也立即退出当前循环,但会再次从循环顶部开始执行
label语句用于给语句加标签,可以通过break和continue语句引用(常用于嵌套循环):强制执行或强制退出标签所在循环
let num = 0;
outermost: for (let i=0; i<10; i++){
for (let j=0; j<10; j++){
if (i===5 && j===5){
break outermost;
}
num ++;
}
}
console.log(num); // 55
-------------------------------------
let num = 0;
outermost: for (let i=0; i<10; i++){
for (let j=0; j<10; j++){
if (i===5 && j===5){
continue outermost;
}
num ++;
}
}
console.log(num); // 95
with
用于将代码作用域设置为特定的对象,主要用于针对同一对象的反复操作
严格模式下,不允许with语句的使用
let obj = {
value : 114514,
str : 'fuck',
name : 'obj'
}; with (obj) {
console.log(value);
console.log(str);
console.log(name);
}
//114514
//fuck
//obj
switch
在每个case条件分支后,最好都加上break语句,否则代码会在匹配完当前条件后继续匹配下一条件
switch-case语句可以应用所有数据类型,条件的值也可以是变量或表达式
let str = 'hello world';
switch (str) {
case 'hello'+' world':
console.log('Greeting was found!'); //
break;
case 'goodbye':
console.log('Closing was found');
break;
default:
console.log('Unexpected message was found');
}
在比较每个条件分支的值时使用'===',不会强制转换数据类型
《JavaScript高级程序设计》Chapter03 JavaScript语言基础的更多相关文章
- 读书时间《JavaScript高级程序设计》一:基础篇
第一次看了<JavaScript高级程序设计>第二版,那时见到手上的书,第一感觉真是好厚的一本书啊.现在再次回顾一下,看的是<JavaScript高级程序设计>第三版,并记录一 ...
- 《JAVASCRIPT高级程序设计》表单基础知识和文本框脚本
在HTML中,表单是由<form>元素来表示,在javascript中,表单对应的是HTMLFormElement类型,它具有一些独有的属性和方法: 一.表单基础知识 1.取得表单的方式 ...
- JavaScript高级程序设计之表单基础
A FORM <form id='form' action='http://a-response-url' method="post"> <!--maxlengt ...
- [笔记]《JavaScript高级程序设计》- JavaScript简介
JavaScript实现 虽然JavaScript和ECMAScript通常都被人们用来表达相同的含义,但JavaScript的含义却比ECMA-262中规定的要多得多.一个完整的JavaScript ...
- 读书笔记(06) - 语法基础 - JavaScript高级程序设计
写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...
- 《JavaScript高级程序设计》读书笔记--前言
起因 web编程过程使用javascript时感觉很吃力,效率很低.根本原因在于对javascript整个知识体系不熟,看来需要找些书脑补一下,同时欢迎众网友监督. 大神推荐书籍 看了博客大神们推荐的 ...
- 《JavaScript高级程序设计》学习笔记(5)——面向对象编程
欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第六章内容. 1.面向对象(Object ...
- 《JavaScript高级程序设计》学习笔记(4)——引用类型
欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第五章内容. 在ECMAScript中, ...
- 《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题
欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第四章内容. 1.函数:通过函数可以封装 ...
- 《JavaScript高级程序设计》学习笔记
系统学习JS, 从<JavaScript高级程序设计>入门,通过学习jQuery或者angularJS源码来进阶. 第1章 JavaScript简介 1.JS问世的目的是处理以前由服务器端 ...
随机推荐
- lua-table类的继承
--男人类man = {name = "man",age=123}--继承空间man.__index=man--儿童类child= {}--继承setmetatable(child ...
- tensorboard 2.0可视化 —浏览器中输入http://ip:6006 - 无法访问此网站——有效解决
https://blog.csdn.net/sinat_28442665/article/details/108975276
- 百度云+Zotero进行知识管理的方法
首先,要在zotero的首选项的文件与文件夹里去自定义你的zotero文件夹,这个文件夹就是你的zotero软件的文档存储编辑的文件夹,本来默认是在电脑用户里自动创建的,比如hp/user/zoter ...
- Idea下载指南之几个选项
通常我们在下载idea等一些图形编译器时,都会有很多选项供您选择,下面我们来看下这几个英文选项吧. create desktop Shortcut Update Path variable(resta ...
- 更改材质uv
- nginx+vite 项目打包及部署
项目打包及部署到服务器二级路由 例如:我希望将打包的项目部署到 http://localhost:8088/web/ 上 一. 项目配置及打包 项目部署到服务器二级路由需要配置基础路径base,即需要 ...
- 计数 dp 部分例题(六~十部分)
六.转化求和顺序(線形和への分解) 例题1 题意 有一个长为 \(n\) 的数组 \(a\).求在 \(a\) 中选择 \(k\) 个数的所有方案中,每次选择的所有数的中位数的和.\(n\le 10^ ...
- CF446D 题解
题意 传送门 给定一张 \(n\) 个点 \(m\) 条边的无向图,每个节点有权值 \(v_i=\) \(0/1\).角色从节点 \(1\) 开始随机游走,走到 \(n\) 停止.求其经过路径上权值和 ...
- 实践:腾讯云COS备份本地数据以及异地备份
在当前大数据时代背景下,数据在业务中占有不可低估的地位,数据备份已然成为了最后一道屏障. 腾讯云对象存储COS,提供数据备份.共享.大数据处理.线上数据托管一站式解决方案,成为了不少企业和个人用户备份 ...
- fabric2.2学习笔记1
fabric2.2学习笔记1 20201303张奕博 2023年1月9日 hyperledger fabric 结构分析 每个Server作用: AdminServer:控制该节点的命运,可以删除该节 ...