仍杂持续学习中,内容可能有点杂乱,后期会整理……
1、基本语法
1.1 js 的引入
- 页面内嵌:
<script> code </script>
也就是直接在页面写 - 外部引入:
<script src=' 需引入的 js 代码文件位置及名称 '> code </script>
,也就是引入外部的 js 文件
……
<body>
<script type='text/javascript'> // 告诉浏览器 script 标签里的文本属于 javascript 语言
var a=100,
_b=10,
$c=1; // 变量的定义 (变量的只有这三种命名规则) 及赋值
document.write(a, _b, $c) // 打印(输出)到页面
</script>
</body>
……
以上代码中变量的命名需遵循一定的规则,以字母,下划线或 $ 符开头。
1.2 数据类型
1.2.1 堆和栈
介绍数据类型前,需要介绍两个名词:堆 heap 和栈 stack。
任何程序在运行时都要在内存中开辟空间,堆和栈就是跟内存相关的名词。
堆 是动态分配内存,内存大小不一,也不会自动释放。可以简单理解为一块区域。
栈 是自动分配相对固定大小的内存空间,并由系统自动释放。可以理解为客栈(固定的房间)。
1.2.2 原始值与引用值
原始值(放在栈 stack 里面):
number, Boolean, String, undefined, null
一共 5 种。引用值(放在堆 heap 里面):
Array 数组
var a=[1,2,3,4]
Object 对象
var obj={ name:'zs', age:18, sex:'male' }
function 函数
function test() { // 函数名必须遵循小驼峰原则 // 函数内容; return; // 函数必须有返回,return 可以省略(返回空) }
date 日期
var date = Date.now()
RegExp 正则
两类错误
- 低级错误:比如冒号写成了中文冒号,会引发该代码块不会执行,因为 js 编译时会先大致扫描整个代码块,检查语法错误。注意,这不会影响另一个 js 代码块。
- 逻辑错误:比如变量未经定义便使用,代码会运行,到错误处再报错。
1.3 运算符
js 中的运算符与其他编程语言大致一样,这里只做简单介绍。
1.3.1 自增(或自减)
a++:
var a=10; document.write(a++); // 先执行本条语句打印 a,再 ++ // 输出打印为 10
++a:
var a=10; document.write(++a); // 先 ++ 计算 a 再执行本条语句 // 输出打印为 11
1.3.2 逻辑运算符
A && B
:“并且”的意思。若 A、B 均为真,就取值 B;若 A、B 中至少一个为假,则取值 02>1 && documnet.write(' 通过 ') // 打印输出‘通过’,这里运算符按顺序执行
A||B
:“或”的意思碰到真就返回。若 A 为真,返回 A,若 A 为假,B 为真,就返回 B,若 A、B 均为假,也返回 B。!A
与!!A
:非运算符,取反,结果为布尔值,双感叹号意思是取反再取反。>>>!1 false >>>!0 true >>>![] false >>>!!1 true
1.4 条件语句
if
语句if (条件判断){ 当条件满足时,执行里面的语句 }else if (条件判断){ 当条件满足时,执行里面的语句 }else{ 当上述条件都不满足时,执行里面的语句 }
for
循环for (var i=0;i<10;i++){ ……; }
while/do while
:用法与 C++ 一样switch case
:条件判断语句switch(参数){ case 条件 1: // 判断参数是否等于满足条件 1 执行语句; break; case 条件 2: // 判断参数是否等于满足条件 2 执行语句; break; } ------------------------------------------------------------------- var date=window.prompt('input') switch(date){ case 'monday':console.log('working'); break; case 'tuesday':console.log('working'); break; case 'wendesday':console.log('working'); break; }
注意:switch 找到满足条件的语句后,后面的语句虽然不判断,但是也会执行出来,加个 break,就可以终止 switch case 语句。
1.5 类型查询与转换
类型查询:
typeof(obj)
,js 中有六种数据类型:number/srting/boolean/undefined/object/function
注意:typeof(null)为 object。
类型转换
显式转换
Number(a)
将 a 转换成数字parseInt(string,radix)
:parse 是转化,Int 是整型,radix 是进制,取值 2-36。parseFloat(string)
a.toString(radix):转换成字符串,可以指定进制。
String(a):字符串转换
隐式转换:在需要时自动转换
自动转换:
// 这里随便举个例子 var a='1'*123 // 数字乘字符串会自动转换成数值类型,加减乘除除了加,都有这个性质 ------------------------------------------------- var a='1' var b=+a //+ 号可将字符类型转换成数字类型
等于判断
===
:三个等于号,绝对等于!==
:绝对不等于
2、函数
2.1 函数的定义
函数作用:实现高内聚,低耦合,减少重复。
function 函数名() { // 函数名必须遵循小驼峰原则
// 函数内容;
return; // 函数必须有返回,return 可以省略(返回空)
}
-------------------------------------------------------------
var test = function 函数名() { // 函数表达式, 这种写法没必要
函数内容;
}
-------------------------------------------------------------
var test = function(a,b) { // 匿名函数表达式, 还可以指定形参
函数内容;
}
test(1,2); // 函数的调用, 实参可以多于形参,不会报错
// 另外,这里藏着一个 aguments(数组类型), 装着传入的实参[1,2], 可以调用
// 如 document.write(aguments)
另外,这里藏着一个aguments
(数组类型),装着传入的实参[1,2],可以调用,如 document.write(aguments)。
举例:
function sum(a,b) {
a=2;
arguments[0]=3
document.write(a)
}
sum(100,200)
// 输出打印为 3
形参长度:函数名.length
2.2 作用域
与 python 类似,分全局变量和局部变量
js 运行三部曲:语法分析(通篇扫面,检查语法错误)——> 预编译——> 解释执行(边解释边执行,解释一行执行一行)、
2.2.1 语法分析
变量和函数声明的顺序问题:
函数声明,不管写在那里,都会被整体提到逻辑的最前面。
变量的声明也会提升(赋值不会)
test();
function test(){
console.log('a');
}
// 以上也是可以执行,先调用函数,再定义它
----------------------------------------------------------
console.log(a);
var a=123;
// 只会输出 undefined, 变量 a 声明了,但不会被赋值输出
imply global 暗示全局变量:即任何变量,若变量未经声明就赋值,则此变量就为全局对象(就是 window 所有)
一切声明的全局变量,全是 window 的属性,可以通过 window. 变量名
来访问
2.2.2 预编译
预编译发生在函数执行前的一刻。
当函数执行时,会创建一个称为 执行期上下文 的内部对象。
一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
查找变量:从作用域链的顶端依次向下查找。
(1)函数预编译过程
- 创建 AO 对象(Activation Object),识别函数的作用域,函数产生的执行空间
- 找形参和变量 声明,将变量和形参作为 AO 属性名,值为 undefined
- 将实参值和形参统一(把实参值传到形参里)
- 在函数体里面找函数声明,值赋予函数体。(先看自己的 AO,再看全局的 GO)
// 这里举个例子
function fn(a) {
console.log(a);
var a=123;
function a() {}
console.log(a);
var b=function () {}
console.log(b);
function d() {}
}
fn(1);
// 输出结果为:
ƒunction a()
123
ƒunction b()
以上执行的优先顺序理解:
(2)全局的预编译
生成一个 GO 对象 Global Object(window 就是 GO)
找形参和变量声明,将变量和形参作为 GO 属性名,值为 undefined
在函数体里面找函数声明,值赋予函数体。
- 先生成 GO 还是 AO?想执行全局,先生成 GO,在执行函数前一刻生成 AO。若有几层嵌套关系,近的优先,从近到远的,有 AO 就看 AO,AO 没有才看 GO。
[[scope]]:每个 javascript 函数都是一个对象, 对象中有些属性我们可以访问,但有些不可以,这些属性仅供 javascript 弓擎存取,[[scope]]就是其中一 个。[[scopel]指的就是我们所说的作用域, 其中存储了运行期上下文的集合。
作用域链: [[scopel]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
举个例子:
a 函数被定义是,发生如下过程:
定义的函数 a 被执行时,发生如下过程:
b 函数被创建时,发生如下过程:(继承了 a 函数的作用域)
b 函数被执行时,发生如下过程:(创建的自己的 AO)
2.3 立即执行函数
执行完不再另外调用时,立即被销毁,目的时为了避免占用空间。
var num = (function (a,b,c){
return a+b+c;
}(1,3,4));
// 还有第二种写法:不过 w3c 建议采用第一种
(function (){})(); // 这两种函数的 名都没有写的必要
只有表达式才能被执行符号执行,执行符号就是括号 。
function test(){console.log('a');}(); // 这样会报错,函数的声明不能执行
--------------------------------------------------
function test(){console.log('a');};
test(); //test()就是执行表达式 test 的意思,故不会报错
---------------------------------------------------
// 以下这两种写法也不会报错
var num=function (){console.log('a');}();
+ function test(){console.log('a');}(); // 加号将其变成了表达式
3、对象
3.1 创建对象
创建对象有三种方法:
- 字面量
- 构造函数
- 系统自带,new Object();Array();Number();Boolean();String();Date()
- 自定义
- Object.create(原型)方法
var MrJiang={ // 字面量创建对象
name:'MrJiang',
age:18,
sex:'male',
health:100,
smoke:function () {
console.log("I'm smoking!");
this.health--; // 这里的 this 代表的是 MrJiang 对象
},
};
----------------------------------------
// 也可这样创建对象, 与上无区别
var obj = new Object(); // 有 new 就是构造对象
obj.name='MrJinag';
obj.sex='male';
3.2 增删改查
获取属性:
在浏览器里的控制台 console 面板运行:
增加属性:(当然在代码也也可以增加属性)
删除:delete MrJiang.name
3.3 函数生成对象(构造函数)
function Car() {
this.name='BWM';
this.height='1400';
this.health=100;
this.run=function() {
this.health--;
};
}
var car = new Car(); // 通过函数生成一个对象
var car2 = new Car();
car2.name='Tesla';
-------------------------------------------------------
function Student(name,age,sex) {
// 这里隐藏个这个 var this={};
this.name = name;
this.age = age;
this.sex = sex;
this.grade=2017;
// 隐式的 return this;
};
var zs = new Student('zs',18,'male');
-------------------------------------------------------
function Student(name,age,sex) {
// 这里隐藏个这个 var this={};
this.name = name;
this.age = age;
this.sex = sex;
this.grade=2017;
return 123; // 这个就是来搞破坏了, 这个‘return 原始值’是无效的,‘retuen 对象’是可以的(数组,函数都行)
};
var zs = new Student('zs',18,'male'); // 一定要这个 new
有了 new,函数就产生了构造函数的功能。原始值是没有属性和方法的,只有个 length。只有引用值有。
构造函数与普通函数的区别:①定义上没有很大区别,构造函数一般首字母大写,创造实例时用 new。②this 指向不同,构造函数的 this 指向实例对象
因为在 ES6 之前 JS 并没有引入类的概念 所以用构造函数代表类。
原始值的属性:
var num = 4;
num.len=3;
console.log(num.len) // 输出 undefined,但不报错
以上执行结果的原因是,系统碰到 num.len=3,知道这是不被允许的,于是就自动补充:new Number(4).len = 3; delete;
给你创建,但创建完就立马删除了,故不对 num.len=3 报错;
后面碰到 console.log 输出 num.len,系统又会自动补充new Number(4).len
,这个就没被定义,所以输出 undefined。
3.4 包装类
// 将原始值变成对象,这就是包装类
var num =new Number(123);
var str=new String('123');
var bol=new Boolean('true');
原始值类型的,通过包装类可以变得有属性。
一个特例:
var str='abcd';
str.length=2;
console.log(str.length) // 结果为 4
以上运行解释:碰到 str.length=2
,自动隐式的创建new String('abcd').length=2;
,然后立马delete;
,然后str.length
取的是对象类型的字符串的属性。
记住这个:字符串只有一个不可更改的属性 length(字符串还有其他方法的)。赋其他任何属性都不行。
3.5 继承模式
- 原型链继承
- 借用构造函数继承
- 不能继承借用构造函数的原型
- 每次构造函数都要多走一个函数
- 共享原型
- 不能随便改动子类的原型
- 圣杯模式
3.5.1 原型
1、定义:原型是 function 对象的一 个属性(出生即隐式存在),它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
2、利用原型特点和概念,可以提取共有属性。
3、对象如何查看原型一 > 隐式属性_ proto_
4、对象如何查看对象的构造函数一 > constructor
Person.prototype.LastName='Deng'; // 这里的 prototype 就是原型
Person.prototype.say=function () {
console.log('hehe');
};
function Person(){
}
var person=new Person(); // 虽然函数 Person 什么都没有,但继承了 Person.prototype 的属性
console.log(person.LastName)
// 输出为‘Deng’
---------------------------------------------------
function Person(){
this.LastName='Ji'; // 在函数中添加这一句,其他不变
}
console.log(person.LastName)
// 输出为‘Ji’, 自己有就不继承了
更改原型的指向:在使用 new 将函数 Person()变对象时,默认在函数加了一行代码:var this={__proto__:Person.prototype}
声明的原型的指向。
既然这样,那么原型的指向便可以更改:
Person.prototype.LastName = 'Deng';
function Person(){
}
var ch = {
LastName:'sunny',
};
var pon = new Person();
pon.__proto__ = ch; // 更改 pon 的原型
console.log(pon.LastName)
// 输出:sunny
3.5.2 原型链
// 以下就是原型链:
Grand.prototype.LastName='Deng';
function Grand(){};
var grand=new Grand();
Father.prototype=grand;
function Father(){
this.name='Xuming';
}
var father=new Father();
Son.prototype=father;
function Son(){
this.hobbit='smoke';
}
var son=new Son();
--------------------------------
// 控制台里
>>>son.lastName
'Deng'
>>>son.name
'Xuming'
>>>son.hobbit
'smoke'
//son 继承了祖先所有的属性
原型链会过多的继承不该继承的属性。
3.5.3 原型创建对象
Person.prototype.LastName = 'Deng';
function Person(){}
var pon = Object.create(Person.prototype);
3.5.4 call/apply
(1)call
作用:改变 this 的指向。
function Person(name,age){
this.name=name;
this.age=age;
}
var pers=new Person('deng',100);
var obj={};
Person.call(); // 等同于 Person() 执行的意思
----------------------------------------
// 它更大的用处是:
Person.call(obj,'cheng',200);
// 它改变了 Person 函数中的 this 指向,相当于在函数中添加了 this==obj
此时 obj 就变成了:
通过 call 方法,就可以让 obj 借用函数的属性。
原型链会将长辈的所有特点都会继承过来,有时我们不需要其中的东西,利用上面学的 call 方法可以实现这一点。
下例就是一个实际应用:
function Person(name,age,sex,health){
this.name=name;
this.age=age;
this.sex=sex;
this.health=health
}
function Student(name,age,sex,tel,grade){
Person.call(this,name,age,sex); // 调用 Person 函数里的属性
this.tel=tel;
this.grade=grade;
}
var student=new Student('sunny','123','male',139,2017);
(2)apply
与 call 的区别是:call 需要把实参按照形参的个数传进去
apply 需要传一个 arguments。
……
Person.apply(this,[name,age,sex]); // 括起来
……
3.5.5 共享原型与圣杯模式
Father.prototype.LastName='Deng';
function Father(){}
var father=new Father();
function Son(){}
Son.prototype=Father.prototype; // 只继承 Father 的原型
var son=new Son();
进一步地:
Father.prototype.LastName='Deng';
function Father(){}
function Son(){}
function inherit(Target,Origin){
Target.prototype=Origin.prototype;
}
inherit(Son,Father);
var son=new Son();
----------------------------------------------------
// 以上有个缺点,如添加
Son.prototype.sex='male';
// 则这也改变了 Father 的 sex, 显然不合理
//Son.prototype 和 Father.prototype 指向了同一个空间
共享原型:改变子对象的原型会改变父对象的原型
圣杯模式:还是共享原型,不过需要一点小技巧。
Father.prototype.LastName='Deng';
function Father(){}
function Son(){}
function inherit(Target,Origin){
function F(){};
F.prototype=Origin.prototype;
Target.prototype=new F();
Target.prototype.constuctor=Target;
}
inherit(Son,Father);
son.prototype.sex='male';
var son=new Son();
var father=new Father();
// 这样就不影响了
3.6 命名空间
一个网页文件往往是团队合作的结果,经常嵌入多个 js 文件,有时为了实现某个类似的功能,不同的程序员可能写了相似的功能,用了一样的变量命名或者一样的标签名,这时把多个人的工作整合到一起,就会出现冲突的问题。
这是就出现了命名空间,将变量全放在命名空间里。
// 定义一个命名空间(以创建对象的形式)
var org={
department1:{
jicheng:{
name:'abc',
age:123
},
xuming:{
name:'sxc',
age:23
}
},
department2:{
zs:{},
ls:{}
}
}
// 调用变量
var jicheng=org.department1.jicheng;
jicheng.name
以上是老的解决办法。
现在采用新的方法:使用闭包实现
var name='dcf'
var init=(function(){ // 立即执行函数
var name='abc';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
var initDeng=(function(){
var name='Deng';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
init()
initDeng()
// 以上就不会污染 name 这个变量了
3.7 访问属性名
var obj={
name:'qwe'
}
// 访问属性
obj.name
// 实际上,obj.name 等价于 obj['name'], 真正执行的是 obj['name']
obj['name'] // 也可以访问属性
再看个例子:通过拼接的属性访问
var deng={
wife1:{name:'xiaoliu'},
wife2:{name:'xiaozhang'},
wife3:{name:'xiaomeng'},
callWife:function(num){
return this['wife'+num];
}
}
deng.callWife(2) // 打印出 Object {name:'xiaozhang'}
3.8 对象枚举
var arr=[1,2,3,4,5,6]
for (var i=0;i<arr.length;i++){
console.log(arr[i])
}
//for in 循环
var obj={
name:'zs',
age:12,
sex:'male',
height:180
}
for (var prop in obj){
console.log(obj[prop]); // 这里只能这样访问,console.log(obj.prop)会出现 undefined
}
// 输出
zs
12
male
180
以上还是那个问题,obj.prop 的意思是 obj[‘prop’]。
var obj={
name:'zs',
age:12,
sex:'male',
height:180,
__proto__:{
lastName:'deng'
}
}
for (var prop in obj){
console.log(obj[prop]);
}
// 输出
zs
12
male
180
deng
// 如果不想要 deng, 可以这样排除原型:
for (var prop in obj){
if (obj.hasOwnProperty(prop)){
console.log(obj[prop]);
}
}
instanceof
用法及含义
A instanceof B :A 对象是不是 B 构造函数构造出来的(看 A 对象原型链上有没有 B 的原型)
[] instanceof Array
// 输出 True
toString
// 让数组调用对象的 toString 方法
Object.prototype.toString.call([])
// 靠 call 改变 this 的指向
3.9 克隆
var obj={
name:'abc',
age:123,
card:['vasa','master'],
wife:{
name:'dvc',
son:{
name:'ass'
}
}
}
var obj1={
name:obj.name,
age:obj.age
}
正菜来了:
function deepClone(origin,target){
var target=target||{},
toStr=object.prototype.toString,
arrStr='[Object]';
for (var prop in origin){
if (origin.hasOwnProperty(prop)){
if (origin[prop]!=='null'&& typeof(origin[prop])=='object'){
if(toStr.call(origin[prop])==arrStr){
target[prop]=[];
}else{
target[prop]={};
}
deepClone(origin[prop],target[prop]);
}else{
target[prop]=origin[prop];
}
}
}
return target
}
4、数组
4.1 数组
var arr = [1,2,,4];
-------------------------------
var arr = new Array(1,2,,4);
数组的方法
arr.push():增加元素(单个,多个,数组)
// 实现 push 的方法 var arr=[]; Array.prototype.push=function(){ for(var i=0;i<arguments.length;i++){ this[this.length]=arguments[i]; } return this.length }
arr.pop():弹出最后一个元素
arr.shift():删除元素(从前开始删)
arr.unshift():增加元素(从前开始插)
arr.reverse():逆转元素的顺序
arr.sort():元素排序(默认升序),arr.sort().reverse()降序
// 这里排序有个问题 var arr=[1,3,5,4,10] ----------------------- // 控制台里 >>>arr.sort() Array(5) [1, 10, 3, 4, 5] // 这里排序是按 ascii 码排的 ----------------------------------------- // 自定义排序 //1. 函数体里必须写两形参 //2. 看返回值 1)当返回值为负数时,那么前面的数放在前面 // 2)为正数时,那么后面的数在前 // 3)为 0,不动 arr.sort(function(a,b){ return a-b;// 升序 //retrun b-a; 降序 }); // 控制台里 >>>arr Array(5) [1, 3, 4, 5, 10] ----------------------------------------------- // 乱序 arr.sort(function(a,b){ return Math.random()-0.5; }); ---------------------------------------------------- var cheng={ name:'cheng', age:18, sex:'male', face:'handsome', }; var deng={ name:'deng', age:40, sex:undefined, face:'amazing', }; var zhang={ name:'zhang', age:20, sex:'female', }; var arr=[cheng,deng,zhang]; arr.sort(function(a,b){ return a.age-b.age; }) // 控制台里 >>>arr 0: Object { name: "cheng", age: 18, sex: "male", … } 1: Object { name: "zhang", age: 20, sex: "female" } 2: Object { name: "deng", age: 40, face: "amazing", … } length: 3 <prototype>: Array []
arr.splice(从第几位开始,截取长度,在切口处添加新元素):切片
var arr=[1,2,3,5] ----------------------- // 控制台里 >>>arr Array(4) [1, 2, 3, 5] >>>arr.splice(3,0,4) Array[] >>>arr Array(5) [1, 2, 3, 4, 5] --------------------------------- >>>arr Array(4) [1, 2, 3, 4, 5] >>>arr.splice(-1,2) Array[5] >>>arr Array(4)[1,2,3,4]
arr.toString():将数组变成字符串
arr.slice(begin,end):切片
arr.join(str):按照 str 的规则连接,返回字符串类型
var arr=[1, 2, 3, 4, 5] // 控制台里 >>>arr.join('-') 1-2-3-4-5
str.split():按照括号里的规则拆分,返回为数组类型
var str='1-2-3-4-5' // 控制台里 >>>arr.split('-') ['1','2','3','4','5']
4.2 类数组
类数组要求:属性要为索引(数字)属性,必须有 length 属性,最好加上 push
var obj={
'0':'a',
'1':'b',
'2':'c',
'length':3,
'push':Array.prototype.push
}
// 控制台里
>>>obj
Object { 0: "a", 1: "b", 2: "c", length: 3, push: push() }
>>>obj.push('d')
4
>>>obj
Object { 0: "a", 1: "b", 2: "c", 3: "d", length: 4, push: push() }
如果 obj 对象再加个 splice 属性,长得就完全像个数组了。
var obj={
'0':'a',
'1':'b',
'2':'c',
'length':3,
'push':Array.prototype.push,
'splice':Array.prototype.splice,
}
// 控制台里
>>>obj
['a','b','c']
5、补充知识点
5.1 错误类型
- EvalError:eval()的使用与定义不一致
- RangeError:数值越界
- ReferenceError:非法或不能识别的引用数值
- SyntaxError:发生语法解析错误
- TypeError:操作数类型错误
- URlError:URl 处理函数使用不当
5.2 错误捕捉及处理
try{
console.log('a');
console.log(b);
console.log('c');
}catch(e){
console.log(e.name+':'+e.massage);
}
// 尝试执行 try 里面的代码,如果出现报错,则立即转到执行 catch 里的代码
在 try 里面发生错误,不会执行错误后的 try 里面的代码。例如上述代码中,console.log(‘c’)便不会执行。
5.3 严格模式
JavaScript 的语法标准随着时间的更替也在不断更新,从 ES3.0 到 ES5.0,语法更新可能会导致某些方法不兼容。现在主流采用 ES5.0 标准(其实目前已经到 10 版本了)。
// 写在代码最前面,表示支持 ES5.0 的严格模式
'use strict';
严格模式既可以写在全局中,可以写在局部函数里(推荐局部)。
严格模式下,变量使用前必须先声明;局部 this 必须被赋值
6、DOM
6.1 DOM
DOM 是 Document Object Model 的缩写,定义了表示和修改文档所需的方法。DOM 对象即为宿主对象,有浏览器厂商定义,用来操作 html 和 xml 功能的一类对象的集合。也可以说 DOM 是对 HTML 及 XML 的标准编程接口。
DOM 不能直接操作 CSS。
xml 和 html:
DOM 的使用示例:
<script type='text/javascript'>
//dom 对象
var div=documnet.getElementByTagName('div')[0]; // 选取 html 中的 div 便签
div.style.width='100px';
div.style.height='100px';
div.style.backgroundColor='red';
var count=0;
div.onclick=function(){
count++;
if (count%2==1){
this.style.backgrandColor='green';// 点击变绿
}else{
this.style.backgrandColor='red';// 点击变红
}
}
</script>
6.2 事件
7、数据传输
7.1 json
一种数据传输格式,一种类似‘对象’的数据格式,便于前端和后端数据传输。
//json
'{'name':'Jiang','age':18}'
js 中的对象变为 json 格式:
var obj={
name:'Jiang',
age:18
}
var str=JSON.stringify(obj)
// 控制台里
>>>str
"{'name':'Jiang','age':18}"
json 格式变 js 中的对象:
var obj=JSON.parse(str)
7.2 异步加载
js 加载:js 加载是一种同步加载,加载到 javascript 文件时,暂时阻断了 html 和 css 的的加载线,等 js 加载并执行完毕后,再继续执行 html 的 css 的加载。注意 js 加载本身是单线程的。是阻塞的。
但是有些 js 的存在就只是为了初始化一些数据,与页面没关系,不会修改操作页面。这些 js 文件包只是为了引入工具包(模块化的 function), 不调用就不会执行,不会影响页面,于是就可以采用并行先加载过来,提高效率。
javascript 异步加载的三种方案:
defer 异步加载,但是要等到 dom 文档全部解析完才会被执行。只有 IE 能用,也可以将代码写到内部。
<script type='text/javascript' src='tools.js' defer='defer'> </script> // 执行到这时,不会阻塞后续的 html 和 css 的加载
async 异步加载,加载完就执行,async 只能加载外部脚本,不能把 js 写在 script 标签里。
- 执行时不会阻塞页面
<script type='text/javascript' src='tools.js' async='async'></script>
创建 script,插入到 DOM 中,加载完毕后 callback。这种就是按需加载。
<script type='text/javascript'> var script=document.createElement('script'); script.type='text/javascript'; script.src='tools.js'; script.onload=function(){ // 此处的作用是等 tools.js 加载完毕再执行 test test(); } //script.onload 支持 chrome,safari,firefox,opera, 不支持 IE document.head.appendChild(script); </script> ----------------------------------------- //tools.js 文件 alter(' 我居然这么帅 ') function test(){ console.log('a') }
进行函数封装(最终的形式):
<script type='text/javascript'> function loadScript(url,callback){ var script=document.createElement('script'); script.type='text/javascript'; if (script.readState){// 处理 IE 浏览器 script.onreadystatechange=function(){ if (script.readyState=='comlete'||script.readyState=='loaded'){ tools[callback](); } } }else{// 处理目前几种主流浏览器 script.onload=function(){ tools[callback](); } } script.src=url; document.head,appendChild(script); } load.Script('tools.js','test') </script> --------------------------------------- //tools.js 文件 var tools={ test:function(){ console.log('a') }, demo:function(){} }
asynchronous javascript and xml —->ajax
7.3 js 加载时间线
浏览器的执行顺序:
- 创建 Document 对象,开始解析 web 页面,解析 HTML 元素和他们的文本内容后添加 Element 对象和 Text 节点到文档中。这个阶段 document.readyState=’loading’。
- 遇到 Link 外部 CSS,创建线程加载,并继续解析文档。
- 遇到 script 外部 js,并且没有设置 async,defer,浏览器加载,并阻塞,等待 js 加载完成并执行该脚本,然后继续解析文档。
- 遇到 script 外部 js,并且设置有 async,defer,浏览器创建线程加载,并继续解析文档。对于 async 属性的脚本,脚本加载完成后立即执行。(异步禁止使用 document.write())
- 遇到 img 等,先正常解析 dom 结构,然后浏览器异步加载 src,并继续解析文档。
- 当文档解析完成,document.readyState=’interactive’。
- 当文档解析完成后,所有设置有 defer 的脚本会按照顺序执行。(注意与 async 的不同,但同样禁止使用 document.write())
- document 对象触发 DOMContenLoaded 事件,这也标志这程序执行从同步脚本执行阶段,转化为事件驱动阶段。
- 当所有 async 的脚本加载完毕并执行后,img 等加载完毕后,document.readyState=’complete’,window 对象触发 load 事件。
- 从此,以异步响应方式处理用户输入,网络事件等。
8、正则
8.1 实现方式
正则实现的几种形式:
/ 匹配规则 / 修饰符
new RegExp(匹配规则,修饰符)
举个例子:
<script type='text/javascript'>
var reg_1=/^a/g; // 第一种形式
var reg_2=new RegExp('^a','mg'); // 第二种形式
var str='abcd\na';
</script>
-----------------------------
// 控制台里
>>>reg_1.test(str)
true
>>>str.match(reg_1) // 匹配以 a 开头的字符
Array['a']
>>>str.match(reg_2)
Array['a','a']
8.2 修饰符与匹配规则
修饰符:
- i:执行对大小写不敏感的匹配
- g:执行全局匹配(查找所有符合条件的匹配)
- m:执行多行匹配,对于多行字符而言
匹配规则:
方括号:用于查找某个范围内的字符。
如[abc]
,查找方括号之间的任意字符
如[^abc]
,查找不在方括号里的字符
等等…………,还有元字符,与 python 里的正则差不多。
举个例子:
<script type='text/javascript'>
var reg=/[0-9A-z][cd][d]/g; // 第一位匹配 0 至 9 或 A 至 z,第二位匹配 c 或 d,第三位匹配 d
var str='adc1cd'
</script>
-----------------------------
// 控制台里
>>>str.match(reg)
['1cd']
一些常见的函数方法
alert(a)
弹窗函数- 字符串方法:
str.charAt(1)
,取出字符串 str 的第 2 位字符str.charCodeAt(i)
,给出字符串 str 的第 i+1 位字符的 unicode 编码值。
- 交互输入:
num = window.prompt('input')
欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net