Pixiv:DSマイル
备注:写得比较简略
利用JS可以使网页具备交互能力,有关JS的历史不在此说明(可能会看到DHTML或是ES、TS等其他概念或是技术,但不在此说明)
JS属于解释性语言,主要由ECMAScript、DOM、BOM三部分组成
<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; }
在简单了解JS语言特性以及DOM后一方面可以接着深入ES,令一方面可以开始着手Web APIs。我个人是优先倾向于后者,ES可能要再等一段时间才会学习。
其中DOM、BOM(WOM)是Web APIs中特别重要的一环,是直接实现交互功能的关键
API是指应用程序编程接口(Application Programming Interface),预先提供了一定功能可以直接实现功能而不需要考究源码
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接口可以访问HTML所有的元素,当网页加载时便会产生DOM
有关DOM的具体内容我已写在其他blog,这里主要介绍最常用的
以一种树结构来看到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