前言
此文为个人学习笔记记录,旨在为自己加深印象。内容仅供参考。一些个人认为现阶段没必要深入的知识点不在此文当中。有问题请各位多提意见。持续更新~
编辑器:vscode
一、什么是javaScript
javaScript是基于 对象 的,由 事件驱动 的 解释性 脚本语言
1、对象 :javaScript 也是一门面向对象的编程语言。window对象 - BOM\ location 对象 - 地址栏对象 dom 管理
2、事件驱动:解决浏览器和用户之间交互问题。用户操作,浏览器页面反馈,由事件驱动来完成。
3、解释型:解释性语言的程序不需要编译,在运行程序的时候才翻译,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就需要逐行翻译一次,效率比较低。
作用
客户端云计算 / 客户端表单合法验证 / 浏览器对象调用 / 事件触发 / 网页特殊效果 …等
1、嵌入动态文本与HTML页面
2、对浏览器时间做出相应
3、读写HTML元素
4、在数据被提交到服务器之前验证数据
5、检测访客的浏览器信息
6、控制cookies,包括创建和修改等。
7、基于node.js技术进行服务器端编程。
组成
ECMAscript 核心:
与javascript 关系:ECMA 是 javascript 的规格、javascript 是ECMAscript 的一种实现
它定义了❑ 语法❑ 类型❑ 语句❑ 关键字❑ 保留字❑ 操作符❑ 全局对象 等等
Web浏览器只是ECMAScript实现可能存在的一种宿主环境(host environment)
其他宿主环境还有服务器端JavaScript平台Node.js
dom 文档对象模型 :文档对象模型(DOM, Document Object Model)是一个应用编程接口(API)、DOM将整个页面抽象为一组分层节点,生成Dom数,每个节点都包含不同的数据
bom 浏览器对象模型 :提供独立于内容,可以与浏览器窗口进行互动的对象结构。国通BOM可以操作浏览器窗口;描述了与浏览器进行交互的方法和接口
引用方式
这里主要说两种方式:
1、内嵌
推荐写在body 里最后面。因为遇到阻塞情况下。遇到script标签内容,执行完之后,再执行代码可以有多个script标签,依次执行。
2、外部脚本
引入外部脚本益处:
1、可维护性:一个目录保存所有JavaScript文件,则更容易维护
2、缓存:浏览器会根据特定的设置缓存所有外部链接的JavaScript文件,这意味着如果两个页面都用到同一个文件,则该文件只需下载一次,这意味着页面加载更快
script元素
它下列8个属性
1、async:可选。表示应该立即开始下载脚本,但不能阻止其他页面动作
2、charset:可选。使用src属性指定的代码字符集。
3、crossorigin:可选。配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS
crossorigin=“anonymous” 不设置
crossorigin=“use-credentials” 设置
4、defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。
5、 src:可选。表示包含要执行的代码的外部文件。
6、type:可选。表示代码块中脚本语言的内容类型(也称MIME类型 7、
integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI, Subresource Integrity)
defer 属性 推迟执行脚本
表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。
即这段 JavaScript 加载时 HTML 并 未停止解析,这两个过程是并行的。
<script defer src="xxx.js"></script>
async 异步执行脚本
从改变脚本处理方式上看,async属性与defer类似。当然,它们两者也都只适用于外部脚本,与defer不同的是,标记为async的脚本并不保证能按照它们出现的次序执行。
给脚本添加async属性的目的是告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本。正因为如此,异步脚本不应该在加载期间修改DOM。
<script async src="xxx.js"></script>
动态加载脚本
所以通过向DOM中动态添加script元素同样可以加载指定的脚本。只要创建一个script元素并将其添加到DOM即可。
let script = document.createElement('script')
script.src ='xxxxx.js'
// 并不是所有浏览器都支持async属性,所以统一设置为同步加载
script.async = false
document.head.appendChild(script)
// 这种方式浏览器加载器不可见,影响获取优先级。可能会影响性能。可以在头部显示声明它们
<link rel="preload" href="xxxxx.js">
noscript 元素
针对早期浏览器不支持JavaScript的问题,需要一个页面优雅降级的处理方案。最终,元素出现,被用于给不支持JavaScript的浏览器提供替代内容
由于基本没有不支持的了,这里就不多赘述。
二、语言基础
1、语法特点
1、区分大小写 一切都区分大小写,包括变量。函数名,操作符等等,比如time和Time 是两个变量
2、ECMAScript中的语句以分号结尾。省略分号意味着由解析器确定语句在哪里结尾;
2、注释:
单行: 两个斜杠 //
多行: /* 注释 */
单行
// var a =10
多行
/* function person(a,b) {
return a+b
}
*/
3、标识符
所谓标识符,就是变量、函数、属性或函数参数的名称。标识符可以由一或多个下列字符组成
第一个字符必须是一个字母、下划线(_)或美元符号($)
剩下的其他字符可以是字母、下划线、美元符号或数字
标识符不能是关键字或保留字
4、关键字保留字
关键字:指JS本身已经使用了的字符,不能再充当变量名,方法名;
包括:break.case,catch,continue,default,delete,do,else,for,if,in.new.,return.this.throw,try,var,等
保留字:为预留出来的关键字,未来可能成为关键字,同样不能使用它们充当变量名或方法名
5、严格模式
在脚本开头加上这一行: “ use strict ” ;
它其实是一个预处理指令,也可以单独指定一个函数在严格模式下执行,只要把这个预处理指令放到函数体开头即可
function abc() {
"use strict"; // 严格模式
// 逻辑
}
6、语法规范
(1)一个函数作用域中所有的变量声明应该尽量提到函数首部,用一个 var 声明,不允许出 现两个连续的 var声明,声明时如果变量没有值,应该给该变量赋值对应类型的初始值,便于 他人阅读代码时,能够一目了然的知道变量对应的类型值。
(2)代码中出现地址、时间等字符串时需要使用常量代替。
(3)在进行比较的时候吧,尽量使用’=’, '!‘代替’==’,’!=’。
(4)不要在内置对象的原型上添加方法,如 Array, Date。
(5)switch 语句必须带有 default 分支。
(6)for 循环必须使用大括号。
(7)if 语句必须使用大括号。
7、命名规则
变量命名语义化:变量名称一般用名词
遵循驼峰命名法 userName
三、变量、作用域、内存
1、var 关键字
var (variable)js的关键字,用来声明变量意思
声明之后,计算机会自动分配内存空间,不需程序员管,通过变量名访问内存中分配的空间,未初始化时,变量会保存一个特殊值undefined
声明的时候绑定顶层对象,Window
在任意版本ES都可以使用
var abc // 未初始化情况,变量会保存一个特殊值,undefined
var abc = 123 // 声明并赋值。 将 123 赋值给变量 abc
var a = 1 ,b=2 , c=3 // 声明多个。中间用逗号隔开
变量赋值操作会执行两个动作:
1、编译阶段:编译器在当前作用域声明一个变量(未声明情况下)
2、运行阶段:引擎会在该作用域查找这个变量,能找到就会对它赋值
特殊情况
var a=b=c=3 // a=3 , 但是b,c没有声明
var a = 3 , a=13 // 13会覆盖掉3 ,以最后一次赋值为主,a =13
// 不比生命
var sTest = "hello ";
sTest2 = sTest + "world";
alert(sTest2); // 但还是最好声明
1.1var声明作用域
使用var操作符定义的变量会成为包含它的函数的局部变量
使用var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
var get = ‘ 哈哈哈 ’ // get 为全局变量
function options(){}
var a = 12, // 这里的a在函数 options 中为局部变量
b= 100 // 没有var声明的变量,在函数中也是全局变量,这里是变量的作用域提升机制,程序解析器会将当前函数内部的变量直接提升到函数的外部
}
1.2 var声明提升
关键字声明的变量会自动提升到函数作用域顶部:
function foo () {
console.log( a )
var a = 100
}
foo() // UNDEFINED
=>
function foo () {
var a // 拉到函数作用域的顶部
console.log( a )
a = 100
}
1.3命名法则
命名法则: Camel 标记法
首字母是小写的,接下来的字母都以大写字符开头。
`var myTestValue = 0, mySecondValue = "hi";
Pascal 标记法
首字母是大写的,接下来的字母都以大写字符开头。例如:
> var MyTestValue = 0, MySecondValue = "hi"; 1
匈牙利类型标记法
在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串,如下所示“
var iMyTestValue = 0, sMySecondValue = "hi";
1.4作用域链
作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,我们
可以访问到外层环境的变量和函数。变量的查找的方式(遵循就近原则依次向上)先找局部变量的值=>依次往上查找到形式参数=>全局变量上来查找=>如果前面的都没有则当前变量没有定义过需要报错
2、let 关键字(次选)
let关键字是es6新增的。也是用来声明变量。
let 在 var 函数作用域基础上,新增了块级作用域
特征:
变量不能重复声明,会报错
let 声明的变量只在它所在的代码块中生效,很适合嵌套for循环
代码块 : { } 包含的内容就是语句块, 就是函数等东西,带有{}的语句
跟VAR 同样的命名规则
不影响作用域链效果
-----暂时性死区 :
块级作用域中存在let / const 命令。所在变量就会绑定这个区域,不受外界影响
就是先声明,后使用,不存在变量提升
for (let i = 0; i < 3; i*++*) { // 父级作用域
let i = ‘wo’ // 子级作用域
console*.*log(i)
}
设置变量的 i 的部分是一个父级作用域
而循环体内部的 i 是一个单独的子作用域
2.1 let 声明
使用let在全局作用域中声明的变量不会成为window对象的属性
let age =18
console.log(window.age) // undefined
3、 const声明(首先选择)
const的行为与let基本相同,声明的也是块作用域
唯一一个重要的区别是用它声明变量时必须同时初始化变量,
且尝试修改const声明的变量会导致运行时错误。 (不能修改)
但是如果const变量引用的是一个对象,那么修改就不会违反const的限制。
const age =10
age =20 // TypeError: 给常量赋值
const person = {}
person.name = 'Tom' // ok
不能用const来声明迭代变量(因为迭代变量会自增)
如果你只想用const声明一个不会被修改的for循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量。这对for-of和for-in循环特别有意义
let i =0;
for(const j =7 ;i<5;++1){
console.log(j)
}
for。。in / for。。of 循环均可
四、数据类型
ECMAScript有6种简单数据类型(也称为原始类型): Undefined、Null、Boolean、Number、String和Symbol。Symbol(符号)是ECMAScript 6新增的。还有一种复杂数据类型叫Object(对象)。ECMAScript的数据类型很灵活,一种数据类型可以当作多种数据类型来使用。
1.typeof操作符
typeof 操作符用于数据类型的检测
var num = 18;
console.log(typeof num);
返回值
定义未赋值 undefined
布尔 Boolean
字符串 string
数值 number
符号 symbol
函数 funciton
不能区别:
对象 、正则表达式、array, NULL → object
[[class]]属性
所有 typeof 返回值为 “object” 的对象(如数组)都包含一个内部属性 [[Class]]
(我 们可以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,
一般通过 Object.prototype.toString(…) 来查看。
Object.prototype.toString.call( [1,2,3] );
// "[object Array]"
Object.prototype.toString.call( /regex-literal/i );
// "[object RegExp]
2、undefined 类型
Undefined类型只有一个值,就是特殊值undefined,当使用var或let声明了变量但没有初始化时,就相当于给变量赋予了undefined值
let age ;
console.log(age==undefined) // true
一般来说,永远不用显式地给某个变量设置undefined值,字面值undefined主要用于比较;
增加这个特殊值的目的就是为了正式明确空对象指针(null)和未初始化变量的区别。
3、null类型
Null类型同样只有一个值,即特殊值null。null值表示一个空对象指针,这也是给typeof传一个null会返回"object"的原因;
在定义将来要保存对象值的变量时,建议使用null来初始化,
undefined值是由null值派生而来的,因此ECMA-262将它们定义为表面上相等,但是全等是false
let a;
let b = null;
console.log(a == b); // turn
console.log(a === b); // false
4、 Boolean类型类型
Boolean(布尔值)类型是ECMAScript中使用最频繁的类型之一,有两个字面值:true和false。
尔值字面量true和false是区分大小写的
其他ECMAScript类型的值都有相应布尔值的等价形式。要将一个其他类型的值转换为布尔值,可以调用特定的Boolean()转型函数,始终返回一个布尔值
let string = "helloworld"
let boolean = Boolean(string)
console.log(boolean); // true
转换规则
转换为true的值:true、非空字符串、非0数值、任意对象、N/A
转换为false的值:false、“ ”(空字符串)、0,NaN 、null 、undefined
注意:if等流控制语句会自动执行其他类型值到布尔值的转换
5、Number类型
Number类型使用IEEE754格式表示整数和浮点值(在某些语言中也叫双精度值)
分为整数和浮点数
eg:
let num = 20; // 整数
let num1 =20.86; // 小数(浮点数)
因为存储浮点值使用的内存空间是存储整数值的两倍,所以ECMAScript总是想方设法把值转换为整数。在小数点后面没有数字的情况下,数值就会变成整数
let num2 = 30.0 // 小数点后为0,当作整数处理
其他值转换为数值类型:
①parseInt:
可以将其他类型数据转换为数字类型(数字类型的整型)主要是字符串转换,如果数据转换为数字之后,不是正常数字,值也是NaN
无法转换Boolean
无法转换NULL 结果为NAN
无法转换undefined 结果为NAN
parseInt(‘123abc’) ----> 123
// 第二个参数 进制
let num = parseInt("0xAF",16)
②parseFloat:
可以将其他类型数据转换为数字类型(数字类型的浮点型型) 主要是字符串转换
用法:parseFloat(要转换的值)
// 对比
parseInt(‘123.456’) ----> 123
parseFloat(‘123.465’) ----> 123.465
③Number:
Number()是转型函数,可用于任何数据类型。 如果数据转换为数字之后,不是一个正常的数字 “abc” {} ‘123abc’转换之后,值就是NaN(not a number)
console.log(Number({})); // NaN
console.log(Number("")); // 0
console.log(Number(true)); //1
console.log(Number('00001')); // 1
console.log(Number('aa123')); // NaN
console.log(Number('hello world')); // NaN
数值范围:
最大值: console.log(Number.MAX_VALUE);
最小值: console.log(Number.Min_VALUE);
特殊值:
alert(infinity); 无穷大
console.log(Number.MAX_VALUE *2 );
alert(-infinity) ; 无穷小
alert(NaN) ; Not a number 代表一个非数值 类型也是Number
特殊问题总结:
1、 除数不能为零 显示无穷大
2 . 小数相加,结果有偏差
0.1 + 0.2 不等于0.3 js采用规定使用IEEE 754 标准的双精度浮点数,在计算机内部储存就有偏差。不是精确的0.1,代码被编译或解释后,就已经产生舍入错误3.算数运算不能得到正常的数字的都会返回NAN,任意两个NaN 都不相等
6、String 类型
String(字符串)数据类型表示零或多个16位Unicode字符序列。字符串可以使用双引号(")、单引号(’)或反引号(`)标示。前后必须一致。
字符串内互相嵌套。内单外双/内双外单
特点
:ECMAScript中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了,要修改某个变量中的字符串值,必须先销毁原始的字符串
字面量: 字面量创建 var str = " javascript"
构造函数: var str1 = new String(“123”);
转换为字符串类型:
tostring() ---------------- null.undefined 没有这个方法
string() ---------- 始终返回相应类型值的字符串 null返回’NULL’. undefined 返回 ‘ undefined’
var num = 034;
var bool = true;
var n = null;
var u = undefined;
var arr = [1,2,3,4,5];
var obj = {"username":'张三',"userpass":'123456'}
//Number转换成String
console.log(String(num),num.toString()); //34 34
//Boolean转换成String
console.log(String(bool),bool.toString()) // true true
//null类型转换成String
console.log(String(n))
//null利用toString无法转换的,要报错
// console.log(n.toString())
console.log(String(u));
//undefined利用toString无法转换的,要报错
// console.log(u.toString());
//array方法转换成字符串
console.log(arr.toString(),String(arr)); // 1,2,3,4,5
//object转换成字符串
console.log(obj.toString(),String(obj)) //[object Object] [object
Object]
//将值按照进制来转换
console.log(num.toString(10));
//总结:
//针对于null和undefined是toString方法无法转换,要报错,String()方法可以转换
字符串转义符
字符字面量可以出现在字符串中的任意位置,且可以作为单个字符被解释:
\n 换行
\ 斜杠
\‘ 单引号 表示就是单引号,没有任何含义
" 双引号 表示就是双引号,没有任何含义
\t TAB 缩进
\b 空格
\xnn 十六进制表示的字符
\unnnn 十六进制表示的Unicode字符
字符串相关方法:
① .length : 取得字符串长度
var name = "my name is c"
console.log(name.length); →9
② .charAt (“下标”) 获取对应下标字符
let string = "hello world"
console.log(string.charAt(0)); → h
③ .indexOf() 查找字符对应下标
let string = "hello world"
console.log(string.indexOf('o')); → 7
④ trim() 去除首尾空格
var trimStr = " dlksajdlk jsalk djsadjsa ";
console.log("哈哈"+trimStr+"嘿嘿");
var resTrimStr = trimStr.trim();
console.log("哈哈"+resTrimStr+"嘿嘿");
⑤转换大小写
tolowerCase() 字符串转化为小写
toUpperCase() 字符串转化为大写
⑥ match(): 返回所有查找的关键字内容的数组。
var str1 = "hello";
var str2 = "lo";
var res = str1.match(str2); //匹配字符串
console.log(res.index); //输出匹配成功的开始下标位置
⑦ 字符串分割 split(" 分隔符")
var t23 = "asf3sdg&sadfgsg&qwrt&sf"
console.log(t23.split("&"));
输出: [ 'asf3sdg', 'sadfgsg', 'qwrt', 'sf'
⑧字符串截取
console.log(ycy.slice(1,3));
// 截截取第1个到第3个(不包括3)
console.log(ycy.substr(1,3));
// 截取第1个到第3个(包括3)
console.log(ycy.substring(1,3));
// 截取第1个到第3个(不包括3)
⑨字符串拼接
Ⅰ: concat()
var t23 = "asf3sdg&sadfgsg&qwrt&sf"
var t33 = t23.split("&")
console.log(t33[0].concat(t33[1]));
Ⅱ:+号拼接
var age = 102;
console.log('我今年'+ age +'岁');
字符串和变量相拼接,变量不添加引号
Ⅲ:eval (字符串)
数组的方法 join("拼接符");
var arr = [1,2,3,4,5,6,7,8,9];
var resArrStr = arr.join("+");
console.log(resArrStr);
eval(字符串); 将js中的字符串转为js表达式
console.log(eval(resArrStr));
⑩ 返回 Unicode 值
fromCharCode() 返回指定 Unicode 值,然后返回一个字符串
String.fromCharCode(numX,numX,...,numX)
charCodeAt() 查找下标对应字符的unicode编码
var num1 ='1astring'
console.log(num1.charCodeAt(0)); → 49
ES6字符串拓展
模板字符串
新的声明字符串方式
特性: 内容中可以直接出现换行符(定义多行字符串)用反引号表示 相比es5
的拼串,可读性,可维护性更好
let a = '时间管理大师'
let b = 'aaaa'
console.log(
`${a}就是${b}`
) →aaa就是时间管理大师
模板编译
该模板使用<%…%>放置 JavaScript 代码,使用<%= … %>输出 JavaScript 表达式。
let template = `
<ul>
<% for(let i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %></li>
<% } %>
</ul>
`;
字符串插值
可以在一个连续定义中插入一个或多个值
字符串插值通过在${}中使用一个JavaScript表达式实现:
let value =5
let second = 'one'
let fired = `${value} to the ${second} power is ${value * value}`
console.log(fired); // 5 to the one power is 25
所有插入的值都会使用toString()强制转型为字符串
也可以调用函数和方法
新增的方法:
includes() 返回布尔值,表示是否找到了参数字符串
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
7、Symbol 类型
Symbol(符号)是ECMAScript 6新增的数据类型。符号是原始值,且符号实例是唯一、不可变的
用途是确保对象属性使用唯一标识符,不会发生属性冲突
①基本用法
使用symbol 初始化
let sym =Symbol()
console.log(typeof sym) // symbol
调用时候,可以传入一个字符串对符号进行描述。
let sym =Symbol('foo')
let sym1 =Symbol('hello')
console.log(sym == sym1) // false
Symbol没有字面量语法,只要创建Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性
let sym =Symbol()
let sym1 =Symbol('hello')
console.log(sym) // Symbol
console.log(sym1) // Symbol('hello')
Symbol()函数不能与new关键字一起作为构造函数使用。这样做是为了避免创建符号包装对象
但是可以借助Object函数
let Sym = Symbol()
let mySml = Object(Sym)
console.log(typeof mySml); // object
②全局符号注册表
在全局符号注册表中创建并重用符号,达到共享和重用符号实例。
使用Symbol.for()方法:
五、操作符/运算符
①一元操作符
递增/递减 ++ - - 前置,后置
let age = 20
++age
console.log(age); // 21
let age = 20
age++
console.log(age); // 20