HTML专注于内容,CSS专注于表现,JavaScript专注于行为。
JavaScript术语包含三个部分:
ECMAScript和JavaScript的区别:
ECMAScript是为了规范各种前端脚本语法的标准(后端node.js也包含ECMAScript),JavaScript只是其的一种实现。
共6大数据类型
注意:
typeof(null) === ‘object‘; //true
typeof(somevar) !== "undefined"
NaN!=NaN;//true
,只能通过isNaN(变量)判断是否为数字,而不能通过=
。字符串 | 含义 |
---|---|
\\、\‘、\" | 由于\、‘、"在js中是关键符号,所以需要转义 |
\n | 换行符 |
\r | 回车符 |
\t | 制表符 |
\u | \u后面的字符将会被视为Unicode码 |
if(变量)
时,以下值被当作false。
注意:
null == false; //false
if(‘false‘)
、if(‘0‘)
都为true,因为非空字符串当作true优先级:!> && > || ,但为了可读性,最好加括号。
惰性求值:前面的满足,后面不会执行。
操作符 | 名称 | 说明 | 例子 | |
---|---|---|---|---|
== | 相等运算符 | null == undefined;//true ‘1‘==true; //true ‘1‘==1; //true |
||
=== | 严格相等运算符 | 类型相同&&值相同 | null === undefined; //false 1 === ‘1‘; //false |
|
!= | 不相等运算符 | NaN!=NaN;//true ‘1‘!=1; //false |
||
!== | 严格不相等运算符 | ‘1‘!==1; //true |
||
> | 大于运算符 | ‘2‘>1 ;//true |
||
>= | 大于等于运算符 | 1>=‘1‘; //true |
||
< | 小于运算符 | 1<‘2‘; //true |
||
<= | 小于等于运算符 | 1<=‘1‘; //true |
注意:
例子:
let somevar;
somevar === undefined;//true
1*undefined;//NaN;
1*null;//0
数组为引用类型,typeof([]) === ‘object‘ //true
let a = [2,4,5]
a[4]=6;//跳过了a[3],a[3]将为undefined
delete a[0];//删除后数组长度不变,被删除地方的值变为undefined
a[4]=7
a[0]
注意:
初始化:
let m1 = new Map(); // 空Map
let m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
注意:map的键必须唯一,若加入重复的键,后面的值会冲掉前面的值。
初始化:
let s1 = new Set(); // 空Set
let s2 = new Set([1, 2, 3]); // 含1, 2, 3
注意:
注意:for in循环遍历键,而for of和forEach会遍历键值。
声明式定义
function func(){} //在全局中,或函数中的函数,多用此法定义
函数标识记法
let func = function(){} //函数当作对象一个属性时,用词定义法,如下:
let student = {
name:zhangsan,
study:function(){
console.write('study hard!');
}
}
js中函数也是一种数据(应该属于六种数据类型的object,虽说typeof为‘function‘,而不是‘object‘),故命名规则和变量一样用驼峰,而不是C#中的帕斯卡。
arguments:可以通过索引获取传过来的所有参数,类似数组但不是。
function foo(x) {
for (let i=0; i<arguments.length; i++) {
console.log(arguments[i]);
}
}
rest(ES6规范):获取多余的参数。
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
parseInt()
转换字符串为整数
parseInt('123abc1');//输出123,遇到第一个字母或其他非法符号截断
parseInt('FF',16);//输出255,第二个参数为进制
parseInt('0x377');//输出887,以0x开头代表16进制,无需指定进制
parseInt('0377');//输出377,虽然以0开头代表八进制,但易与十进制混淆,所以还是当成十进制
parseInt('1.258e2');//125
a!==NaN
,因为NaN===NaN返回false,所以只能用isNaN判断。isFinite()
表示是否有限,注意Infinity、-Infinity代表正负无限
isFinite(Infinity);//false
isFinite(-Infinity);//false
isFinite(1e309);//false,因为超出了js能表示的最大数字
/?&
等都是关键字符,有特殊含义,若需要他们仅仅作为字符出现,则需要‘转义‘/?&
等关键字,需要先用encodeURIComponent编码,再与整个url拼接起来alert()
弹窗,且会阻塞js线程。
window.变量名
获取到例子:
let a = 123;
function f(){
alert(a);
let a = 1;
alert(a);
}
f();
//输出:先弹出'undefined',再弹出1.
解释:因为函数域始终优先与全局域,所以全局的123没作用。上面代码被等价的改写为下面
let a = 123;
function f(){
let a; //变量会被提升至此,且js引擎默认初始化为undefined
alert(a);
a = 1; //赋值不会提升,只提升了定义
alert(a);
}
f();
()=>{}
。(ES6规范)多用于执行一些一次性的或初始化的任务。
function (name){
alert('Hello'+name+'!');
}('dude'); //匿名自执行函数
函数内再定义函数。
function outer(param) {
function inner(theinput) {
return theinput * 2;
}
return 'The result is ' + inner(param);
}
坑1:
let xiaoming = {
birth: 1990,
age: function () {//根据出生日期获取xiaoming年龄
let y = new Date().getFullYear();
return y - this.birth;
}
};
let fn = xiaoming.age;//fn指向了age函数,fn跟xiaoming没任何关系
fn();
//输出:Uncaught TypeError: Cannot read property 'birth' of undefined
//原因:相当于window调用的fn,age中的this.birth就是window.birth.
坑2:
'use strict';
let xiaoming = {
birth: 1990,
age: function () {//根据出生日期获取xiaoming年龄
console.log(this.birth);//这里的this正常的指向xiaoming对象
function getAgeFromBirth() {
let y = new Date().getFullYear();
return y - this.birth;//嵌套函数中的this又指向了window
}
return getAgeFromBirth();
}
};
xiaoming.age();
//输出:Uncaught TypeError: Cannot read property 'birth' of undefined
//原因:对象中的嵌套函数(第二层及以上)中的this指向window,只有直接子级函数的this指向该对象本身。
解决办法:
let that = this;
保存住对象的引用,然后在孙子及更深层嵌套的函数中用that.属性名
访问对象属性。
let xiaoming = {
birth: 1990,
getAge: function () {
let that = this;
function getAgeFromBirth() {
let y = new Date().getFullYear();
return y - that.birth;//that指向了xiaoming
}
return getAgeFromBirth();
}
};
xiaoming.getAge();
let xiaoming = {
birth: 1990,
getAge: function () {
let fn = () => new Date().getFullYear() - this.birth; // this指向xiaoming
return fn();
}
};
xiaoming.getAge();
function a(){
alert('A!');
return function(){
alert('B!');
}
}
let func = a();//弹出'A'
func();//弹出'B'
//或者直接如下
a()();//先弹出'A',后弹出'B'
function a() {
alert('A!');
a = function(){
alert('B!');
};
}
a();//弹出'A!'
a();//弹出'B!'
应用场景:浏览器兼容性探测,初始化时根据浏览器类型,重写某些方法。
私有变量可以访问自身作用域(var为函数,let、const为块)和其外层作用域,就形成了一条作用域链。
用一个全局变量指向内层的函数,这样通过这个全局变量就可以访问内层函数同级的变量,突破了作用域链。(看着像从外层访问里层)
let F = function () {
let b = "local variable";
let N = function () {
let c = "inner local";
return b;
};
return N;
};
let inner = F();
inner();//输出"local variable"
let inner;
let F = function (){
let b = "local variable";
let N = function () {
return b;
};
inner = N;
};
F();
inner();//输出"local variable"
函数所绑定的是作用域本身,而不是在函数定义时该作用域中的变量或变量当前所返回的值。
若需要绑定(非引用类型)变量当前值的快照,则可以通过调用传参。因为函数传参是传的当前值的拷贝。
getter与setter
通过setter给变量赋值可以加验证。
//变量写成局部变量,不可直接访问。通过getter和setter暴露取值和赋值的接口。
let getValue, setValue;
(function() {
let secret = 0;
getValue = function(){
return secret;
};
setValue = function (v) {
if (typeof v === "number") {
secret = v;
}
};
}());
getValue();//输出0
setValue(123);
getValue();//输出123
setValue(false);//false验证失败,赋值不成功
getValue();//输出123
迭代器
function setup(x) {
let i = 0;
return function(){
return x[i++];
};
}
let next = setup(['a', 'b', 'c']);
next();//输出"a"
next();//输出"b"
next();//输出"c"
键类型 | 数据类型 |
---|---|
数字 | 数组 |
字符串 | 对象 |
任意类型 | map |
在一些程序语言中,通常会存在两种不同的数组形式。
js中数组表示索引型数组,对象表示关联型数组。
1.文本标识法
let obj = {
breed: 'Turtle',
occupation: 'Ninja'
};
对象的属性名若不符合变量命名规范,则属性名需要加引号。
let obj = {
'this':'abc',
'123':123
}
2.构造函数
function Hero() {
this.occupation = 'Ninja';
}
let hero = new Hero();
1.通过变量名.属性名
访问
hero.occupation;
2.通过变量名[属性名]
访问
hero['occupation'];
此种访问有两种使用场景:
增:hero.name = ‘zhangsan‘
;
改:hero.name = ‘lisi‘
;
删:delete hero.name
;
浏览器环境中,全局对象为window。
调用全局变量可以 a 或 window.a 或 this.a 。
指向实例化时所用的构造函数。若用文本标识法创建对象,则它的constructor指向Object()。
h2.constructor;
//输出
//function Hero(name){
// this.name = name;
//}
let o = {};
o.constructor;
//输出 function Object(){[native code]}
用于判断某个对象是否由某个指定的构造器或其父级构造器所创建。
h instanceof Hero;//true
h instanceof Object;//true
当且仅当俩引用指向同一对象时,俩对象相等且严格相等。
let fido = {breed: 'dog'};
let benji = {breed: 'dog'};
fido == benji;//输出false
内建对象大致分三类。
Object是所有对象的父级对象。
let o = {}
和let o = new Object()
等价。
Object含以下三个内建属性:
数组也是一种对象。
let a = [];
typeof a;//Object
a instanceof Object;//true
相比对象的特殊之处
length属性会随着数字键名的数量而更新,而忽略非数字键名属性。
a[0] = 0;
a.prop = 2;//非数字键名不会增加length
a.length;//输出1
a;//输出[0,prop:2];
当手动设置length的值小于数组中的元素数量时,多出的部分元素被移除。
原素组会改变的方法:
splice————万能改变数组的方法,截取数组同时填充若干元素,返回截取后的数组。
let a = [1,3,5,7,9];
let b = a.splice(1,2,100,101,102);//第二个参数为截取长度,与slice的第二个参数不同
console.log(a);//[1,100,101,102,7,9]
console.log(b);//[3,5]
原数组不受影响,返回一个改变后的数组的方法:
call和apply可以指定方法的执行上下文,从而可以实现一个对象去"借用"另一个对象的方法为己所用。
例如,arguments对象没有数组的内建方法,可以像如下方式调用
function f(){
let args = [].slice.call(arguments);
}
通过该方法可以实现子类对象中调用父类对象中的方法
例如:Array继承自Object,Array中重写了Object中的toString方法,但在Array中想调用Object中的方法时可以Object.prototype.toString.call([])
apply和call的唯一区别是,apply传参放在一个数组里。
作用:
其他几种基本数据类型也有以上功能
五个基本类型数据都有一个对应的Object类型封装。
(‘abcdefg‘).slice(0,2)
会发生装箱拆箱。
因为slice方法在String类型对象上,所以会先把值类型转换为引用类型,得到结果后再转换回值类型。
作用与Boolean相同,但增加了一些属性和方法。
把Number当成一个对象,该对象里有以下属性:
把Number当成构造函数,该构造函数prototype指向对象上有以下方法:
toString————重写了object的toString,有一个可选的radix参数(默认10)
(255).toString(16);//'ff'
Math用法与上面不同,不能new。
常用属性:
常用方法:
用于创建Date对象的构造器函数,可以传递以下几种参数
注意:js中的月份是从0开始,0表示一月,1表示二月...
常用方法
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳
同时有相应的set方法设置值。
注意:getDay表示获取星期,getDate才表示获取日
Date.now();//返回当前时间的时间戳
Date.parse('Jan 11, 2018');//返回时间戳
Date.UTC(2018,0,11);//返回时间戳
写法:
let re = new RegExp(‘j.*t‘,‘gmi‘)
let re = /j.*t/ig
组成部分:
修饰符:
RegExp对象的方法:
/j.*t/.test("Javascript");//false
/j.*t/i.test("Javascript");//true
/j.*t/i.exec("Javascript")[0];//Javascript
字符串中使用正则的方法:
let s = 'HelloJavaScriptWorld';
s.match(/a/);//返回["a"],没有加g修饰符,故匹配到第一个就返回
s.match(/a/g);//返回["a","a"],加g后匹配所有
s.search(/j.*a/i);//返回5
s.replace(/[A-z]/,'');//返回elloJavaScriptWorld,替换首个大写字母为空
s.replace(/[A-Z]/g,'');//返回elloavacriptorld,替换所有大写字母为空
s.replace(/[A-Z]/g,"_$&");//返回_Hello_Java_Script_World,用$&代替所匹配的文本
s.replace(/([A-Z])/g, "_$1");//返回_Hello_Java_Script_World,若正则表达式中分了组(即带括号),那么可以用$1表示分组中的第一组,$2表示第二组,依此类推
注意:replace中第一个参数不是正则而是字符串时,只会替换掉第一个。这是与其他语言不同的。
"pool".replace('o','*');//返回"p*ol"
"pool".replace('/o/g','*');//返回"p**l"
function replaceCallback(match){
return ""+match.toLowerCase();
}
s.replace(/[A-Z]/g,replaceCallback);//输出_hello_java_script_world
该回调函数接受一系列参数(以上示例仅用到了第一个参数)
包括一些派生的ReferenceError、RangeError、EvalError、SyntaxError、TypeError、URIError。
Error类对象都有两个属性:
try {
var total = maybeExists();
if (total === 0) {
throw new Error('Division by zero!');
} else {
alert(50 / total);
}
} catch (e){
alert(e.name + ': ' + e.message);
} finally {
alert('Finally!');
}
IE浏览器跟Chrome、FireFox抛出异常的name和message不同,可以自定义抛出一个匿名对象。
throw {
name: "MyError",
message: "OMG! Something terrible has happened"
}
js中的继承就是基于原型的。
函数也是对象,每个函数上都有一个prototype属性。
function foo(a,b){
return a*b;
}
typeof foo.prototype;//输出"object"
函数的原型属性只有在函数当作构造函数使用(即使用new调用)时才起作用。
this.属性名
访问实例属性值和原型对象上的属性。每个对象都会有一个构造器,而原型本身也是一个对象,这意味着它必然也有一个构造器,而这个构造器又会有自己的原型。于是这种结构可能会一直不断地持续下去,并最终形成原型链。
判断一个对象是否是另一个对象的原型对象
let monkey = {
hair:true,
feeds:'bananas',
breathes:'air'
};
function Human(name){
this.name = name;
}
Human.prototype = monkey;
let george = new Human('George');
monkey.isPrototypeOf(george);//返回true
获取一个对象的原型对象
Object.getPrototypeOf(george);//返回monkey对象
george.constructor.prototype;//这样也可以获取
生成一个对象时,js引擎自动在对象上加了一个__proto__属性,指向该对象的原型对象。然后原型对象也是对象,也有一个__proto__属性指向一个原型对象...如此下去,便形成了一条原型链。
__proto__只能在学习或调试环境下使用
注意:以上为对象层面的原型链。new一个对象时,js引擎把构造函数、原型对象层面的链状关系转化为对象层面的原型链。构造原型对象和构造函数之间的链状关系才是我们所需编写的代码。
//扩展Date,加一个format方法
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
};
function Dog(){
this.tail = true;
}
let benji = new Dog();
Dog.prototype.say = function(){
return 'Woof!';
}
benji.say();//对象生成后,再在原型对象上加方法,依然可以调用该方法
beiji.constructor === Dog;//返回true
Dog.prototype = { //此处完全替换掉了原来的原型对象
paws:4,
hair:true
}
typeof benji.paws;//返回'undefined'
beiji.say();//返回'Woof!',因为beiji的__proto__属性还链接着原来的原型对象
let lucy = new Dog();//在完全替换掉原型对象后,再实例化对象
lucy.say();//TypeError:lucy.say is not a function
lucy.paws;//4
lucy.constructor;//function Object(){[naticve code]},替换掉原型对象后,该原型对象的constructor属性就不指向Dog了
最佳实践:当我们重写对象的prototype时,需要重置相应的constructor属性。
js引擎所做的:查找对象属性时,先在对象自身属性中查找,再沿着__proto__链着的对象上查找。
我们所需做的:通过构造函数和原型对象构建链接关系。(new一个对象时,js引擎把转化为通过__proto__把对象之间连接起来)
Child.prototype = new Parent();
Child.prototype.constructor = Child;//重置原型对象上的constructor属性,不然就指向了Parent
缺点:该方法不仅继承了父类的实例属性,还继承了父类的原型属性
function extend(Child,Parent){
let F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
该方法只会继承父类的原型属性,不会继承父类的实例属性。
ES6中引入了class关键字,但并非js中有了类,只是一个实现继承的语法糖,实际还是通过原型实现继承。
class Student {
constructor(name) {
this.name = name;//实例属性、方法放在constructor中
}
hello() { //原型属性、方法放在外面
alert('Hello, ' + this.name + '!');
}
}
class PrimaryStudent extends Student { //extends关键字代表继承自谁
constructor(name, grade) {
super(name); // 记得用super调用父类的构造方法!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
运行javascript代码需要宿主环境,一般是浏览器环境。
BOM(浏览器对象模型)是一个用于访问浏览器和计算机屏幕的对象集合。可以通过window访问这些对象。
window对象是浏览器中的全局对象,所有的全局变量和函数都可以通过window对象的属性访问。
navigator是一个反应浏览器及其功能信息的对象。如navigator.userAgent可以识别不同的浏览器。
location是一个用于存储当前载入页面url信息的对象。
属性:
//若果当前页面的url为http://search.phpied.com:8080/search?p=java&what=script#results
for(var i in location) {
if(typeof location[i] === “string”) {
console.log(i + ' = "' + location[i] + '"');
}
}
//输出:
//href = "http://search.phpied.com:8080/search?q=java&what=script#results"
//hash = "#results"
//host = "search.phpied.com:8080"
//hostname = "search.phpied.com"
//pathname = "/search"
//port = "8080"
//protocol = "http:"
//search = "?q=java&what=script"
注:location的href中除了hash变化不会引起向服务端发起请求外,其他部分变化都会重新向服务端发起请求。
方法:
window.histoty属性允许我们以有限的权限操作同一个浏览器会话中的已访问页面。
作用:让无跳转的单站点也可以将它的各个状态保存为浏览器的多条历史记录。当通过历史记录重新加载站点时,站点可以直接加载到对应的状态。
API:
history.pushState(stateObject, title, url)
,包括三个参数。window.onpopstate
页面前进后退时,若当前url有对应的stateObject则触发事件,并在参数中包含stateObject。
//假如当前网页地址为http://example.com/example.html,则运行下述代码后:
window.onpopstate = function(event) {
alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
//绑定事件处理函数
history.pushState({page: 1}, "title 1", "?page=1"); //添加并激活一个历史记录条目 http://example.com/example.html?page=1,条目索引为1
history.pushState({page: 2}, "title 2", "?page=2"); //添加并激活一个历史记录条目 http://example.com/example.html?page=2,条目索引为2
history.replaceState({page: 3}, "title 3", "?page=3"); //修改当前激活的历史记录条目 http://ex..?page=2 变为 http://ex..?page=3,条目索引为3
history.back(); // 弹出 "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // 弹出 "location: http://example.com/example.html, state: null
history.go(2); // 弹出 "location: http://example.com/example.html?page=3, state: {"page":3}
window.frames属性是当前页面中所有框架的集合。
frames中的每个元素都包含了一个页面,都有各自的window全局对象。
screen所提供的是浏览器以外的环境信息。
打开窗口、关闭窗口
注:Chrome、edge中测试均无反应,已废弃。
setTimeout:在一定时间后执行
function boo(){
console.log('boo!');
}
let id = setTimeout(boo,2000);//2秒后执行boo方法
clearTimeout(id);//根据id取消计时器
setInterval:每隔多少毫秒执行一次
let id = setInterval(boo,2000);//每隔2秒执行一次
clearInterval(id);//根据id取消计时器
DOM是一种将XML或HTML文档解析成树形节点的方法。通过DOM的方法与属性,我们可以访问到页面中的任何元素,并进行元素的修改删除及添加操作。
基于DOM Level1用于解析所有XML文档的那部分称为Core DOM,在Core DOM上进行扩展的那部分称为HTML DOM。
document表示当前所访问的文档。
document.documentElement表示document上的HTML节点。
document.documentElement(即HTML节点)有三个,即head元素、body元素,以及两者之间的空白(空白默认为文本节点)。
节点对象.id
访问id属性的值,节点对象.className
访问class属性的值若一段HTML结构如下:
<html>
<head></head>
<!--这中间虽然什么都没有,但其实还是有一个text节点-->
<body>
<p class="opener">first paragraph</p>
<p><em>second</em> paragraph</p>
<p id="closer">final</p>
<!-- and that's about it -->
</body>
</html>
document.documentElement.childNodes[1];//#text,因为head和body之间存在一个空白,该空白为text节点
document.documentElement.childNodes[1].parentNode;//<html>...</html>
let bd = document.documentElement.childNodes[2];
bd.childNodes.length;//9,因为四个节点(包括注释)之间、子节点和父节点之间一共存在5个空白的text节点,所以一共9个节点
bd.childNodes[1].hasAttributes();//true,第一个标签有个class属性。注意索引0是空白text,索引1才是p标签
bd.childNodes[1].attributes.length;//1
bd.childNodes[1].attributes[0].nodeName;//'class'
bd.childNodes[1].attributes[0].nodeValue;//'opener'
bd.childNodes[1].attributes['class'].nodeValue;//'opener'
bd.childNodes[1].getAttribute('class');//'opener'
bd.childNodes[1].className;//'opener'
bd.childNodes[1].nodeName;//'p'
bd.childNodes[1].textContent;//'first paragraph'
bd.childNodes[1].innerHTML;//'first paragraph'
bd.childNodes[3].textContent;//'second paragraph'
bd.childNodes[3].innerHTML;//'<em>second</em> paragraph'
bd.childNodes[1].childNodes[0].nodeValue;//'first paragraph'
索引法的问题:
快捷方法:
注:getElement系列除了getElementById返回一个Element外,其他都返回一个HTMLCollection集合,HTMLCollection是动态的,会随着文档树的变化动态更新。
querySelector系列返回一个NodeList,NodeList是静态的,获取后,文档树变化不会影响NodeList.
document.getElementsByTagName('p').length;//3
document.getElementsByTagName('p')[0];//<p class="opener">first paragraph</p>
document.getElementsByTagName('p')[0].className;//'opener'
document.querySlector('p').className;//'opener'
document.querySlectorAll('p')[0].className;//'opener'
body虽然说嵌套在html标签里,但document.body就可以访问到body,而不用document.documentElement.body。
let my = document.getElementById(,'closer');
my.innerHTML = 'final!!!';
my.innerHTML = '<em>my</em> final';
my.firstChild;//<em>my</em>
my.firstChild.firstChild;//'my'
my.firstChild.firstChild.nodeValue = 'your';
my.style.border = '1px solid red';
my.style.cssText += 'font-weight:bold;';//直接在原有cssText属性上加css字符串文本
注意:后三个方法调用方是父容器节点。
let p = document.createElement('p');
p.innerHTML = '<em>yet</em> another';
p.style.border = '2px dotted blue';
document.body.appendChild(p);
let list=document.getElementById("myList")
list.insertBefore(p,list.childNodes[0]);//第一个参数为新节点,第二个参数为插入谁的前面
item.replaceChild(p,list.childNodes[0]);//第一个参数为替换者,第二个为被替换者
document.body.appendChild(p.cloneNode(false));//将只会拷贝一个p标签,相当于document.body.appendChild(document.createElement('p'));
document.body.appendChild(p.cloneNode(true));//p及p标签里的子元素都将拷贝
let p = document.getElementsByTagName('p')[1];
let removed = document.body.removeChild(p);
let p1 = document.getElementsByTagName('p')[1];
let replaced = document.body.replaceChild(removed,p1);
document.body.innerHTML = '';//清空body里的所有HTML
以上总结的都是属于DOM Level 0(或叫Core DOM),既适用于XML又适用于HTML。以下的只适用于HTML。
<a href=‘...‘/>
的集合<a name=‘...‘>
的集合document.forms————包含所有表单的集合
document.write()————在页面载入时插入一些HTML元素,当载入完成后调用则会覆盖整个HTML。一般没什么用。
document.location————同window.location
1.内联HTML属性法
<div onclick="alert('Ouch!')">click me</div>
缺点:Javascript代码和HTML耦合在一起。
2.元素属性法
<div id="my-div">click</div>
let myelement = document.getElementById('my-div');
myelement.onclick = function() {
alert('Ouch!');
}
缺点:只能指定一个事件函数。
3.事件监听器法
<p id="closer">final</p>
let mypara = document.getElementById('closer');
mypara.addEventListener('click', function(){alert('Boo!')}, false);
mypara.addEventListener('click', console.log.bind(console), false);
移除某个监听器:
function func(){
alert('Woo');
}
mypara.addEventListener('click', func, false);
mypara.removeEventListener('click', func, false);
注意:移除某个监听器时,传递的方法参数必须是同一个方法的引用,即使写一个完全相同的方法爷不行。故需要移除的监听器在注册时不能用匿名方法。
addEventListner方法的第三个参数,当置为true时为捕捉法,默认为false即冒泡法。
<body>
<ul>
<li><a href="http://phpied.com">my blog</a></li>
</ul>
</body>
单击链接
按照DOM2的规定,事件传播分三阶段:先捕捉标签,然后到达标签,再冒泡。
在最里层的处理器中加e.stopPropagation()
,就不会触发上层父容器的事件。
function paraHandler(e){
alert('clicked paragraph');
e.stopPropagation();
}
在浏览器中某些元素的事件有一些预定义行为,例如,单机链接会载入另一个页面。可以在事件处理器中加e.preventDefault()
来阻断默认行为。
// 在点击所有链接前询问是否导航至目标链接,若选择否,则不导航
let all_links = document.getElementsByTagName('a');
for (let i = 0; i < all_links.length; i++) {
all_links[i].addEventListener(
'click',
function(e){
if (!confirm('Are you sure you want to follow this link?')){
e.preventDefault();
}
},
false // don't use capturing
);
}
现代浏览器还有dragstart、dragend、drop事件,触控设备还有touchstart、touchmove、touchend事件。
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = myCallback;
xhr.open('GET','somefile.text',true);
xhr.send('');//若要携带参数则以格式'key=value&key2=value2'
fuction myCallback(){
if(xhr.readyState<4){
return;
}
if(xhr.status!==200){
alert('Error!');
return;
}
alert(xhr.responseText);
}
原文:https://www.cnblogs.com/victor-leeson/p/10963802.html