之前在慕课网上看了看JavaScript的教程,但是整个教程的内容不够详细,因此在廖雪峰官方网站看看关于js的教程,并重新学习和记录如下。
js用于在静态HTML页面上添加一些动态效果 ,网景公司的Brendan Eich这哥们在两周之内设计出了JavaScript语言 。为了让js称为全球标砖,欧洲计算机制造协会(European Computer Manufacturers Association)制定了js的标准,称为RCMAscript标准,最新版ECMAscript 6标准于2015年6月发布(简称ES6)。
快速入门
js代码一般放在<head>
当中,由封闭的<script>...</script>
包含起来
第二种是将js放在一个单独的js文件中,然后在head中声明该文件
1 | <head> |
有时候会看到定义js的类型,<script type="text/javascript">
,但是实际上是没有必要的,因为默认的script的类型就是javascript
基础语法
每一句以分号(‘;’)结束,语句块用大括号括起来
//表示注释,/*…*/也表示注释
数据类型和变量
Number
js不区分整数和浮点数,统一用Number表示
字符串
字符串是以单引号或双引号引起来的任何文本,比如’abc’或者”xyz”。如果引号里面还有引号,那么就要用到转义字符\
,ASCII字符可以用\x##
表示,例如:
1 | '\x41'; // 完全等同于 'A' |
还可以用\u####
表示一个Unicode字符:
1 | '\u4e2d\u6587'; // 完全等同于 '中文' |
多行字符串可以用反引号表示,也就是数字1左边那个键
1 | console.log(`多行 |
多个字符串连接起来跟python一样用加号+
就可以了,也可以跟shell脚本一样用变量名来代替,比如:
1 | var name = '小明'; |
操作字符串
获取字符串长度用.length
,如果要获取slice,跟python的list方法一样,要注意,字符串本身是不可以变动的,对某个slice赋值不会改变本身:
1 | var s = 'Test'; |
还有一些函数用于操作字符串
toUpperCase()
:字符串变大写toLowerCase()
:字符串变小写indexOf()
:搜索指定字符串出现的位置,如果没找到则返回-11
2
3var s = 'hello, world';
s.indexOf('world'); // 返回7
s.indexOf('World'); // 没有找到指定的子串,返回-1substring()
:返回指定索引区间的子串,类似于python使用冒号的slice方法1
2
3var s = 'hello, world'
s.substring(0, 5); // 从索引0开始到5(不包括5),返回'hello'
s.substring(7); // 从索引7开始到结束,返回'world'
布尔值
布尔值只有true和false两种,可以直接使用true,false来表示,也可以使用布尔运算来计算出来(比如大小比较或者与或非),js的与运算是&&,或运算是||,非运算是!
比较运算符
大小比较与其他语言没有区别,但是js有个特殊的等于比较,两个等号”==”会自动转换类型之后再比较,而三个等号”===”不会自动转换类型,由于JavaScript这个设计缺陷,不要使用==
比较,始终坚持使用===
比较。
1 | false == 0; // true |
还有一个问题就是NaN与任何值都不相等,包括他自己
1 | NaN === NaN; // false |
唯一判断NaN的方法就是使用isNaN()
函数
浮点数运算的相等比较中,由于浮点数运算会出现误差,因此计算机无法精确标识无限循环小数,要比较两个浮点数是否相等,智能计算他们之间的绝对值,看是否小于某个阈值
1 | 1 / 3 === (1 - 2 / 3); // false |
null和undefined
null表示空值,与0和空字符串''
都是不同的,null和undefined大致类似,大多数情况下都应该用null
,undefined
只有在判断函数参数是否传递的情况下有用
数组
js的数组和python的list类似,可以包含任意类型的数据,例如:
1 | [1, 2, 3.14, 'Hello', null, true]; |
另一种创建数组的方法是通过Array()
函数实现
1 | new Array(1,2,3);// 创建了数组[1, 2, 3] |
更建议直接使用方括号[]
来建立数组,数组索引也和python类似,起始索引为0
1 | var arr = [1, 2, 3.14, 'Hello', null, true]; |
数组同样用length来获取长度,如果对array的length赋值的话会改变数组的内容,没有定义的内容全为undefined,如果变短则截断
1 | var arr = [1, 2, 3]; |
Array可以通过索引把对应的元素改为新的值
1 | var arr = ['A', 'B', 'C']; |
请注意,如果通过索引赋值时,索引超过了范围,同样会引起Array
大小的变化:
1 | var arr = [1, 2, 3]; |
indexOf
Array也可以用indexOf来获取某个元素的位置
slice
slice()
对应String的substring()
方法,用于切片
push和pop
push()
是在array末尾添加元素,pop()
是把array最后一个元素返回出来
unshift和shift
unshift()
:在array头部添加若干元素
shift()
:将array的第一个元素删除掉并返回出来
unshift和shift相当于push和pop作用在array头部
1 | var arr = [1, 2]; |
sort
对array进行排序
reverse
元素顺序反转
1 | var arr = ['one', 'two', 'three']; |
splice
splice()
是array的万能方法,可以从指定索引删除若干元素,然后从该位置再添加若干元素
1 | var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle']; |
concat
把两个array连接起来,并返回一个新的array
1 | var arr = ['A', 'B', 'C']; |
join
join和python的join方法效果一样,使用方法如下
1 | var arr = ['A', 'B', 'C', 1, 2, 3]; |
多维数组
多维数组和python的list里面的list一样
1 | var arr = [[1, 2, 3], [400, 500, 600], '-']; |
取数组元素作为变量
取数组元素作为变量应该用${array[i]}
这样的形式
1 | var arr = ['小明', '小红', '大军', '阿黄']; |
注意这里的`号,不是单引号,单引号无法得到变量,全部视为字符串
对象
js的对象是由一组键值对组成的字典,与python中的字典类型基本一样:
1 | var person = { |
js对象的键都是字符串类型,值可以是任何类型,要获取一个对象的属性,就直接用对象变量.属性名
的方式:
1 | person.name; // 'Bob' |
如果某个对象的key是字符串类型,访问的时候就只能跟python的字典一样,用object['key']
来访问
1 | var xiaohong = { |
如果访问不存在的元素,那么返回的就是undefined
你可以随意给对象添加或者是删除属性,通过delete进行删除,还可以通过in
来判断某个属性是否在某个对象中
1 | var xiaoming = { |
但是用in
判断有风险,因为如果是继承得到的属性也会被判断为自身的。要判断是否自身的属性, 应该用hasOwnProperty()
方法:
变量
js的变量要以var定义,变量名是大小写英文、数字、$
和_
的组合 ,不能以数字开头
用等号对变量赋值,但一个变量只需要初始化一次
1 | var a = 123; // a的值是整数123 |
strict模式
如果不用var进行初始化的话,那么变量将是全局变量,这会导致很严重的错误
ECMA为了修补js的这一严重缺陷,在后续退出了strict模式,如果不用var初始化变量将会报错,启用strict模式的方法是在js代码的第一行写上
1 | 'use strict'; |
条件判断
js用if{...} else if{...}
的形式来进行条件判断,例如
1 | if (age >= 6) { |
JavaScript把null
、undefined
、0
、NaN
和空字符串''
视为false
,其他值一概视为true
,因此上述代码条件判断的结果是true
。
循环
js的循环和c语言当中的是一样的
1 | var x = 0; |
for
循环最常用的地方是利用索引来遍历数组:
1 | var arr = ['Apple', 'Google', 'Microsoft']; |
for
也可以用break来退出
js当中的for
也可以用python当中的in
的形式:for ... in
1 | var o = { |
要过滤掉对象继承的属性,用hasOwnProperty()
来实现:
1 | var o = { |
for in 数组的话,得到的是索引,因为数组的索引被视为属性
1 | var a = ['A', 'B', 'C']; |
Map和Set
js中的Map相当于python中的字典,由键值对组成
初始化一个map需要一个二维数组或者是初始化为空map,用set
添加键值对,用has
确认是否含有某个键,用get
取对应键的值
1 | var m = new Map(); // 空Map |
Set
就是python当中的集合,不允许重复
iterable
因为for in
语法不适用于Map和Set(因为他们不可以通过下标遍历),因此有了for ... of
循环遍历
1 | var a = ['A', 'B', 'C']; |
然而,更好的遍历方式是使用iterable
内置的forEach
方法,接收一个函数,每次迭代自动回调该函数
1 | var a = ['A', 'B', 'C']; |
Set
与Array
类似,但Set
没有索引,因此回调函数的前两个参数都是元素本身:
1 | var s = new Set(['A', 'B', 'C']); |
Map
的回调函数参数依次为value
、key
和map
本身:
1 | var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); |
函数
在js中,函数定义的方法如下
1 | function abs(x){ |
如果没有return结果,那么函数的返回值是undefined
还有一种函数的定义方法是把函数赋值给一个变量名
1 | var abs = function (x){ |
js允许传入任意个函数参数,如果比定义的多,只会调用定义的那个参数,如果比定义的少,那么会返回NaN
1 | abs(10); // 返回10 |
要避免收到undefined
,可以对参数进行检查:
1 | function abs(x) { |
arguments
js本身还定义了一个参数是arguments,指向传入的所有参数,形式跟array一样:
1 | function foo(x) { |
rest
js还定义了rest参数,用于获取除了已定义参数之外的所有参数
1 | function foo(a, b, ...rest) { |
est参数只能写在最后,前面用...
标识,
函数作用域
函数内定义的是局部变量,不可以在函数外使用,跟其他编程语言规定是一样的
变量提升
js的变量声明会提到最前面进行编译,但是变量赋值并不会提升
1 | function foo() { |
上面这段代码不报错,但是显示的是Hello,undefined
js引擎看到的是如下的结构
1 | function foo() { |
全局作用域
js当中未定义在函数体中的变量都是全局变量,绑定在window这个对象上
1 | var course = 'Learn JavaScript'; |
名字空间
全局变量会绑定到window
上,不同js文件如果用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,减少冲突的好办法就是把所有的变量和函数全不绑定到一个全局变量中,如:
1 | // 唯一的全局变量MYAPP: |
局部作用域
因为js的变量作用域是函数内部,因此类似于c++的for循环当中定义i
的方法,在结束了for之后还是可以调用i
的,如下:
1 | function foo() { |
因此ES6引入了let
关键字
1 | function foo() { |
常量
ES6引入了const
用于定义常量,常量无法修改
1 | const PI = 3.14; |
同时对多个变量赋值
ES6引入可以同时对多个变量赋值的机制,对多个变量赋值的时候,这些变量要用方括号[]
引起来:
1 | var [x, y, z] = ['hello', 'JavaScript', 'ES6']; |
解构赋值还可以忽略某些元素:
1 | let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素 |
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性,在对对象进行解构赋值的时候,用大括号{}
把变量扩起来:
1 | var person = { |
如果对应的属性不存在将会被定义为undefined,如果你要将某个变量拿出来赋给其他值,可以用冒号:
1 | var person = { |
解构赋值还可以使用默认值,这样就避免出现undefined的情况:
1 | var person = { |
解构赋值在用于已经定义好的变量的时候,不能直接以{}
开头,因为js会认为以{
开头的内容是块元素,=
不能对块元素赋值,解决办法是用小括号()
括起来:
1 | // 声明变量: |
方法
在一个对象中绑定一个函数,称为这个对象的方法
1 | var xiaoming = { |
这个age()
就是一个方法,this
就是类定义的this
只有object.funciton()
这样的调用形式才能触发this
对于没有定义的this,在strict模式下指向undefined,在非strict模式下指向window
apply
apply
用于显示地指定this,第一个参数就是需要绑定的this
变量,第二个参数是Array
,调用形式是function.apply(this, Array)
1 | function getAge() { |
另一个与apply()
类似的方法是call()
,唯一区别是:
apply()
把参数打包成Array
再传入;call()
把参数按顺序传入。
比如调用Math.max(3, 5, 4)
,分别用apply()
和call()
实现如下:
1 | Math.max.apply(null, [3, 5, 4]); // 5 |
方法
阅读: 141906
在一个对象中绑定函数,称为这个对象的方法。
在JavaScript中,对象的定义是这样的:
1 | var xiaoming = { |
但是,如果我们给xiaoming
绑定一个函数,就可以做更多的事情。比如,写个age()
方法,返回xiaoming
的年龄:
1 | var xiaoming = { |
绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this
关键字,这个东东是什么?
在一个方法内部,this
是一个特殊变量,它始终指向当前对象,也就是xiaoming
这个变量。所以,this.birth
可以拿到xiaoming
的birth
属性。
让我们拆开写:
1 | function getAge() { |
单独调用函数getAge()
怎么返回了NaN
?请注意,我们已经进入到了JavaScript的一个大坑里。
JavaScript的函数内部如果调用了this
,那么这个this
到底指向谁?
答案是,视情况而定!
如果以对象的方法形式调用,比如xiaoming.age()
,该函数的this
指向被调用的对象,也就是xiaoming
,这是符合我们预期的。
如果单独调用函数,比如getAge()
,此时,该函数的this
指向全局对象,也就是window
。
坑爹啊!
更坑爹的是,如果这么写:
1 | var fn = xiaoming.age; // 先拿到xiaoming的age函数 |
也是不行的!要保证this
指向正确,必须用obj.xxx()
的形式调用!
由于这是一个巨大的设计错误,要想纠正可没那么简单。ECMA决定,在strict模式下让函数的this
指向undefined
,因此,在strict模式下,你会得到一个错误:
1 | 'use strict'; |
这个决定只是让错误及时暴露出来,并没有解决this
应该指向的正确位置。
有些时候,喜欢重构的你把方法重构了一下:
1 | 'use strict'; |
结果又报错了!原因是this
指针只在age
方法的函数内指向xiaoming
,在函数内部定义的函数,this
又指向undefined
了!(在非strict模式下,它重新指向全局对象window
!)
修复的办法也不是没有,我们用一个that
变量首先捕获this
:
1 | 'use strict'; |
用var that = this;
,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。
apply
虽然在一个独立的函数调用中,根据是否是strict模式,this
指向undefined
或window
,不过,我们还是可以控制this
的指向的!
要指定函数的this
指向哪个对象,可以用函数本身的apply
方法,它接收两个参数,第一个参数就是需要绑定的this
变量,第二个参数是Array
,表示函数本身的参数。
用apply
修复getAge()
调用:
1 | function getAge() { |
另一个与apply()
类似的方法是call()
,唯一区别是:
apply()
把参数打包成Array
再传入;call()
把参数按顺序传入。
比如调用Math.max(3, 5, 4)
,分别用apply()
和call()
实现如下:
1 | Math.max.apply(null, [3, 5, 4]); // 5 |
对普通函数调用,我们通常把this
绑定为null
。
装饰器
利用apply()
,我们还可以动态改变函数的行为。
JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。
现在假定我们想统计一下代码一共调用了多少次parseInt()
,可以把所有的调用都找出来,然后手动加上count += 1
,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt()
:
1 | ; |
高阶函数
js的最基础的高阶函数,就是把一个函数作为另一个函数的参数
1 | function add(x, y, f) { |
map/reduce
js的map/reduce和python的基本一样,只是调用方法略有区别,是x.map(function)
1 | var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; |
1 | var arr = [1, 3, 5, 7, 9]; |
filter
用于把array的某些元素过滤掉
1 | var arr = [1, 2, 4, 5, 6, 9, 10, 15]; |
sort
sort方法用于排序
1 | // 看上去正常的结果: |
因为sort的这种默认的排序往往不能达到要求,因此需要自己定义sort当中的条件函数
1 | var arr = [10, 20, 1, 2]; |
返回1的时候表示要换位置,返回-1表示不换位置
闭包
闭包就是在一个函数内部再定义一个函数,执行函数的时候返回的不是值,而是函数
1 | //普通的求和函数 |
匿名函数
创建一个函数并立即执行的方法称为匿名函数
1 | (function (x) { return x * x }) (3);//由于js语法限制,要用小括号括起来 |
箭头函数
ES6新增的一种函数
1 | x => x * x; |
上面的箭头函数相当于:
1 | function (x) { |
参数不止一个的时候要用括号括起来:
1 | // 两个参数: |
如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
1 | // SyntaxError: |
生成器
生成器和python当中的类似,用yield返回,用next访问
标准对象
js中所有都是对象,用typeof
来查看对象类型
1 | typeof 123; // 'number' |
包装对象
js提供包装对象,包装对象的关系就像java当中的int
和Intenger
的关系,Intenger
这种包装对象要用new
来创建,js当中的number
、boolean
和string
都有包装对象 ,就是首字母大写,虽然包装对象看上去和原来的值一模一样,显示出来也是一模一样,但他们的类型已经变为object
了!所以,包装对象和原始值用===
比较会返回false
:
1 | var n = new Number(123); // 123,生成了新的包装类型 |
如果在使用Number
、Boolean
和String
时,没有写new
,那么这三个函数就是类型转换函数
注意:
- 不要使用
new Number()
、new Boolean()
、new String()
创建包装对象; - 用
parseInt()
或parseFloat()
来转换任意类型到number
; - 用
String()
来转换任意类型到string
,或者直接调用某个对象的toString()
方法; - 通常不必把任意类型转换为
boolean
再判断,因为可以直接写if (myVar) {...}
; typeof
操作符可以判断出number
、boolean
、string
、function
和undefined
;- 判断
Array
要使用Array.isArray(arr)
; - 判断
null
请使用myVar === null
; - 判断某个全局变量是否存在用
typeof window.myVar === 'undefined'
; - 函数内部判断某个变量是否存在用
typeof myVar === 'undefined'
。
Date
js中Date
对象用于获取日期和时间:
1 | var now = new Date(); |
如果要创建一个指定日期和时间的Date
对象,可以用:
1 | var d = new Date(2015, 5, 19, 20, 15, 30, 123); |
**JavaScript的月份范围用整数表示是0~11,0
表示一月,1
表示二月……,所以要表示6月,我们传入的是5
! **
第二种创建一个指定日期和时间的方法是解析一个符合ISO 8601格式的字符串:
1 | var d = Date.parse('2015-06-24T19:49:22.875+08:00'); |
但它返回的不是Date
对象,而是一个时间戳。不过有时间戳就可以很容易地把它转换为一个Date
:
1 | var d = new Date(1435146562875); |
时区
浏览器可以把时间戳正确转换为本地时间
时间戳是个什么东西?时间戳是一个自增的整数,它表示从1970年1月1日零时整的GMT时区开始的那一刻,到现在的毫秒数。假设浏览器所在电脑的时间是准确的,那么世界上无论哪个时区的电脑,它们此刻产生的时间戳数字都是一样的,所以,时间戳可以精确地表示一个时刻,并且与时区无关。
1 | var d = new Date(1435146562875); |
获取时间戳的方法如下:
1 | new Date().getTime() |
正则表达式
js当中的正则表达式的写法和python是一样的,创建正则表达式的方法有两种
第一种是直接通过/正则表达式/
写出来,第二种方式是通过new RegExp('正则表达式')
创建一个RegExp对象
re.test(string)
方法用于判断正则表达式是否匹配,这个re就是一个正则表达式对象
1 | var re = /^\d{3}\-\d{3,8}$/; |
切分字符串
js切分字符串也是用split()
实现的,用这则表达式可以通过任意形式切分
1 | //通过空格切分 |
提取子串
js用exec
提取子串,子串在正则表达式中用括号括起来
exec()
方法在匹配成功后,会返回一个Array
,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。
1 | var re = /^(\d{3})-(\d{3,8})$/; |
同样?
可以使得正则表达式进行非贪婪匹配
全局搜索
js的正则表达式有几个特殊的标志,最常用的是g
,表示全局匹配
1 | var r1 = /test/g; |
全局匹配可以多次执行exec()
方法来搜索一个匹配的字符串。当我们指定g
标志后,每次运行exec()
,正则表达式本身会更新lastIndex
属性,表示上次匹配到的最后索引:
1 | var s = 'JavaScript, VBScript, JScript and ECMAScript'; |
JSON
JSON是JavaScript Object Notation的缩写,是一种数据存储格式
在JSON中,一共就这么几种数据类型:
- number:和JavaScript的
number
完全一致; - boolean:就是JavaScript的
true
或false
; - string:就是JavaScript的
string
; - null:就是JavaScript的
null
; - array:就是JavaScript的
Array
表示方式——[]
; - object:就是JavaScript的
{ ... }
表示方式。
为了统一解析,JSON的字符串规定必须用双引号""
,Object的键也必须用双引号""
。
可以用JSON.stringify(object, attribute, format)
将对象变为json
输出,第一个参数是对象名,第二个参数是属性名或者是转换函数,第三个参数用于控制格式(一般是有多少个空格)
1 | var xiaoming = { |
结果:
1 | { |
如果第二个参数是转化函数
1 | function convert(key, value) { |
上面的代码把所有属性值都变成大写:
1 | { |
反序列化
如果你拿到一个JSON
字符串,可以用JSON.parse()
将其转换为js对象
1 | JSON.parse('[1,2,3,true]'); // [1, 2, 3, true] |
parse还可以加上一个处理函数
1 | var obj = JSON.parse('{"name":"小明","age":14}', function (key, value) { |
JS面向对象
JS没有class的概念,如果要进行继承要用Object.create()
方法,实质就是将一个类的prototype指向另一个类
1 | var Student = { |
在编写JavaScript代码时,不要直接用obj.__proto__
去改变一个对象的原型。Object.create()
方法可以传入一个原型对象,并创建一个基于该原型的新对象
1 | // 原型对象: |
构造函数
new
一个对象,就是构造函数,如果不写new,那么就是一个普通函数,返回的是undefined
1 | function Student(name) { |
新创建的xiaoming的原型链是:
1 | xiaoming ----> Student.prototype ----> Object.prototype ----> null |
原型继承
class继承
原型继承章节比较难,之后会回过来看
ES6引入了class关键字,可以直接包含构造函数和定义在原型上的其他函数
1 | class Student { |
有了class之后,直接用extends就可以继承,调用父类方法直接用super
1 | class PrimaryStudent extends Student { |
浏览器
js可以获取浏览器对象并对其操作,window
不光是全局作用域,还表示浏览器窗口,window
对象有innerWidth
和innerHeight
属性 ,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高。
1 | console.log('window inner size: ' + window.innerWidth + ' x ' + window.innerHeight); |
navigator
通常包含的是浏览器信息,常用的属性包括:
- navigator.appName:浏览器名称;
- navigator.appVersion:浏览器版本;
- navigator.language:浏览器设置的语言;
- navigator.platform:操作系统类型;
- navigator.userAgent:浏览器设定的
User-Agent
字符串。
操作DOM
HTML文件被浏览器解析为一棵DOM(Document Object Model)树,要改变HTML的结构,就要用js来操作DOM
对DOM的操作主要有以下几种:
- 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
- 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
- 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
- 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
拿到DOM节点和之前用selenium
写爬虫的方法基本是一致的,方法主要有document.getElementById()
和document.getElementsByTagName()
,以及CSS选择器document.getElementsByClassName()
1 | // 返回ID为'test'的节点: |
还有一种是跟scrapy
写爬虫的时候的query
选择器差不多的语法
1 | // 通过querySelector获取ID为q1的节点: |
修改DOM
直接修改拿到的节点的innerHTML内容,这要把HTML的内容替换进去:
1 | // 获取<p id="p-id">...</p> |
还有一种是替换innerText
或者innerContent
,这样替换的只是html标签中间的文字内容,不能改变html内容
1 | // 获取<p id="p-id">...</p> |
两者的区别在于读取属性时,innerText
不返回隐藏元素的文本,而textContent
返回所有文本
还可以通过js修改css样式,直接对对象的Object.style.xxx
进行修改
1 | // 获取<p id="p-id">...</p> |
所有修改的css样式名称用驼峰命名法
插入DOM
如果一个标签原本是空的,你直接修改它的innerHTML
就相当于插入了一个DOM
如果不是空的,就需要用appendChild
方法,将一个子节点加到父节点的最后一个节点
1 | <!-- HTML结构 --> |
把<p id="js">JavaScript</p>
添加到<div id="list">
的最后一项:
1 | var |
现在,HTML结构变成了这样:
1 | <!-- HTML结构 --> |
因为我们插入的js
是从html中获取的,因此相当于把上面的节点append到了下面
当然你也可以通过document.createElement('tag')
来建立某个标签,然后再appendChild
1 | var |
如果要插入到指定位置,那么就用insertBefore
函数,用法是父节点.insertBefore(新节点,参考节点)
,这样就把新节点插到了参考节点之前
1 | var |
删除DOM
删除一个节点只需要得到父节点和本身,然后用父节点.removechild(本身)
移除掉特定的节点
1 | // 拿到待删除节点: |
###js操作表单
js操作表单和操作DOM类似,因为表单本身也是DOM
HTML表单的输入控件主要有以下几种:
- 文本框,对应的
<input type="text">
,用于输入文本; - 密码框,对应的
<input type="password">
,用于输入口令; - 单选框,对应的
<input type="radio">
,用于选择一项; - 复选框,对应的
<input type="checkbox">
,用于选择多项; - 下拉框,对应的
<select>
,用于选择一项; - 隐藏文本,对应的
<input type="hidden">
,用户不可见,但表单提交时会把隐藏文本发送到服务器。
先获取一个表单,然后直接对value赋值,就可以改变value的值
1 | // <input type="text" id="email"> |
这种方式可以应用于text
、password
、hidden
以及select
。但是,对于单选框和复选框,应该用checked
判断是否被勾上,也可以对他们设置值将其勾上:
1 | // <label><input type="radio" name="weekday" id="monday" value="1"> Monday</label> |
HTML5控件
HTML5比标准的HTML多了几种控件,常用的有date
、datetime
、datetime-local
、color
等,它们都使用<input>
标签
1 | <input type="date" value="2015-07-01"> |
提交表单
js有两种方式提交表单,在提交的时候可以对form当中的值进行修改或者是判断是否符合规则
第一种是通过<form>
元素的submit()
方法进行提交
1 | <!-- HTML --> |
这种方式的缺点是扰乱了浏览器对form的正常提交。浏览器默认点击<button type="submit">
时提交表单,或者用户在最后一个输入框按回车键。因此,第二种方式是响应<form>
本身的onsubmit
事件,在提交form时作修改:
1 | <!-- HTML --> |
最后一定要return true
,这样浏览器才会提交表单,如果return false
浏览器就不会提交表单
在检查和修改<input>
时,要充分利用<input type="hidden">
来传递数据。
例如,很多登录表单希望用户输入用户名和口令,但是,安全考虑,提交表单时不传输明文口令,而是口令的MD5。普通JavaScript开发人员会直接修改<input>
:
1 | <!-- HTML --> |
这个做法看上去没啥问题,但用户输入了口令提交时,口令框的显示会突然从几个*
变成32个*
(因为MD5有32个字符)。
要想不改变用户的输入,可以利用<input type="hidden">
实现:
1 | <!-- HTML --> |
注意到id
为md5-password
的<input>
标记了name="password"
,而用户输入的id
为input-password
的<input>
没有name
属性。没有name
属性的<input>
的数据不会被提交。
上传文件
HTML当中上传文件,用到的唯一控件就是<inpt type="file">
注意:当一个表单包含<input type="file">
时,表单的enctype
必须指定为multipart/form-data
,method
必须指定为post
,浏览器才能正确编码并以multipart/form-data
格式发送表单的数据。
一般来说上传文件由后台处理,js可以在提交时对文件名称进行检查,以防止上传无效格式的文件
1 | var f = document.getElementById('test-file-upload'); |
File API
HTML5新增的File API允许js读取文件内容,提供了File
和FileReader
两个主要对象,可以获取文件信息并读取文件
下面这段代码是预览图片并显示相关信息的代码
1 | var |
这一部分的回调函数也不是太懂,之后会再回来看看
AJAX
AJAX(Asynchronous JavaScript and XML )就是异步加载的JavaScript,一般提交一个Form,点击submit之后浏览器就会刷新页面,告诉你成功还是失败,web就是这样,一次HTTP请求对应一个页面
如果你想要用户留在当前页面,同时发出HTTP请求,就必须要用js发送请求,接收到数据后再用js更新页面。这样页面没有刷新,但是数据不断地更新。
AJAX请求是异步执行的,也就是说,要通过回调函数获得响应。
在现代浏览器上写AJAX主要依靠XMLHttpRequest
对象:
1 | function success(text) { |
当创建了XMLHttpRequest
对象后,要先设置onreadystatechange
的回调函数。在回调函数中,通常我们只需通过readyState === 4
判断请求是否完成,如果已完成,再根据status === 200
判断是否是一个成功的响应。
请求第三方网站数据CORS
CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。
只要浏览器的相应的Access-Control-Allow-Origin
包含本域,则此次跨域请求成功
Promise
Promise是一种ajax异步加载,比较难,之后再看
Canvas
canvas可以用来画图
1 | <canvas id="test-canvas" width="300" height="200"></canvas> |
getContext('2d')
方法让我们拿到一个CanvasRenderingContext2D
对象,所有的绘图操作都需要通过这个对象完成。
1 | var ctx = canvas.getContext('2d'); |
左上角为原点,其余为x,y轴开始画图
1 | var |
jQuery
JavaScript 简介
JavaScript 是互联网上最流行的脚本语言,这门语言可用于 HTML 和 web,更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。
每一句后面添加“;”
放在html的head之间:
①<script type="text/javascript"> </script>
;
②<script src="script.js"> </script> ;
直接写入 HTML 输出流
1 | document.write("<h1>这是一个标题</h1>"); |
输出多个内容时与python一样用+连接
输出html标签时(例如输出“<br/>”
),需要用引号扩上并用<>
包围
对事件的反应
1 | <button type="button" onclick="alert('欢迎!')">点我!</button> |
改变 HTML 内容
1 | x=document.getElementById("demo") //查找元素 |
您会经常看到 document.getElementById(“some id“)。这个方法是 HTML DOM 中定义的。
DOM (Document Object Model)(文档对象模型)是用于访问 HTML 元素的正式 W3C 标准。
定义变量
定义变量使用关键词var
,语法如下:
var 变量名
变量名可以任意取名,但要遵循命名规则:
1.变量必须使用字母、下划线(_)或者美元符($)开始。
2.然后可以使用任意多个英文字母、数字、下划线(_)或者美元符($)组成。
3.不能使用JavaScript关键词与JavaScript保留字。
注意:Javascript里面区分大小写,变量mychar和myChar是不同的变量
条件判断语句
语法:
1 | if(条件) |
JavaScript定义函数
关键字function
,用法如下:
1 | function 函数名(){ |
点击按钮出提示的例子:
1 | <!DOCTYPE HTML> |
alert 警告框
alert
是在屏幕上弹出一个警示框,点击确认之后消失,其使用方法如下:
1 |
|
confirm 选择框
confirm
是在屏幕上弹出一个选择框,点击确认返回true,否则返回false
1 |
|
prompt提示框
“”
是弹出一个提示框,同时你可以在这个提示框中输入值并返回
1 |
|
打开新窗口
open()
方法可以查找一个已经存在或者新建的浏览器窗口。语法如下:
1 | window.open([URL], [窗口名称], [参数字符串]) |
1 | 窗口名称:可选参数,被打开窗口的名称。 |
关闭窗口
window.close
关闭窗口
DOM
dom意思是document object model,文档对象模型,是把html代码分割成3类节点:文本节点,属性节点,元素节点的树形结构
通过id寻找元素
document.getElementByid('id')
innerHTML改变html元素内容
用于改变html代码中的内容,通过docment.getElementById
找到元素并赋值给object,然后用object.innerHTML = "new content"
进行赋值
改变html样式
用object.style.property ="xxx"
来改变html中元素的样式,object是通过document.getElementById()
取得的元素对象
显示或隐藏
通过object.style.display = value
,value
的值为none
或者是block
更改类名
通过object.className=“xxx”
改变一个元素的类名
移除style设置
object.removeAttribute("style")
用于移除对元素style的设置