[关闭]
@SovietPower 2022-06-11T13:08:13.000000Z 字数 14041 阅读 1091

JavaScript 笔记

学习笔记



作业部落链接:https://www.zybuluo.com/SovietPower/note/1820040
参考:
https://www.runoob.com/js/js-tutorial.html
https://www.w3school.com.cn/js/index.asp


JS 简介

JavaScript是一种轻量级的编程语言,是可插入HTML页面的编程代码。
HTML定义了网页的内容,CSS描述了网页的布局,JavaScript控制了网页的行为。

在HTML中,JavaScript代码必须位于<script></script>标签之间。
<script>可使用type属性:<script type="text/javascript">指定脚本语言为JS,但不是必需,因为JS是HTML默认的脚本语言。

可以在HTML文档中放置任意数量的脚本。
脚本可以放在<head>中,也可放在<body>中。一般将脚本放在<body>的最后,以改善显示速度,因为编译脚本会拖慢显示;也可统一放在<head>中,以便方便管理、不会干扰页面内容。
脚本也可放在外部的JavaScript文件中,其后缀为.js。通过在<script>中设置src引用外部脚本。引用时可以使用完整的URL,也可用相对于当前网页的路径。

将脚本放在外部文件中有如下优点:

HTML 输出流中使用 document.write,相当于添加在原有html代码中添加一串html代码。而如果在文档加载后使用(如使用函数),会覆盖整个文档。

JS 基础内容

JS是一种脚本语言,脚本语言是解释性语言的一种。在浏览器读取代码时,会逐行执行脚本,而不是在执行前对所有代码进行编译。

特点:

  1. document.write("Hello, \
  2. World!")

注意只能对字符串使用。

很多特点与C++相同:

注:

  1. <script>
  2. <!--
  3. document.write("您的浏览器支持JS脚本!");
  4. //-->
  5. </script>

字面量

字面量(literal)是源代码中的固定值,如数字、字符串、表达式、确定的数组。可直接用来赋值(字面量叫做混合值,变量叫做变量值)。
与常量相比,常量是用变量表示的(只是不允许修改),而字面量是直接表示出来的,不用变量储存。变量是一个名称,字面量是一个值。
使用常量便于代码整体修改,使用字面量更直观。

除了常见的数字字面量、字符串字面量,还有:
表达式字面量,用于计算,如:1+2, 1*2
数组字面量(array)定义一个数组,如:[1, 2, 5]
对象字面量(object)定义一个对象,如:{name:"ABC", age:20, grade:"A"}
函数字面量(function)定义一个函数,如:function func(a, b) {return a*b;}

变量

运算符

加号:

数据类型

可包含值的类型(基本类型):数字(Number)、字符串(String)、布尔(Boolean)、bigint(可表示任意精度格式的整数)、Symbol(ES6中新的基本类型,表示独一无二的值,即字面量)。
不可包含值的类型(基本类型):空(null)、未定义(undefined)(两者均不含任何方法)。
引用数据类型:对象(Object)、数组(Array)、函数(Function)、日期(Date)。

基本类型也称原始数据、原始类型、基本数值、基本数据类型,指既非对象也无方法的数据。所有基本类型的值都是不可改变的。

数字(number)可用整数、小数、科学计数表示,不区分整数与实数,如:3.14, 123, 12e-5
字符串(string)用单引号、双引号表示都可。字符串中可以出现引号,只要不与包围字符串的引号相同(当然也可用转义引号)。
布尔(boolean)取值为truefalse

undefined表示该变量不含有值,null表示该变量不指向任何对象地址。
可为变量赋值undefinednull来清空变量,但更倾向于使用null,因为null会主动进行内存释放,如:var A=[1, 2, 3]; A=null; 会释放指向数组[1, 2, 3]的引用(当对象不被任何变量引用时,会释放、回收)。

注意:undefinednull都表示"值的空缺",它们值相等,其布尔值都为false;undefined == null会返回true,undefined === null会返回false。

注意,对boolean值使用异或,其会变为int。
[false] ^= true的结果是1 而不是true。可以用x = !x

数组(array)用中括号包含,下标从0开始。

数组有三种声明方式:
1. var A = new Array()var A = []定义大小为0的数组,通过A[x]=y初始化A[x]的内容,且会将数组大小扩展到x+1,未被初始化的位置的值为undefined
2. var A = new Array(12, "qwq", 34),通过压缩数组(condensed array)。
3. var A = [12, "qwq", 34],通过字面量数组(literal array)。

字符串、对象、函数的具体内容见下。

使用typeof x查看x的数据类型(结果格式为string)(typeof是一种运算符)。
对除null以外的基本数据类型使用typeof,会返回类型本身,如string, number, boolean, undefined
对于非基本类型(数组,对象,函数),typeof的返回值要么是对象object,要么是函数function。此外,null的数据类型也是objectnull是一个特殊的对象值,含义是"非对象")。所以使用typeof并不能区分一个变量是对象还是数组。

使用x instanceof obj可判断x是否为obj类型。如:x instanceof Array。用于判断准确类型。
使用相应方法也可判断x的准确类型。如:Array.isArray(x)(在此之前可先判断Array.isArray是否为true,可判断是否支持该方法)。

使用constructor属性可返回某变量的构造函数,如:

  1. (3.14).constructor // 返回函数 Number() { [native code] }
  2. "John".constructor // 返回函数 String() { [native code] }
  3. false.constructor // 返回函数 Boolean() { [native code] }
  4. [1,2,3,4].constructor // 返回函数 Array() { [native code] }
  5. {name:'John', age:34}.constructor // 返回函数 Object() { [native code] }
  6. new Date().constructor // 返回函数 Date() { [native code] }
  7. function () {}.constructor // 返回函数 Function(){ [native code] }

所以使用constructor属性可判断对象的准确类型(通过构造函数是否包含某字符串),如:

  1. function isArray(A) {
  2. return A.constructor.toString().indexOf("Array") > -1;
  3. }

声明变量时,可使用new为其指定类型,如:var x = new Number(), y = new Boolean(), z = new Object();。但注意,new声明的变量会被创建为对象x,y分别为Number对象、Boolean对象),应避免使用那些本可直接定义的类型(原始类型)的对象,如字符串、数值或布尔对象,它们会增加代码的复杂性并降低效率。
内容相同的字符串与字符串对象用===比较会返回false。

原始类型和对象的区别(这不同于Python):
原始类型(如"abc")自身没有对象的属性和方法(如str.toUpperCase()),但效率更高;对象有自己的属性和方法,但效率更低。
但是,原始类型仍能使用相应对象的属性和方法,因为每种原始类型都可创建其“对象包装器”(包含String、Number、Boolean和Symbol),原始值在调用属性/方法时可执行如下操作:
1. 创建一个包含原始值字面量的对应类型的特殊对象,包含对应对象的所有属性和方法。
2. 执行创建出的特殊对象的被调用属性/方法。
3. 销毁特殊对象,返回到原始值。

所以,不能为原始类型添加属性/方法(赋值语句可以执行成功,但只是对特殊对象赋值,原始值仍不包含属性/方法)。

类型转换

转String
String(x)
输出一个对象或变量时,会自动调用其toString方法。

Number to String
使用String(x)方法,或Number的方法x.toString()

Number的其它方法:
number.toExponential(x):将number的值转为科学计数法。返回String。
参数可选,规定科学计数法中的小数位数,范围为,默认会尽可能大。

number.toFixed(x):将number的值四舍五入为指定小数位数的数字。返回String。
参数可选,规定小数的位数,范围为,默认为0(即取整)。

number.toPrecision(x):将number转换为指定长度的数值字符串。
参数可选,规定要转换为几位数,范围为,默认为数字本身位数。

Boolean转String
使用String(x)方法,或Boolean的方法x.toString()
如:false.toString()==String(false)=="false"true.toString()==String(true)=="true"

Date转String
使用String(x)方法,或Date的方法x.toString()

Date的其它方法见:https://www.runoob.com/jsref/jsref-obj-date.html

转Number
Number(x),或用运算符+
+直接对变量使用时,可将其转为数字。如果变量不能转换为数值,则其值为NaN。如+"5"==5, +"ABC"==NaN。具体可见运算符部分。

特殊情况:

字符串

字符串(string)用单引号、双引号表示都可。字符串中可以出现引号,只要不与包围字符串的引号相同(当然也可用转义引号)。
字符串也是一种数组,可通过下标访问字符。

属性:
constructor:返回创建字符串属性的函数。
length:返回字符串的长度。
prototype:允许向对象添加属性和方法。

方法:
https://www.runoob.com/js/js-strings.html

对象

对象是拥有属性和方法的数据,是属性和方法的容器(即可存储多个值、函数)。
对象的键值对称为属性,方法是作为属性来存储的函数。

通过x.attrx["attr"]访问属性或方法,通过x.func()调用方法。

定义对象有四种方式:
1. 通过属性的"名称:值"对:var A = {name:"A", age:20, score:"A"}
也可分多行写:

  1. var A = {
  2. name: "A",
  3. age: 20,
  4. score: "A",
  5. getScore: function() {
  6. return this.score;
  7. }
  8. }

2. 先创建对象,再追加属性、方法。

  1. var A = new Object();
  2. A.name = "A";
  3. A.age = 20;
  4. A.getName = function() {return this.name;}

3. 将2.改为函数。

  1. function InitA()
  2. {
  3. var obj = new Object();
  4. obj.name = "A";
  5. obj.age = 20;
  6. obj.getName = function() {return this.name;}
  7. return obj;
  8. }
  9. var A = InitA();

4. 将3.的函数直接改为对象。

  1. function InitA()
  2. {
  3. this.name = "A";
  4. this.age = 20;
  5. this.getName = function() {return this.name;}
  6. }
  7. var A = new InitA;

注:定义时,同一变量名可被赋值多次(属性或方法),只以最后一次赋值为准。

函数

使用function Function_Name(arguments)定义函数。函数体放在大括号/花括号中。定义的函数可以在任意位置被调用。
形参称为parameters,实参称为arguments。调用Function_Name获得的是函数对象(完整的函数声明代码),调用Function_Name()获得的是函数结果。
函数可以返回任意类型的值或不返回值,没有确定的类型限制。

关于参数
传入的实参可以少于形参个数,若形参没有默认值,则为undefined。
传入的实参可以多于形参个数。
所有传入的实参都会被存到该函数对象的arguments属性中。使用arguments[0], ..., arguments[arguments.length-1]可访问所有实参。
arguments类似数组,但没有Array的属性方法,只有length属性和索引元素功能。

自调用函数
在表达式后面加(),会得到自调用表达式,在此处会自动被调用。
可用此创建一个匿名自我调用的函数(没有函数名,注意函数要整体加括号)。
如:

  1. (function () {
  2. console.log('qwq');
  3. })();

箭头函数
更简洁的函数表达式。类似Python的lambda,但仍可加函数体。
语法:

  1. (参数1, 参数2, ..., 参数n) => {函数体}
  2. 唯一参数 => {函数体} //当只有一个参数时,可省略小括号
  3. () => {函数体} //没有参数时,保留一个小括号
  4. (参数1, 参数2, ..., 参数n) => 表达式 //不使用大括号时,只能有一句表达式,表示返回值
  5. (参数1, 参数2, ..., 参数n) => {return 表达式} //等同于上一行

作用域

作用域为可访问变量、对象、函数的集合。

同一变量在同一作用域,只能使用一种方式声明。
如:

  1. var a=1;
  2. let c=0;
  3. for(var i=1; i<4; ++i) {a=2; var b=3; let c=4;}
  4. console.log(a, b); // 2 3
  5. console.log(c); // 0

通过letfor, if也可拥有自己的作用域(块级作用域),可用于定义循环变量等循环内用的变量,而不影响外部变量的值。
for还有一个特点:定义循环变量的部分为父作用域,循环体内部是另一个子作用域,可以再次声明循环变量且互不干扰:

  1. for(let i=0; i<3; ++i)
  2. {
  3. let i = 'abc';
  4. console.log(i);// abc abc abc
  5. }

此外var可以定义多次,let只能定义一次:

  1. var a=1;
  2. var a=2;
  3. let b=1;
  4. // let b=2; //Identifier 'b' has already been declared
  5. console.log(a, b) // 2 1

HTML中默认的全局对象是页面本身,即window对象。所有全局变量(含函数)都属于window对象,为window的属性(或方法),既可直接用变量名访问,也可用window.name访问。声明全局变量并赋值,会覆盖window的该属性。
未声明的变量赋值,该变量也将成为一个全局变量,也是window的一个属性。
不同的是,非严格模式下通过对未声明的变量赋值创建的全局变量,是全局对象的可配置属性,可以删除;而直接声明的全局变量,是不可配置全局属性,不可删除。
如:

  1. var n1 = 1;
  2. function f() {n2 = 2;}
  3. f();
  4. console.log(n1, window.n1); //1 1
  5. console.log(n2, window.n2); //2 2
  6. console.log(delete n1); //false 无法删除
  7. console.log(n1); //1
  8. console.log(delete n2); //true 可删除
  9. console.log(n2); //ReferenceError: n2 is not defined.

事件

HTML元素中可以使用JS添加事件属性:<element_name event_name="JS代码">(使用单双引号都可)。
如:
通过点击按钮改变自身或其它元素(this可换为getElementBy..)的内容:
<button onclick="this.innerHTML=Date()">当前时间</button>
也可以在点击按钮时直接调用函数,且更常与函数一起使用:
<button onclick="DisplayDate()">当前时间</button>

DOM事件:https://www.runoob.com/jsref/dom-obj-event.html

为某元素添加监听事件:element.addEventListener(event, function, [useCapture])(追加,同一事件可以同时执行多个函数)
为某元素删除监听事件:element.removeEventListener(event, function, [useCapture])

this

this所指的对象,与其使用位置有关:

在浏览器窗口中,全局对象即为[object Window],即window对象。

JS 语句

条件

JS的if, if...else, if...else if...else均与C相同。

JS的switch也基本与C相同(包括breakdefaultcase内容不需要大括号)。
但注意,case必须加break,否则在匹配一个case后,会执行后面所有case的内容直到被break(匹配后,后面的case不会再被判定)。

JS还有switch的类似写法:

  1. const/var condition = ...;
  2. let obj = {
  3. 'condition1' : () => { ... },
  4. 'condition2' : () => { ... },
  5. 'condition3' : () => { ... },
  6. }
  7. obj[condition]();

该写法类似函数的哈希表,但如果不存在obj[condition]这一项,即没有对某个可能的condition进行判断,会出错Uncaught TypeError: obj[condition] is not a function,程序会终止运行。

循环

for, while, do...while, break, continue与C相同,包括只有一条语句时(如continue)不需要大括号。如:

  1. for (var i=0, len=A.length; i<len; i++)
  2. document.write(A[i] + "<br>");

此外,还可以for infor of

https://blog.csdn.net/q5706503/article/details/82950764

  1. for (var v of A):
  2. console.log(v); //A[i]
  3. for (const v of A): //可用const保证不修改元素
  4. console.log(v);
  5. for (let [k, v] of mp) //迭代一个map
  6. console.log('map:', k, v);

break

可用label_name:对一个代码块进行标记。用break label_name可从当前代码块中直接跳出。
直接使用break时,默认从当前循环/switch代码块中跳出。使用break label_name可以从任意一个代码块中跳出。
如:

  1. Output:
  2. {
  3. document.write(A[0] + '<br>');
  4. document.write(A[1] + '<br>');
  5. break Output; //跳出
  6. document.write(A[2] + '<br>');
  7. }
  8. OuterLoop: //直接跳出外部循环
  9. for(let i=0; i<5; ++i)
  10. {
  11. InnerLoop:
  12. for(let j=0; j<5; ++j)
  13. {
  14. if(i<=2) break;
  15. else if(i==3) break OuterLoop;
  16. }
  17. }

输出

例:
通过DOM中定义的document.getElementById(x)获取id为x的HTML元素,然后用其innerHTML属性修改内容(同样还有document.getElementByName(x)获取name为x的HTML元素,但返回的是一个数组)。

  1. <p id="para1">emmm</p>
  2. <script>
  3. document.getElementById("para1").innerHTML = "段落已被更改。";
  4. </script>

例:
<script>document.write("<h1>这是标题</h1>")</script>会在相应位置生产一个一级标题。

注意:
如果在文档加载完成后,再执行document.write(),输出内容会将整个HTML页面覆盖。
因为如果执行document.write()前没有调用document.open()(比如页面加载完成后执行),会先调用document.open(),导致清空当前文档内容。

例:
<script> console.log(Date()); </script>

错误

try...catch

类似Python的try...except。检测到错误后可对错误进行处理,且不会终止程序。
try定义进行错误检测的代码块;catch定义错误处理代码块。注意该代码块似乎必须要加大括号。
例:

  1. try {
  2. qwqalert('qwq');
  3. }
  4. catch(e) {
  5. alert('Error:\n' + e.message + '\n' + '点击以继续\n');
  6. }
  7. finally {
  8. console.log('Finish') //Finish
  9. }

可加入finally,同Python,不论是否捕捉到错误,最后都会执行finally代码块。

throw

类似Python的raise。使用throw exception可主动抛出任意类型的错误。
exception可是任意类型(字符串、数字、对象等),使用catch捕捉到后可输出该对象。
例:

  1. var x = document.getElementById("qwq").value;
  2. try {
  3. if(x=="") throw "值为空";
  4. else if(isNaN(x)) throw "非法值";
  5. else if(x<10) throw x;
  6. }
  7. catch(e) {
  8. console.log( "Error: " + e );
  9. }

调试

使用console.log进行输出。
使用debugger语句可设置一个断点,程序会在该处停止执行,直到手动继续。
例:

  1. console.log("stop");
  2. debugger;
  3. console.log("continue");

严格模式

使用"use strict"进入严格模式,指定代码在严格条件下进行。
"use strict"不算一条语句,属于一个字符串字面量,所以即使不支持严格模式也会被忽略。
"use strict"只允许出现在整个脚本或函数体的开头(在函数中使用则只对该函数生效)。

使用严格模式可以:
1. 消除代码运行的一些不安全之处,保证代码运行的安全。
2. 提高编译器效率,增加运行速度。
3. 符合规范,更严谨。

严格模式的限制:

声明提升
变量提升、函数提升(hoisting):JS中,所有变量和函数的声明会被放到最顶部。所以,变量和函数可以先使用后声明。
即使如此,也应先声明后使用。严格模式下不允许使用未先声明的变量和函数。

注意只有声明部分会被提升,初始化的赋值部分不会被一起提升。
如下例输出1 undefined

  1. var x=1;
  2. console.log(x, y);
  3. var y=2;

正则表达式

正则表达式是由一个字符序列形成的搜索模式。
语法:/正则表达式主体/可选修饰符

JS中,正则表达式常用于字符串的两个方法:search(), replace()
search(x):参数可以为字符串或正则表达式。查找字符串中与串相等(或与正则表达式相匹配)的第一个子串,并返回那个子串的起始位置。
replace(x, y):第一个参数可以为字符串或正则表达式,第二个参数为字符串。将字符串中与相等(或与正则表达式相匹配)的所有子串,替换为字符串

正则表达式主体(todo)

https://www.runoob.com/regexp/regexp-syntax.html

正则表达式修饰符(todo)

i匹配时对大小写不敏感。
g进行全局匹配(查找所有匹配,在找到第一个匹配后不停止)
m进行多行匹配。

RegExp对象

JS中,RegExp对象是一个预定义了属性和方法的正则表达式对象。
具体可见:https://www.runoob.com/jsref/jsref-obj-regexp.html。以下是常用的正则表达式方法。

test()
判断一个字符串是否匹配某个模式,返回true或false。
例:

  1. var s=/e/;
  2. console.log( s.test("abcde") ) //true
  3. console.log( /e/.test("abcde") ) //true

exec()
查找给定串中与正则表达式匹配的结果,返回一个存放了结果的数组。
如:

  1. console.log(/e/.exec("The best things in life are free!")); //e

高级

filter

https://blog.csdn.net/m0_65146387/article/details/121911136

array.filter(function(value, index, arr), thisValue);
函数常用箭头函数表示,index, arr是可选的。
返回一个包含所有满足条件的元素的数组。


其它

滚动页面

https://blog.csdn.net/weixin_38990605/article/details/124980964

滚动至页面最底端:
无滚动条:

  1. var height = document.body.clientHeight;
  2. window.scroll({ top: height , left: 0, behavior: 'smooth'})

有滚动条:

  1. var height = document.body.scrollHeight;
  2. window.scroll({ top: height , left: 0, behavior: 'smooth'})

scrollHeight、clientHeight、offsetHeight具体的范围:

回到顶部:

  1. window.scroll({ top: 0 , left: 0, behavior: 'smooth'})

去某一元素处:

  1. let btn = document.getElementById('btn');
  2. let height = btn.offsetTop ;
  3. window.scroll({ top: height , left: 0, behavior: 'smooth'})

另附查资料看到一个父组件滚动法:

  1. let item = document.getElementById("item"); // 指定的元素
  2. let wrapper = document.getElementById("wrapper"); // 其父元素必须是产生滚动条的元素
  3. wrapper.scrollTo(item.offsetLeft, 0); // 横向
  4. wrapper.scrollTo(0 , item.offsetTop); // 竖向
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注