一.前言
通过HTML和CSS的学习,我们可以做到实现静态的页面。然而实现动态页面或者实现交互功能就离不开JavaScript。所以在这里对半个月学习js做一个总结。
二.了解JavaScript
2.1 什么是JS
JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
2.2 组成部分
- ECMAScript:描述了该语言的语法和基本对象。
- 文档对象模型(DOM):描述处理网页内容的方法和接口。
- 浏览器对象模型(BOM):描述与浏览器进行交互的方法和接口。
三.重要知识点总结
3.1 如何引入js
- 页面内嵌
为符合 web 标准(w3c 标准中的一项)结构(html)、行为(js)、样式(css)
相分离,通常会采用外部引入。 - 一个文件中可以包括多个 css,js——不混用
- 特殊写页面,大部分写在外部——不混用
- 如果同时写了内部的 js 和外部的 js,那么是外部的 js 文件显示出来
3.2 基本语法
3.2.1 变量(variable)
HTML,css 不是编程语言,是计算机语言,编程语言需要有变量和函数
变量是存放东西,方便后续使用的框。
- var a ;a =100;可以简化写成 var a=100;
- 单一var声明法:
var a,b,c,d,e;的标准写法是var a = 10; var b = 10; var c = 10; var d = 10; var e = 10;
3.2.2 命名规则(用接近的英文单词)
- 变量名必须以英文字母、_、$ 开头
- 变量名可以包括英文字母、_、$、数字
- 不可以用系统的关键字、保留字作为变量名
3.2.3 值类型
- 不可改变的原始值(栈数据)栈 stack
(Number、String、Boolean、undefined、null) - 引用值(堆数据)大致上放堆 heap 里面
(array 数组、Object、function … data、RegExp 正则)
3.2.4 js语句基本规则
- 语句后面要用分号结束“;”但 function test(){},for(){},if(){}后面都不用加分号
- js 语法错误会引发后续代码终止,但不会影响其它 js 代码块
错误分为两种:
1)低级错误(语法解析错误),不能写中文
2)逻辑错误(标准错误,情有可原,错的那个执行不了) - 书写格式要规范,“= + / -”两边都应该有空格
3.3 js运算符
3.3.1 运算操作符
- “+”作用:数学运算、字符串链接(任何数据类型加字符串都等于字符串)
- %,摩尔,模,是取余数的意思
- “-”,“*”,“/“,“%”,”=“,“()” 优先级”=“最弱【赋值符号优先级最低】,”()”优先级较高
3.3.2 比较运算符
- “>”,”<”,”==”,“>=”,“<=”,”!=”比较结果为 boolean 值。但凡是运算符,都是要有运算的
用到布尔值,true 或 false[字符串的比较,比的是 ASCII 码(七位二进制 0000000) >, <] - = =,等不等于(NaN 不等于任何东西,包括他自己,NaN 得不出数,又是数字类型,就是 NaN)
- ->=,<=,!=是否不等于,非等。比较结果为 boolean 值:true 和 false
3.3.3 逻辑运算符
“&&”,“||”,“!“运算结果为真实的值
- “&&”与运算符:两个表达式:先看第一个表达式转换成布尔值的结果是否为真,如果结果为真,那么它会看第二个表达式转换为布尔值的结果,然后如果只有两个表达式的话,只看看第二个表达式,就可以返回该表达式的值了,如果第一位布尔值为 false,不看后面的,返回第一个表达式的值就可以了。如果是三个或多个表达式,会先看第一个表达式是否为真,如果为真,就看第二个表达式,如果第一个是假,就返回第一个值,当是真的时候就往后走,一旦遇到假,就返回。
- &与运算:我们一般不用。按位与,相同为1,不同为0(对齐补零)
- “||”或运算符:看第一个表达式是否为真,如果为真,则返回第一个值,碰到真就返回如果第一个表达式是假,就看第二个表达式,如果第二个是最后一个,就返回第二个的值。
- “!“非运算符,否的意思。先转成布尔值,再取反
被认定为 false 的值:转换为布尔值会被认定为 false 的值 undefined,null,NaN,
“”(空串), 0, false
3.4 初识引用值
3.4.1 数组
所有的JavaScript变量都是对象。数组元素是对象。函数是对象。因此,你可以在数组中有不同的变量类型。你可以在一个数组中包含对象元素、函数、数组。
3.4.2 对象 object
var obj = {
里面存属性和方法
key 属性名:value 属性值,
}
在{}面用。属性与属性之间用逗号隔开
//属性值可以双引号或单引号;属性名是为了方便找到他,只是一个辅助。
3.5 操作符
3.5.1typeof
typeof 能返回的六种数据类型(区分数字类型)
number、string、boolean、undefined、object、function
(null 返回 object,最早是代替空对象的)
如果定量没定义就直接访问,就 a is not defined 报错;有一种特殊情况,当且仅当把未定义的变量放到 console.log(typeof(a));里面就访问,不报错,返回 undefined
3.5.2 显示类型转换
- Number(mix) 是想把里面的东西转换成数字
var demo = undefined;
var num = Number(demo);
console.log(typeof(num) + “:” + num);
答案显示 Number:NaN
(可以把null、空字符串、false转换为0;把true转换为1)
- parseInt(string,radix)parse 是转化,Int 是整型,整数,目的是把里面转换成整数。parseInt 从数字类开始看,看到非数字类为止,返回原来的数。
(把空字符串、true、false、null转换为NaN)
var num = parseInt(demo ,radix);
radix 写成 16,系统会认为是以 16 进制为基底,10(一零)是 16 进制的一零,是
以 16 进制为基底,把他转成为 10 进制的数字(就是 16),上面是以目标进制为基底,
转换成十进制(radix 范围是 2-36)
- parseFloat(string):转换成浮点数字,就是正常小数。parseFloat 从数字类开始看,看到除了第一个点以外的非数字类为截止,返回前面的数。
- toString
- 想把谁转换成字符串,就写成谁.toString
- undefined 和 null 不能用 toString
- toString(8);这里的 radix 意思是以十进制为基底,转换成目标进制(即 8 进制) - String(mix):String(mix)转换成字符串,写什么都成了字符串
- Boolean():转换成布尔值 false 和 true
3.5.3 隐式类型转换
隐式类型转换是跟你转换了也不知道
隐式类型转换内部隐式调用的是显示的方法
隐式类型转换包括 isNaN () ,++,--, +/-(一元正负),+,*,% ,&&,|| ,!,<,>,<= ,>= ,== ,!=
- isNaN ():当你把一个数放到()里,它能判断是不是 NaN,先把括号里面的放到 number里面转换,然后返回来
- ++/-- (加加减减) +/-(一元正负)
(尽管转换不成数字,也会转换成数字类型,因为里面隐式的调用了一个 number) - “+”:+隐式类型会转换成 string,当加号两侧有一个是字符串,就用调用 string,把两个都变成字符串
- " * ,%" 乘和模都会转换成 number.
- && || !与或非,都是有类型转换的,不过是返回的是表达式的值,不是隐士类型转换的值,但是判断是一个类型转换的值
- < > <= >=
有数字相比较的,就会隐士类型转换成数字类型
两个字符相比,比较ASCⅡ
- == !=
undefined == null //答案 true
NaN ==NaN //答案 false,NaN 是唯一一个连自己都不等于的
3.5.4 不发生类型转换
- ===绝对等于(三个等号) !==绝对不等于
(NaN =NaN //答案 false 特殊的)
【toFixed(3)是保留三位小数的意思,四舍五入】
提示:
alert(‘a’);就是弹出框,相当于 console.log
3.6 函数function
function 随便起个名(){};
编程讲究高内聚,弱偶合。
3.6.1 定义
- 函数声明
a.定义一个函数可以先写一个 function,函数就是另一个类型的变量。
b.function 随便起个名(){函数体};
c.函数名起名:开发规范要求,函数名和变量名如果由多个单词拼接,必须符合小驼峰原则(第一个单词首字母小写,后面的首字母大写)
d.c 语言和 c++,他们打印指针,会输出指针的地址,而 js 这种弱数据语言(解释性语言)永远不输出地址,输出地址指向房间 - 函数表达式
a.命名函数表达式
b.匿名函数表达式
3.6.2 组成形式
- 函数名称
function test(){}其中 function 是函数关键字,test 是函数名,必须有(){},参数可有可没有,参数是写在()括号里面的。如果写成 function test(a,b){},相当于隐式的在函数里面 var a,var b 申明了两个变量,()括号里面不能直接写 var - 参数(可有可没有,但是高级编程必有)
a.形参(形式参数):指的是 function sum(a,b){}括号里面的 a 和 b
b.实参(实际参数):指的是 sum(1,2);里面的 1,2
(天生不定参,形参可以比实参多,实参也可以比形参多。js 参数不限制位置,天生不定参数在每一个函数里面都有一个隐式的东西 arguments 这个是实参列表)
在 if 里面定义函数声明 function 是不允许的 - 返回值 return
a.结束条件和返回值 return,return 有终止函数的功能
b.没写 return,实际上是加上了一个隐式的 return
c.return 最常用的是返回值。本意是把一个值返回到函数以外
3.7 全局的预编译三部曲
- 生成了一个 GO 的对象 Global Object(window 就是 GO)
- 找形参和变量声明,将变量和形参名作为 GO 属性名,值为 undefined
- 在函数体里面找函数声明,值赋予函数体
(任何全局变量都是 window 上的属性没有声明就是赋值了,归 window 所有,就是在 GO 里面预编译)
(想执行全局,先生成 GO,在执行 test 的前一刻生成 AO在几层嵌套关系,近的优先,从近的到远的,有 AO 就看 AO,AO 没有才看 GO)
3.8 闭包
3.8.1 什么是闭包
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。
内存泄漏就是内存占用,内存被占用的越多,内存就变得越来越少了,就像内存被泄露了一样
(但凡是内部的函数被保存到外部,一定生成闭包)
3.8.2 闭包的作用
- 实现公有变量
每回调用 counter 就会在原有基础上加一次
每回调用 counter 就会在原有基础上加一次 - 可以做缓存(存储结构)
eg:eater。缓存是外部不可见的,但是确实有存储结构
答案 101 和 100,思考过程:说明两个用的是一个 AO
答案 i am eating banana,eat 和 push 操作的是同一个 food
在 function eater(){里面的 food}就相当于一个隐式存储的机构
obj 对象里面是可以有 function 方法的,也可以有属性,方法就是函数的表现形式 - 可以实现封装,属性私有化。
- 模块化开发,防止污染全局变量
3.9 立即执行函数
3.9.1 定义
此类函数没有声明,在一次执行过后即释放(被销毁)。适合做初始化工作。针对初始化功能的函数:只想让它执行一次的函数立即执行的函数也有参数,也有返回值,有预编译。(写成(function abc(){}())也调用不到)
3.9.2 立即执行函数的两种写法
- (function (){}());在 W3C 建议使用这一种
- (function (){})();
只有表达式才能被执行符号执行
能被执行符号执行的表达式,这个函数的名字就会被自动忽略(放弃名字)
能被执行符号执行的表达式基本上就是立即执行函数
函数声明和函数表达式是两个东西,虽然都能定义函数
函数声明:function test ( ){} 函数表达式:var test = function( ){} - 闭包会导致多个执行函数共用一个公有变量,如果不是特殊需要,应尽量防止这种
情况发生。
3.10 对象
3.10.1 创建方法
- var obj = {} 对象字面量/对象直接量 plainObject
双引号和单引号都是表示的字符串,写双引号也可以写单引号,但是为了跟后端 php配合最好写单引号。如果要打印一个单个的引号,用正则表达式转义字符\注意等号和冒号的用法 obj.say = function(){} var obj = { name : ‘abc’}
- 构造函数
a.系统自带的构造函数 Object()
new Object();Array();Number();Boolean();Date();
b.自定义
Object.create(原型)方法
必须用 new 这个操作符,才能构造出对象构造函数必须要按照大驼峰式命名规则,但凡是构造函数就要大写,
3.10.2 构造函数的内部原理
前提必须要加 new,以下三步都是隐式的:
1.在函数体最前面隐式的加上 var this = {} 空对象
2.执行 this.xxx = xxx;
3.隐式的返回 return this
3.10.3 包装类
- new String();
- new Boolean();
- new Number();
只有原始值数字是原始值,原始值不能有属性和方法,但经过了包装类(加隐式)可以调用一些属性与方法
undefined 和 null 不可以有属性
var num = 4;
num.len = 3;
//系统隐式的加上 new Number(4).len = 3; 然后 delete
console.log(num.len);
//系统隐式的加上 new Number(4).len; 但是这个 new number 和上面的 new number
不是同一个,所以返回 undefined
而上面这些隐式的过程就是包装类。原始值要赋属性
值需要调用包装类,赋了跟没赋值是一样的。
3.10.4 原型
prototype是构造函数的属性,__ proto__是对象的属性
原型是隐式的内部属性,自己加是没有用的
- 原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
- 利用原型特点和概念,可以提取共有属性。
- 对象属性的增删和原型上属性增删改查。
上面通过对象(后代)改原型(祖先)是不行的,在对象里面修改,只作用给自己
改原型都不行,增加肯定也不行。对象可以删除属性 - 对象如何查看原型 ==> 隐式属性 proto。
浅粉色的__proto__是系统的隐式的属性,前面两个_后面两个_,可以修改,尽量不改。
在开发的时候,如果很私人可以写成_private,告诉同事别动。 - 对象如何查看对象的构造函数 ==> constructor。 例 person.prototype //原型(描述一种继承关系)
3.10.5 原型链
- 原型链上属性的增删改查
原型链上的增删改查和原型基本上是一致的。只有本人有的权限,子孙是没有的。 - 谁调用的方法内部 this 就是谁-原型案例
- 绝大多数对象的最终都会继承自 Object.prototype
- Object.create(原型);
Object.create()在括号里面只能放 null 或者 Object,其余会报错 - 原型方法上的重写
原型上有这个方法,我自己又写了一个和原型上同一名字,但不同功能的方法,叫做重写(同一名字的函数,不同重写方式)
数字想用 toString 方法,要经过包装类包装 new Number(num)然后. toString - 3.10.6 call/apply
作用,改变 this 指向。
区别,后面传的参数形式不同。
(toFixed 是保留两位有效数字;Math.random()是产生一个 0 到 1 区间的开区间 随机数;向上取整 Math.ceil();向下取整 Math.floor()) - call
任何一个方法都可以.call
Person.call( );括号里面可以传东西
如果 Person.call( obj );里面的 call 让 person 所有的 this 都变成 obj
不 new 的话,this 默认指向 window。call 的使用必须要 new
call 的第一位参数用于改变 this 指向,第二位实参(对应第一个形参)及以后的参数都当做正常的实参,传到形参里面去借用别人的方法,实现自己的功能。
(只能在你的需求完全涵盖别人的时候才能使用) - apply
apply 也是改变 this 指向的,只是传参列表不同,第一位也是改变 this 指向的人,第
二位,apply 只能传一个实参,而且必须传数组 argunments
call 需要把实参按照形参的个数传进去
3.10.7 继承发展史
1.传统形式 ==> 原型链 //问题:过多的继承了没用的属性
2.借用构造函数 ==>利用 call、apply 所以不算标准的继承模式
- (不能继承借用构造函数的原型 2)每次构造函数都要多走一个函数 ==>浪费效率)
3.共享原型(较好的继承方法)//问题:不能随便改动自己的原型
- 在 inherit(Target,Origin)里面传进去的值是构造函数,需要大驼峰式书写,origin
是原始的意思,让 target(目标)继承 origin
function inherit(Target,Origin){
Target.prototype = Origin.prototype;
}
//问题:更改一个的原型会影响到另一个
4.圣杯模式
圣杯模式是在方法三的共有原型,但是在共有原型的基础上有改变。
共享原型是:son.prototype=father.prototype
圣杯模式是:另外加个构造函数 function F(){}当做中间层,然后让 F 和 father 共
有一个原型 F.prototype=father.prototype,然后 son.prototype = new F();使用原型链形成了继承关系,现在改 son.prototype 就不会影响 father.prototype
联系到闭包作用:可以实现封装,属性私有化。
3.10.8 命名空间(其实就是对象)
管理变量,防止污染全局,适用于模块化开发。
下面是现在公司最常见的方法:用闭包来解决(也可用 webpack),返回方法的调用。
init 是初始化,入口函数,入口名字。init 调用了这个函数的功能
3.10.9 实现链式调用模式
用 return this,就可以连续调用和执行了
3.10.10 属性的表示方法(查看属性)
obj.prop 查看就用.XXXX obj[“prop”] 中括号也是访问属性的方法
用方括号来访问属性也是一样的(里面必须是字符串)
这两种基本上完全相同 obj.name → obj [ ‘name’ ]
想实现属性名的拼接,只能用方括号的形式
3.10.11对象的枚举enumeration
for in 循环(简化版 for 循环),目的是遍历对象,通过对象属性的个数来控制循环圈数,这个对象有多少属性循环多少圈,而且在每一圈时,都把对象的属性名放到 Prop里面 在枚举里面,一定要写成 obj[prop]不能加字符串
上面就是 for in 循环,就是遍历用的。通过对象的属性个数来控制循环圈数,有多少个属性就会循环多少圈。
for(var prop in obj)在循环每一圈的时候,他会把对象的属性名放在 prop 里面。想遍历谁就 in 谁,prop 可以写别的,obj 就是我们想要遍历的对象。var XX in XX 的格式是固定的。
obj.prop 系统以后我们写的是 obj[‘prop’],系统会以为我们是在让他访问 prop这个属性,不会把 prop 当成一个变量来使用。写成 obj[prop]就可以成功访问了
- hasOwnProperty
hasOwnProperty 是一个方法,来判断这个对象是你自己的还是原型的, 任何一个对象里面都有 hasOwnProperty,里面是需要传参的,把属性名传进去(如 prop)。下面达到了如果不是自己的属性,是原型上的属性,就不会返回。
一般与 for in 循环成套出现
注明:for in 循环理论上可以返回原型和原型链上的东西,一旦这个原型链延展到了的 object.prototype 上,不会打印系统的,只会打印自带的。 - in 操作符:很少用
你的也是你的,你父亲的也是你的,只能判断这个对象能不能访问到这个属性,包括原型上;不是判断属性属不属于这个对象的 - instanceof
操作用法类似于 in,但是完全不同
A instanceof B 的意思是 A 对象是不是 B 构造函数构造出来的;记住是:看 A 对象的原型链上有没有 B 的原型
区别数组还是对象的方法1.constructor;2.instanceof;3.数组调用他的 toString 方法
逗号操作符,会看一眼 1,在看一眼 2,然后返回第二个
克隆
- 浅层克隆
把上面做一个兼容性的写法,为了防止用户不传 target(容错),给了参数就直接用,不给就当空对象
function clone(origin,target){
var target = target || {};
for(var prop in origin){
target[prop] = origin[prop];
}
return target;
}
现在我们想实现深度克隆(只考虑数组和对象),copy 过去后,我改,但是你不会改,引用值不能直接拷贝
- 深度克隆
function deepClone(origin,target){
var target = target ||{},
var toStr = Object.prototype.toString,
var arrStr = "[object Array]";
for(var prop in origin){
if (origin.hasOwnproperty(prop)){
if(origin[prop]!== "null" && typeof(origin[prop])=='object'){
target[prop] = [];
}else{
target[prop] = {};
}
deepClone(origin[prop],target[prop])
}else{
target[prop] = origin[prop];
}
}
return target;
}
深度克隆的步骤
1、先把所有的值都遍历一遍(看是引用值和原始值)
用 for ( var prop in obj ),对象和数组都可以使用
2、判断是原始值,还是引用值?用 typeof 判断是不是 object
1)如果是原始值就直接拷贝
2)如果是引用值,判断是数组还是对象
3、判断是数组还是对象?(方法 instanceof【看 a 的原型链上有没有 b 的原型】、
toString、constructor,建议用 toString,另外两个有个小 bug——跨父子域不行)
1)如果是数组,就新建一个空数组;
2)如果是对象,就新建一个空对象。
4、建立了数组以后,如果是挨个看原始对象里面是什么,都是原始值就可以直接考
过来了;或者,建立了对象以后,挨个判断对象里面的每一个值,看是原始值还是
引用值
5、递归
3.10.12this
- 函数预编译过程 this —>指向 window
如果不 new,this 指向 window - 全局作用域里 this —> 指向 window
- call/apply 可以改变函数运行时 this 指向
- obj.func(); func()里面的 this 指向 obj,谁调用这个方法,这个方法里的 this 就是指向谁
3.10 数组
3.10.1定义数组的方式
1)new Array(length/content);
2)字面量 var arr = [1,2,3,4,5];
var arr = [ ] ;数组自变量;var arr = new Array ( ) ;系统提供。两者区别就只一位数的情况。Array ( )括号里面只有一位数,就代表着长度,并且里面每一位都没有值。js 数组是基于对象的,数组是一种特殊的对象。
3.10.2数组常用的方法
- 改变原数组(在原来数组基础上去改变)
1)reverse,sort,push,pop, unshift, shift,
2)splice - 不改变原数组
1)forEach filter map reduce reduceRight
2)slice concat,join—>split,toString - 解释:
1.push 是在数组的最后一位添加数据,可以添加一个,也可以添加很多个
2.pop 是剪切方法(把最后一位数剪切出去)。在 pop( )括号里面不能传参,写了会忽略
3.unshift 是从第一位加东西
4.shift 是从第一位开始减
5.reverse 逆反
6.arr.splice(从第几位开始,截取多少长度,传参在切口处添加新的数据)
7.sort 给数组排序(按照从小到大),改变原数组。sort 按 asc 码排序的
直接调用 arr.sort( )比的是 asc 码,要在里面填函数才可以
- 必须写两形参
- 看返回值 return
1)当返回值为负数时,那么前面的数放在前面,
2)当返回值为正数时,那么后面的数在前,
3)为 0,不动 - 乱序一个数组
var arr = [1,2,3,4,5,6];
arr.sort(function(){
return Math.random() - 0.5;
});
8.concat 连接, 把后面的数组拼到前面,并成立一个新的数组,不影响之前的两个数组。不能改变原数组。最后有三个数组。
9.toString 是把数组当做字符串展示出来
10.slice 从该位开始截取,截取到该位,并不改变原数组,这里也可以写负数。slice 并不改变原数组 slice 完了以后需要有东西接收,不然没有意义。slice 里面可以填 0 个参数,也可以填 1 个参数,也可以填两个参数
a.如果填两个参数,slice(从该位开始截取,截取到该位)
如 arr.slice(1,2)从第一位开始截取,截取到第二位
b.如果填一个参数,从第几位开始截取,一直截取到最后。
如果 arr.slice(1) ,从第 1 位开始截取,截取到最后一位.
c.不写参数就是整个截取数组(把类数组转换成数组的时候经常使用到)
11.join 括号里面需要用字符串形式(标准语法规定),就会用加的东西连接起数组。join 里面不传参默认用逗号连接。
join 可逆的东西:split( )是 string 字符串方法
split 按照什么拆分为数组。用什么拆,什么就没了,按-拆就去掉-,按 4 拆就去掉 4。
split 可以返回数组,数组可以返回字符串
3.10.3类数组
- 可以利用属性名模拟数组的特性
- 可以动态的增长 length 属性
- 如果强行让类数组调用 push 方法,则会根据 length 属性值的位置进行属性的扩充。
类数组:属性要为索引(数字)属性,必须要有 length 属性,最好加上 push 方法。
3.11 报错
3.11.1try…catch
try 花括号{里面会正常执行,但是遇到 b 报错时 b 就执行不出来,后面的代码 c 就不执行了,但是外面的代码 d 还能执行}catch(e){ },这个 e 可以随便写,写 abc 都可以,也是个形参
3.11.2Error.name 的六种值对应的信息:
- EvalError:eval()的使用与定义不一致
//eval 是不被允许使用的 - RangeError:数值越界
- ReferenceError:非法或不能识别的引用数值
//未经声明就使用,没有定义就使用 - SyntaxError:发生语法解析错误
// Syntax 是语法解析() - TypeError:操作数类型错误
- URIError:URI 处理函数使用不当
//引用地址错误
3.11.3es5.0 严格模式
浏览器是基于 es3.0 和 es5.0 的新增方法使用的。
如果两种发生了冲突,就用 es3.0。
es5.0 严格模式是指 es3.0 和 es5.0 产生冲突发部分就是用 es5.0,否则就用 es3.0。
- “use strict” ;不再兼容 es3 的一些不规则语法。使用全新的 es5 规范。两种用法:
1.全局严格模式
2.局部函数内严格模式(推荐)
就是一行字符串,不会对不兼容严格模式的浏览器产生影响。
不支持 with,arguments.callee,function.caller,变量赋值前必须声明,局部 this必须被赋值(Person.call(null/undefined) 赋值什么就是什么),拒绝重复属性和参数
caller函数对象的一个属性,指向调用当前函数的函数。比如 A() 调用 B(), 则在B()中 B.caller 指向A()。
callee是arguments对象的一个属性,指向 arguments 对象的函数,即当前函数。在例子中是XX。
with(){ }可以改变作用域链。{}里面的代码会按照正常顺序执行,但是如果在括号里面添加了对象,就会把对象当做 with 要执行的代码体的作用域链的最顶端(最直接的最近的 AO)。
四.DOM
4.1什么是DOM
1.DOM — > Document Object Model(文档对象模型)
2.DOM 定义了表示和修改文档所需的方法(对象、这些对象的行为和属性以及这些对象之间的关系。)DOM 对象即为宿主对象,由浏览器厂商定义,用来操作 html和 xml 功能的一类对象的集合。也有人称 DOM 是对 HTML 以及 XML 的标准编程接口
dom 不能改变 css 样式表,可以间接改变行间样式的 css
4.2DOM基本操作(大部分都是类数组)——方法类操作
document 代表整个文档(如果给 html 标签上面再套一层标签就是 document)
4.2.1对节点的增删改查
注意哪怕整个文档只有一个 demo,也要加[0],不然选出来的就是一个组
- document.getElementById() //元素 id 在 Ie8 以下的浏览器,不区分 id 大小写,而且也返回匹配 name 属性的元素,通过 id 标识我们来选择这个元素,一一对应
- getElementsByTagName() //标签名,这是一个类数组,最主流的用法,经常用
- getElementsByName(); //IE 不支持需注意,只有部分标签 name 可生效(表单,表单元素,img,iframe),不是在所有的浏览器都能用——开发一般不用
- .getElementsByClassName() // 类名 ->缺点: ie8 和 ie8 以下的 ie 版本中没有,可以多个 class 一起,不是所有浏览器都能用
- .querySelector() // css 选择器,只能选一个,在 ie7 和 ie7 以下的版本中没有
- .querySelectorAll() // css 选择器,全选,选一组,在 ie7 和 ie7 以下的版本中没有
querySelectorAll()和.querySelector()选出来的元素不是实时的(是静态的),所以一般不用,其他的再怎么修改,跟原来的没有关系
4.3DOM基本操作——非方法类操作
4.3.1遍历节点树
- parentNode → 父节点 (最顶端的 parentNode 为#document);
- childNodes → 子节点们(直接的节点数)节点包括文本节点,属性节点
- firstChild → 第一个子节点
- lastChild → 最后一个子节点
- nextSibling →后一个兄弟节点
- previousSibling → 前一个兄弟节点
4.3.2节点的类型
元素节点 —— 1
属性节点 —— 2 (基本没用,)
文本节点 —— 3
注释节点 —— 8
document —— 9
DocumentFragment —— 11
后面的数字是调用 nodeType 返回的数字
规范化
4.3.3基于元素节点树的遍历(不含文本节点)
- parentElement -> 返回当前元素的父元素节点 (IE 不兼容)
- children -> 只返回当前元素的元素子节点
- node.childElementCount === node.children.length 当前元素节点的子元素节点个数(IE 不兼容)——基本不用,因为与 length 相等
- firstElementChild -> 返回的是第一个元素节点(IE 不兼容)
- lastElementChild -> 返回的是最后一个元素节点(IE 不兼容)
- nextElementSibling / previousElementSibling ->返回后一个/前一个兄弟元素节点(IE 不兼容)
除 children 外,parentElement、node.childElementCount、firstElementChild、lastElementChild、nextElementSibling、 previousElementSibling 在 ie9 及以下不兼容。真正常用的就是 children,兼容性好
4.3.4 每一个节点的四个属性
- nodeName元素的标签名,以大写形式表示,只读,不能写
- nodeValue Text 文本节点或 Comment 注释节点的文本内容,可读写
- nodeType(最有用)该节点的类型,只读返回这个 div 的所有的元素节点
- attributes Element 节点的属性集合
属性名不能改,属性值可以改,但是我们一般不用这种方法
我们一般用 getAttribute 和 setAttribute 去取。节点的一个方法
Node.hasChildNodes();——他有没有子节点,返回值是 true 或 false
4.3.5 DOM接口
dom 结构树代表的是一系列继承关系
document 继承自 HTMLDocument.prototype。HTMLDocument.prototype 继承自 Document.prototype
DOM 结构树中,Node 也是构造函数,comment 是注释HTMLDocument 和 HTMLElement 实际上并列了对应的XML,但是因为不用了 XML就省略了。HTMLHeadElement 就是 head 标签,其余类推。
4.4 DOM基本操作
4.4.1常用操作注意
- getElementById 方法定义在 Document.prototype 上,即 Element 节点上不能使用。
- getElementsByName 方法定义在HTMLDocument.prototype 上,即非 html 中的document 以外不能使用(xmldocument,Element)
- getElementsByTagName 方法定义在 Document.prototype 和 Element.prototype 上
- HTMLDocument.prototype 定义了一些常用的属性,body,head,分别指代 HTML 文档中的标签。
- Document.prototype 上定义了 documentElement 属性,指代文档的根元素,在 HTML文档中,他总是指代元素
- getElementsByClassName、querySelectorAll、querySelector 在 Document,Element 类
4.4.2 增
document.createElement(); //增加或创建元素节点(标签)——常见
document.createTextNode(); //创建文本节点
document.createComment(); //创建注释节点
document.createDocumentFragment(); //创建文档碎片节点
4.4.3 插——剪切操作
PARENTNODE.appendChild(); 可以理解成.push
PARENTNODE.insertBefore(a, b);一定是 div 先 insert a,before b(剪切效果)
4.4.4 删
parent.removeChild(); //返回移除子元素,就是被剪切出来了
child.remove(); //自尽,完全删除
4.4.5 替换
parent.replaceChild(new, origin); //用新的 new 去置换旧的 origin
4.4.6Element 节点的一些属性和方法
- 属性:
innerHTML ==> 可取,可写,可赋值
innerText ==> 可取,可赋值 (老版本火狐不兼容) / textContent(火狐使用这个,老版本 IE 不好使) - 方法:
ele.setAttribute(“属性”,“值”) //设置
ele.getAttribute(“属性”); //取这个值
4.6Date()
就是一种对象,是系统提供好的
var date = new Date()大写的 Date 是系统提供的一个构造函数,通过 new Date 的方法会给我们返回一个对象,这个对象就是一个日期对象。日期对象有很多属性和方法。小的 date 代表此时此刻的时间。用小的 date 调用方法,如 date.getDate( )
4.6.1Date对象方法
- Date() 返回当日的日期和时间。
- getDate() 制造出对象,从 Date 对象返回一个月中的某一天 (1 ~ 31)。
- getDay() 今天是一周的第几天,如果是 2 是星期二,但是是指三天(第一天是周日,也就是 0)。从 Date 对象返回一周中的某一天 (0 ~ 6)。
- getMonth() 一月份返回值是 0,从 Date 对象返回月份 (0 ~ 11)。
- getFullYear() 从 Date 对象以四位数字返回年份。
- getYear() 已废弃。请使用 getFullYear() 方法代替。
- getHours() 返回 Date 对象的小时 (0 ~ 23)。
- getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
- getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
- getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
- getTime() 最有用 返回 1970 年 1 月 1 日(纪元时刻)至今的毫秒数。经常用于项目的计算时间。获取时间戳
- setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。
- setMonth() 设置 Date 对象中月份 (0 ~ 11)。
- setFullYear() 设置 Date 对象中的年份(四位数字)
- setYear() 请使用 setFullYear() 方法代替。
- setHours() 设置 Date 对象中的小时 (0 ~ 23)。
- setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。
- setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。
- setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。
- setTime() 以毫秒设置 Date 对象。机械之间交换时间
- toSource() 返回该对象的源代码。
- toString() 把 Date 对象转换为字符串。
- toTimeString() 把 Date 对象的时间部分转换为字符串。
- toDateString() 把 Date 对象的日期部分转换为字符串。
在控制台调用 date.getSeconds 就是 date 创建时间的毫秒数,是静止的,不是动态的。
这个 date 对象记录的是出生的那一刻的时间,不是实时的
4.6.2js定时器 - setInterval(); //注意:setInterval(“func()”,1000);定时循环器
- 如果先定义 1000 毫秒,在后面改成 2000 毫秒,程序仍按 1000 毫秒执行,因为他只识别一次,不能通过改变 time 改变 setInterval 的快慢。
setInterval 计算时间非常不准
注意:setInterval();是 window 的方法,在全局上就算不写 window. setInterval();他也会上全局的 GO 里面查找,所以不写 window.也行。
每一个 setInterval();都会返回一个数字,作为唯一的标识,有唯一标识就可以把他清除掉(利用 clearInerval 清除) - clearInterval(); //能让 setInterval 停止
一般写了 setInterval 就要写 clearInterval - setTimeout(); //正真的定时器,隔了一段时间后再执行(起推迟作用),并且只执行一次。返回一个数字做唯一标识。标识不会重叠。
- clearTimeout(); //清除 setTimeout();让他停止执行
- 这种写法,setTimeout();还没执行就被清除了,就执行不了
setInterval();setTimeout();clearInterval();clearTimeout();这四个都是全局对象,都是window 上的方法,内部函数 this 指向 window
4.7 DOM/BOM基本操作
4.7.1 查看滚动条的滚动距离
- window.pageXOffset 横向/pageYOffset 纵向滚动条
IE8 及 IE8 以下不兼容(IE9 部分兼容)IE9 以上能用 - IE8 及 IE8 以下的使用方法
1)document.body.scrollLeft/scrollTop——求横向距离和纵向距离
2)document. documentElement.scrollLeft/scrollTop
上面两个兼容性比较混乱,其中一个有值,另外一个的值一定是 0。这两个最好的用法是取两个值相加,因为不可能存在两个同时有值
如 document.body.scrollLeft + document. documentElement.scrollLeft - 封装兼容性方法(哪个浏览器都好用),求滚动轮滚动距离 getScrollOffset()——求滚动条的位置
function getScrollOffset(){
if(window.pageXOffset){
return{
x : window.pageXOffset,
y : window.pageYOffset
}
}else{
return{
x : document.body.scrollLeft + document.documentElement.scrollLeft,
y : document.body.scrollTop + document.documentElement.scrollTop
}
}
}
4.7.2 查看视口的尺寸
可视区窗口就是编写的 html 文档可以看到的部分,不含菜单栏、地址栏、控制台
- window.innerWidth/innerHeight 可视区域的宽高 (加上 滚动条宽度 / 高度)IE8 及 IE8 以下不兼容 //w3c 标准方法
注意渲染模式:
1 标准模式:<!DOCTYPE html>是 html5 的(在 emmet 插件下 html:5 就出来了)
2 怪异/混杂模式:试图去兼容之前的语法,去掉<!DOCTYPE html>这一行即可开
启(向后兼容)
2、document.documentElement.clientWidth/clientHeight
标准模式下,任意浏览器都兼容 client 是客户端的意思
3、document.body.clientWidth/clientHeight
适用于怪异模式下的浏览器
4、封装兼容性方法,返回浏览器视口尺寸 getViewportOffset()
document.compatMode 是用于判断是怪异模式还是标准模式的
"CSS1Compat"标准模式 ''BackCompat"怪异模式向后兼容
function getViewportOffset(){
if(window.innerWidth){
return{
w : window.innerWidth,
h : window.innerHeight
}
}else{
if(document.compatMode ==="BackCompat"){
return {
w : window.innerWidth,
h : window.innerHeight
}
}else{
return {
w : document.documentElement.clientWidth,
h : document.documentElement.clientHeight
}
}
}
}
}
4.7.3 查看元素的几何尺寸
- domEle.getBoundingClientRect(); //这是 es5.0 的方法,但是只用了解
- 兼容性很好
- 该方法返回一个对象,对象里面有 left,top,right,bottom 等属性。left 和 top 代表该元素左上角的 X 和 Y 坐标,right 和 bottom 代表元素右下角的 X 和 Y 坐标
- height 和 width 属性老版本 IE 并未实现在老版本的 ie 里面,利用右侧边减左侧面解决
- 返回的结果并不是“实时的”
4.7.4 查看元素的尺寸
dom.offsetWidth,dom.offsetHeight
求得值是包括 padding 的
4.7.5 查看元素位置
- dom.offsetLeft, dom.offsetTop
对于无定位父级的元素,返回相对文档的坐标。
对于有定位父级的元素,返回相对于最近的有定位的父级的坐标。(无论是 left 还是margin-left 等都是距离。 ) - dom.offsetParent
返回最近的有定位的父级,如无,返回 body, body.offsetParent 返回 null这个方法能求有定位的父级
4.7.6 让滚动条滚动
- window 上有三个方法 scroll(), scrollTo(),两个功能一样,scrollBy();累加滚动距离
scroll(x,y), scrollTo(x,y),功能是一样的,里面能填两个参数
scroll(x 轴滚动条的距离,y 轴滚动条的距离),里面的 xy 可以填负数
scrollBy(x,y);是累加滚动距离,填负数就往上滚动
2、三个方法功能类似,用法都是将 x,y 坐标传入。即实现让滚动轮滚动到当前位置。
3、区别:scrollBy()会在之前的数据基础之上做累加。
eg:利用 scrollBy() 快速阅读的功能
五.学习心得
js是前端学习的重中之重,内容很多,入门虽然简单但是常常会忽视掉一些底层的原理。学习js一定要注意底层原理,开发中可能一个不小心就给调试带来很大的麻烦。在学习的时候要求精,不要一味追求速度。