Javascript

JS学习笔记

本文主要是介绍JS学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

镇楼图

Pixiv:DSマイル

备注:写得比较简略



〇、JS基本语法

利用JS可以使网页具备交互能力,有关JS的历史不在此说明(可能会看到DHTML或是ES、TS等其他概念或是技术,但不在此说明)

JS属于解释性语言,主要由ECMAScript、DOM、BOM三部分组成

JS代码使用方式

<script>
    //内嵌式
	//这里开始写JS代码
</script>
<script src="JS文件位置"></script>
<!-- 外部式 -->
<!-- 行内式 -->
<input type="button" onclick="//JS代码">

语句

JS的语法非常自由,可以加分号也可以不加分号

s1
s2;
//推荐加分号

注释

JS的注释和C语言一样,采用///**/<!--

<!-- 我是注释1,不需要添加"-->"
//注释2
/*
	注释3
*/

输入/输出

var x = prompt("输入");
//prompt输入的为String类型
alert("弹出警告框");
console.log("浏览器控制台输出,F12可看到")

变量

JS是弱类型的语言,且大小写敏感,命名规则不再说明和其他语言一样

var age = 18;
age = "18岁"

JS的语法是非常随意的,甚至类型都是可以随意变换的(术语称为动态类型),可以一会字符串一会数字

数据类型

在JS中有七种数据类型,这里先说明五种,其他类型后续会说明

var a;
//undefined类型
//表明已声明但未赋值
var b = null;
//NULL类型
/*对于字符串拼接运算而言
  null会当作空字符串
  而其他像是undefined、true都会当作实际的字符串值
var c = true;
var d = false;
//Boolean类型
//与数值运算时true当作1,false当作0
var e = "String类型";
//备注:JS同样存在转义字符
//可以用单引号也可以用双引号
var g = 114514;
g = 1.14514;
//Number类型
//无需区分整数、浮点数
var h = 0114;
//前面加0表示八进制
var i = 0x514;
//前面加0x表示十六进制
var j = Infinity;
var k = NaN;
//其中有两类特殊数值
//Infinity,-Infinity表示正/负无穷
//NaN表示非数字,如字符串或是无法运算的不是数字,可以用isNaN(k)判断

转换为String

toString(a);
String(b);
"" + 123;//可以通过拼接运算隐式转换

转换为Boolean

Boolean(NaN);
//'',0,NaN,null,undefined会转成false
//其余都会转成true

转换为Number

parseInt("1.114514");
//转换为整数
parseFloat("1.114514");
//转换为浮点数
Number("11451.4");
alert('100' * 10);
//可以过算术运算- * /隐式转换
//备注:不会转成ASCII码再运算

运算

运算符(没有按照优先级排列) 说明
typeof 获取某一类型、变量等的类型
+ 字符串拼接运算
+ - * / % 加减乘除余
++ -- 自增/减,先增减还是先返回和C语言一样略
< > <= >= == != === !== 比较,唯一不同的是在判断相等/不等时有不同的运算符(见备注)
&& || ! 与或非,备注:存在短路判断机制
= += -= *= /= %= 赋值运算符
,
(条件) ? v1 : v2 条件,三元运算符

备注:

在JS中比较相等/不等时有两类

■!= ==,这种是不严格比较,不会比较数据类型会先隐式转换成相同的数据类型(好像是转换成Number)再进行判断

■!== ===,这种是严格比较,会比较数据类型,只要类型不同就会返回false

流程

这和大部分语言一样,这里就不再说明

if(/*条件*/){
    //
}

if(/*条件*/)/*s1;*/

if(/*条件*/){
	//
} else{
	//
}
switch (/*表达式*/){
    case v1:
        //
        break;
        //continue略
    case v2:
        //...
        break;
	//...
    default:
        //...
}
while(/*条件*/){
	//...
}
do{
    //...
}while(/*条件*/);
for(/*初始*/;/*条件*/;/*步长*/){
    //...
}

数组

由于JS是动态类型,因此数组显得相当灵活,其下的元素类型可以完全不同

a = new Array(4);
//创建长度为4的数组
b = Array();
//可不声明长度和new
var c = Array("字符串",true,a,b,123);
//可以在直接定义元素
//且其中元素类型可以完全不同
d = ["字符串",514];
e = [];
//这是另一种定义方式
y[0] = 114;
//索引方法

JS的索引(下标)默认是从0开始的数字,但其实可以更加灵活,像是用哈希表一样,索引也是任意的

x = [];
//通过如下方式可以添加元素
x["name"] = "Li Hua";
x["year"] = 15;
x[12] = 100;
x[false] = 123;
alert(x[false]);
s1 = Array();
s2 = Array();
s3 = Array();
f = [s1,s2,s3];
s1["X"] = 25;
alert(f[0]["X"]);
//也可以构成多维数组
//可以用数组length来调用或修改
a = [];
a["20"] = 20;
a["10"] = 10;
a["00"] = 0;
a.length = 6;
alert(a);
//此时a只有3个定义的元素,其余的会视为empty

函数

function name(/*参数表*/){
	//...
	//return 返回值;
}
//JS中如果不写return则认为return undefined;


function f(n = 5){
    //指定默认值
    if(n === 1)return 1;
    else return n*f(n-1);
}

f();
/*在不指定默认值的情况下
是允许不用传递参数的
但此时视为undefined
输出多半会是奇怪结果

arguments定义可变参数

arguments是一种伪数组,伪数组同样可以用length属性获取长度,但缺少很多数组里的方法

function add(){
    //会在Arguments数组存储所有传递的值
    var sum = 0;
    for(var i = 0;i < arguments.length;i++){
		sum += arguments[i]; 
    }
    return sum;
}

var x = add(1,2,3,4,5);
alert(x);

其他定义方式

var m1 = function(a,b,c){
    //称为匿名函数
    return a+b+c;
}
var m2 = [];
m2[1] = m1;
alert(m2[1](1,2,3));
//现在可以通过变量名来调用

作用域

在JS中同样有作用域的概念,在函数外的变量为全局作用域(适用当前js文件),在函数内的为局部作用域(适用当前函数)

备注:无块级作用域(ES6有)

a = 1;
//全局变量
function f(){
    alert(a++);
}

f();
f();

作用域链

JS是允许函数内写函数的,其中子级的函数可以用父级的变量或是函数

至于先调用哪个会从当前一级往上寻找(就近原则),如果没有就报错

function f1(){
    var n = 10;
    function f2(){
        alert(f3(n));
    }
    function f3(n){
        return n;
    }
	f2();
}

f1();

预解析

JS是解释型语言,即会从上到下逐句解析,但在解析之前会进行一步预解析

预解析过程中会将所有var、function提升到当前作用域最前面,然后根据输入顺序从上到下执行

其中对变量来说,从上到下如果运行到之前为遇到的变量就视为undefined

alert(f(5));//正常
function f(a){
    return a;
}
alert(a);//报错
a = 5;
alert(b);//正常,但有问题
var b = 6;
//变量只会预解析声明
//但不会预解析赋值因此是undefined

//=========================
var n = 10;
f();
function f() {
    alert(n);//结果为undefined
    //函数中的var n会提前
    //但其赋值不会提前
    var n = 20;
}

Web APIs

在简单了解JS语言特性以及DOM后一方面可以接着深入ES,令一方面可以开始着手Web APIs。我个人是优先倾向于后者,ES可能要再等一段时间才会学习。

其中DOM、BOM(WOM)是Web APIs中特别重要的一环,是直接实现交互功能的关键

API是指应用程序编程接口(Application Programming Interface),预先提供了一定功能可以直接实现功能而不需要考究源码


一、面向对象(Object)

Object

Object是特别重要的一类数据类型

Object由属性、方法组成

在JS中分为三类

■用户定义对象:用户自行创建的对象

■内建对象:JS中自带的(写在了我的其他blog中,这里不再说明)

■宿主对象:其他运行环境中自带的

对象类型的某一个变量称为实例

var x = Object();
//创建尚未定义的对象
x.status = 0;
//设定属性
var a = new x;
//通过new生成实例

创建/调用

var x = {};
//创建空对象
var y = {
    name: 1,
    age: 18,
    BP: 3000,
    test: function(){
        alert("test");
    }
}
//可以创建具有属性方法的对象
alert(y.age);
alert(y['BP']);
//备注:这种形式必须用String进行索引
//调用属性
y.test();
//调用方法
var obj = new Object();
//创建空对象
function obj1(name,age){
    this.name = name;
    this.age = age;
}
//构造对象类型
var a = new obj1('张三',18);
//可以通过new来调用定义对象

遍历对象

for(var x in obj){
    alert(obj[x]);
    //通过for in的形式
    //x可以依次获取其属性名
}

二、DOM(Document Operate Moudle)

通过DOM接口可以访问HTML所有的元素,当网页加载时便会产生DOM

有关DOM的具体内容我已写在其他blog,这里主要介绍最常用的

DOM树

以一种树结构来看到HTML文档,会发现本质上是有迹可循的,从树结构也能够更好地运用CSS选择器

DOM中有非常多的对象最重要的是document对象,有一类特别的对象称为window称为BOM(WOM),这种对象是网页整体的页面

通过转换对象后,可以通过属性或是方法去改变实现网页的动态变化

再DOM树下某一元素中又分成了许多节点。节点可以是元素、属性、文本等一切内容

获取元素

要控制HTML元素首先要找到才能去使用

alert(typeof document.getElementById("element1"));
//返回id为element1的对象
document.getElementsByTagName("li");
//返回标签为li的对象数组
var y = document;
var item = y.getElementsByTagName("p")[2];
//获取p标签的对象数组的第三个对象
var z = document.getElementsByTagName("*");
alert("总元素数:"+z.length);
document.getElementsByClassName("class");
//返回类名为class的对象数组
document.getElementsByClassName("class1 class2");
//返回具有class1和class2两个类名的对象数组
document.querySelector('选择器名');
//根据指定选择器返回第一个元素对象

获取其他元素对象

//可以直接根据元素名来获取
document.body
//返回body元素对象
document.documentElement
//返回html元素对象

有关元素属性常用方法

找到后便可以进行和浏览器元素属性有关的操作,使得浏览器“动起来”

object.getAttribute(attr);
//返回object的属性attr
var p = document.getElementsByTagName("p");
for(var i = 0;i < p.length;i++){
	var text = p[i].getAttribute("title");
    //var text = p[i].title;
    //利用属性而非方法实现也是可以的
    if(text != null) alert(text);
}
//获取每个p元素的title属性
//注:对于不存在的属性值会返回null
object.setAttribute(attr,value)
//设置元素属性值

var ol = document.getElementsByTagName("ol");
for(var i = 0;i < ol.length;i++){
	ol[i].setAttribute("type","i");
}
//将所有ol元素的type改成i
var p = document.getElementsByTagName("p");
p[0].setAttribute("title","");
//属性值设为空
p[0].title="";
//利用属性而非方法实现也是可以的

事件

要触发JS代码,需要触发-响应机制,即只有满足一定条件时才会触发

事件由三部分组成

事件源、事件类型、事件处理(js代码)

事件源要触发事件的对象,可以是文本、图像、按钮之类的载体

事件类型有很多,这里不作具体说明

事件处理就是之后要执行的js代码

<img src="1.png" alt="..." onclick="test(this);" />
<!-- 
	onclick是鼠标点击事件
	里面的属性值是JS代码
	如这里触发了test(this);
-->
<a href="1.html" onclick="return false" id="aaa">打不开QAQ</a>
<!--如果返回false则链接不会被打开-->

当然这里还是繁琐了些,可以直接写在js代码中

混着HTML还可能混着CSS我个人是不太喜欢

var x = document.getElementById("aaa");

x.onclick = function(){
    return false;
}
//1.获取事件源
//2.定义事件
//3.编写js代码

改变元素内容

element.innerText
//文本,不可识别标签
//不保留空格换行
element.innerHTML
//HTML,可识别标签
//保留空格换行

var div = document.querySelector("div");
function f(){
    div.innerText = '123456';
    //改变div元素内容
}
function g(){
    div.innerHTML = '<b>123</b>456';
    //可以识别HTML标签
}

改变样式

element.style.xxx = '';
//可以通过style简单设置样式,但命名有所区别
//如grid-gap在JS要用驼峰命名即gridGap来指定
//JS产生的是行内样式,因为优先级特别高

element.className = '';
//更改某一元素的类名

节点操作

一个节点有nodeType、nodeName、nodeValue三个基本属性

节点类型分成了元素节点(nodeType=1)、属性节点(nodeType=2)、文本节点(nodeType=3)

//通过节点操作能更方便的获取元素
node.parentNode
//获取父节点
node.childNodes
//获取所有子节点对象的集合
//备注:除了元素节点不要忽略其他类型节点
//可以通过nodeType属性进行处理
node.children
//获取所有子元素节点对象的集合
node.firstChild
node.lastChild
//获取子节点中第一个/最后一个节点
node.firstElementChild
node.lastElementChild
//获取子节点中第一个/最后一个元素节点
node.nextElementSibling
//获取当前节点的下一个兄弟节点
document.createElement("tag");
//动态创建tag元素节点
node.appendChild(child);
//在node元素下在最后追加子节点
node.insertBefore(child,x);
//插入child元素至node父元素下x之前
node.removeChild(child);
//删除node下某一child子节点
var x = node.cloneNode();
var x = node.cloneNode(false);
//浅copy,只复制标签不复制内容
var x = node.cloneNode(true);
///深copy,复制标签和内容

对于创建内容来说,总体上innerHTML(采用数组)的效率要高于createNode

事件

注册事件有两种方式:传统方式与监听注册

传统方式对同一元素同一事件设置唯一的处理函数

监听注册(推荐)采用addEventListener()对同一元素同一事件可以设置多个监听器

btn.addEventListener(事件,处理函数,useCapture);
//useCapture可选参数,默认false
//采用监听方式可以设置多个
//传统方式只能设定唯一的监听器
//监听器方式事件与传统方式略有区别,具体参考MDN

此外可以删除事件

btn.onclick = null;
//传统方式只要对某个事件设置null即可删除
btn.removeEventListener(事件,处理函数,useCapture);
//监听器方式采用removeEventListener
//useCapture可选参数,默认false

DOM事件流:事件流是指页面接受事件的顺序,事件发生时会在元素节点之间按照某顺序进行传播,这个传播过程就是DOM事件流

捕获阶段:首先需要从上到下捕获要定义事件的元素

当前目标阶段:处理事件

冒泡阶段:再返回到顶层

JS代码只能执行捕获或是冒泡中的一个阶段,其中useCapture可选参数分别表示了捕获阶段(true)和冒泡阶段(false)

btn.addEventListener('click',function(){return false;},true);
//表明再捕获阶段调用

这用于定义嵌套元素且每层都有事件时的执行事件的顺序

如果是捕获阶段,那么会从父元素到子元素执行,如果是冒泡阶段那么会从子元素到父元素执行



参考书籍

《JavaScrpit DOM 编程艺术》

参考网站

MDN

参考教程

黑马程序员 JS pink

这篇关于JS学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!