<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <htmlxmlns="http://www.w3.org/1999/xhtml"xml:lang="en"lang="en"> <head> <title>Title</title> </head> <body>
</body> </html>
HTML4
1 2 3 4 5 6 7 8 9 10
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Title</title> </head> <body>
H5对于表单的升级 1、给input设置了很多新的类型 search email tel number range color date time … [优势] 1)、功能强大了 2)、使用合适的类型,在移动端的开发的时候,用户输入,可以调取出最符合输入格式的虚拟键盘,方便用户操作 3)、部分类型提供了表单验证(内置验证机制:和我们自己写的正则验证不太一样,但是可以凑合【CSS中可以验证、JS中也可以验证】)
~function(){ //=> Each:遍历数组中每一项的内容 let each = function (ary, callback) { for (let i = 0; i < ary.length; i += 1) { let result = callback && callback(ary[i], i); if (result === false) { //=> 如果执行的回调函数中返回false,代表结束当前正在便利的操作(仿照JQ中的each语法实现) break; }
//=> 如果回调函数中返回的是DEL,代表当前这一项在回调函数中被删除了,为了防止数组塌陷问题 if (result === 'DEL') i--; } };
classPlan{ constructor() { this.planList = []; //=> 存放方法的容器 } //=> 挂在到plan原型上的方法 add(fn) { let planList = this.planList, flag = true; //=> 去重处理 each(planList, function(item, index){ if (item === fn) { flag = false; returnfalse; } }) flag ? planList.push(fn) : null; }
//=> Each:遍历数组中每一项的内容 let each = function (ary, callback) { if (!(ary instanceofArray)) return; for (let i = 0; i < ary.length; i += 1) { let result = callback && callback(ary[i], i); if (result === false) { //=> 如果执行的回调函数中返回false,代表结束当前正在便利的操作(仿照JQ中的each语法实现) break; }
//=> 如果回调函数中返回的是DEL,代表当前这一项在回调函数中被删除了,为了防止数组塌陷问题 if (result === 'DEL') i--; } };
//=> ON: 给当前元素某个事件绑定方法 let on = function (curEle, type, fn){ if(document.addEventListener) { //=> 标准浏览器 curEle.addEventListener(type, fn, false); return; }
//=> ES6 封装DOM2兼容处理 ~function(){ Function.prototype.myBind = function (context=window, ...outer) { if ('bind'inthis) { returnthis.bind(...arguments); } return(...inner) =>this.apply(context, outer.concat(inner)) }; let on = function (curEle, type, fn) { if (document.addEventListener) { curEle.addEventListener(type, fn, false); return; } if (typeof curEle['pond' + type] === 'undefined') { curEle['pond' + type] = []; curEle.attachhEvent('on' + type, run.myBind(curEle)); } let pondAry = curEle['pond' + type]; for (let i = 0; i < pondAry.length; i++) { if (pondAry[i] === fn) { return; } } pondAry.push(fn); };
let off = function (curEle, type, fn) { if (document.removeEventListener) { curEle.removeEventListener(type, fn, false); return; }
let pondAry = curEle['pond' + type]; if (!pondAry) return; for (let i = 0; i < pondAry.length; i++) { let itemFn = pondAry[i]; if (itemFn === fn) { pondAry[i] = null; break; } } };
let run = function (e) { e = e || window.event; if (!e.target) { e.target = e.srcElement; e.pageX = e.clientX + document.documentElement.scrollLeft || document.body.scrollLeft; e.pageY = e.clientY + document.documentElement.scrollTop || document.body.scrollTop; e.which = e.keyCode; e.preventDefault = function () { e.returnValue = false; }; e.stopPropagation = function () { e.cancelBubble = true; }; } let pondAry = this['pond' + e.type]; if (!pondAry) return; for (let i = 0; i < pondAry.length; i++) { let itemFn = pondAry[i]; if (itemFn === null) { pondAry.splice(i, 1); i--; coontinue; } itemFn.call(this, e); } };
console.log(str); //=> undefined console.log(fn); //=> fn本身 console.log(avg); //=> undefined console.log(sum); //=> sum is not defined console.log(num); //=> num in not defined
var str = 'aa'; let num = 12;
functionfn(){}
var avg = function(){}; let sum = function(){}; //=> ES6当中只提供了创建变量的信誉发标准,创建函数还是沿用ES5中的function(还会存在变量提升),如果想让函数也不存在变量提升,偶使用函数表达式赋值的方式:let fn = fuction(){}
//=> 创建变量 let xxx = xxx;
//=> 创建函数 let xxx = function(){}
//=> 自执行函数 ;(function(){
})();
2、使用let定义的变量不允许在同一个作用域中重复生命
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var num = 12; var num = 13; console.log(num); //=> 13
let str = 'aa'; let str = 'bb'; console.log(str); //=> Identifier 'str' has already been declared 当前报错,上面代码也不会执行(在JS代码执行之前,就已经知道有重复声明的了,也就是浏览器依然存在类似于变量提升的机制:在JS代码执行之前先把所有let声明的变量过一遍,发现有重复的直接报错)
let num = 12, fn = function(){ let num = 12; }; console.log(num); //=> 12 当前作用域下别重复声明即可(不同作用域中的变量是自己私有的,名字重复没关系)
var att = 200; let att = 100; //=> Identifier 'att' has already been declared //=> 不管之前使用什么方式在当前作用域中声明的变量,再使用let声明的时候都会报错
let num = 12, str = ''; let fn = function(str){ str = 'hello'; console.log(arguments[0]); //=> hello 当前JS并没有开启严格模式,所以形参变量和arguments存在映射机制(但我们应尽量不要这样处理,因为把ES6编译成ES5之后,会默认的开启严格模式,映射机制会终端,此处的值依然是‘word’) console.log(num); //=> Uncaught ReferenceError: num is not defined let num = 13; console.log(num, str); //=> 13 hello }; fn('word'); console.log(num, str); //=> 12 ''
1 2 3 4 5
"use strict" if(10 >= 10){ var total = 100; } console.log(total); //=> Uncaught ReferenceError: total is not defined 判断体也是一个块级作用域,在这个作用域中声明的变量时私有变量,再块级作用域之外时无法使用的
1 2 3 4
for(let i = 0; i < 5; i += 1){ console.log(i); } console.log(i); //=> Uncaught ReferenceError: i is not defined 循环体也是一个块级作用域(每一次循环都会形成一个新的块级作用域,当前例子形成五个块级作用域,每一个块级作用域中都有一个私有变量i,分别存储的时0-4)
1 2 3 4 5 6 7 8 9 10
let i = 10; { let i = 20; { { console.log(i); //=> Uncaught ReferenceError: i is not defined 虽然ES6没有变量提升,但是每一次进入当前作用域都会把let定义的变量找一边(不提升但是找了,找到了说明当前作用域中是有这个变量的,提前用都会报错) } let i = 30; } }
1 2 3 4 5 6 7 8
try{ let i = 100; }catch(e){ let k = 200; } console.log(i); //=> Uncaught ReferenceError: i is not defined console.log(k); //=> Uncaught ReferenceError: k is not defined //=> try catch 中的任何大括号都是块级作用域
1 2 3 4 5 6
switch(10){ case10: let i = 10; break; } console.log(i); //=> Uncaught ReferenceError: i is not defined
1 2 3 4 5
let obj = {name: 'a'}; for(let key in obj){
} console.log(key); //=> Uncaught ReferenceError: k is not defined
增加这些块级作用域的作用
1 2 3 4 5 6
let list = document.getElementsByClassName('item'); for(let i = 0; i < list.length; i += 1){ list[i].onclick = function(){ console.log(i); } }
let [{score:{English:[A],math:[,B],Chinese:[,,C]}}] = data; console.log(A,B,C);
解构赋值在项目中的应用
可以快速接收到传递的多个值(我传递的是一个对象或数组)
1 2 3 4 5
//=> 快速交换两个变量的值 let a = 12; let b = 13; [a, b] = [b, a]; console.log(a, b); //=> 13 12
1 2 3 4 5 6 7 8
let fn = function(){ let a = 12, b = 13, c = 14; return [a, b, c]; }; let [a, b, c] = fn(); console.log(a, b, c); //=> 12 13 14
1 2 3 4 5
let fn = function([a, b, c, d = 0]){ console.log(a, b, c, d); //=> 12 23 34 0 }; fn([12, 23, 34]); console.log(a); //=> Uncaught ReferenceError: a is not defined 函数中的a b c 是私有变量
1 2 3 4 5 6 7 8 9 10 11
//=> 设置参数默认值 let fn1 = function({x = null, y = {}, z = 1000, callback = null}){ }; fn1({x: 10, y: {a:1}});
//=> 不传参数,让其在空对象中结构赋值,避免报错 let fn2 = function({x = null, y = {}, z = 1000, callback = null} = {}){ }; fn2();
1 2 3 4 5 6
let obj = newMap(); obj.set('x', 10); obj.set('y', 20); for(let [key, value] in obj){ console.log(key, value); }
ES6中的箭头函数
箭头函数基础语法
1 2 3 4
let fn = function(x, y){ return x + y; } console.log(fn(10, 20)) //=> 30
1 2
//=> 将上面函数改写成箭头函数 let fn = (x, y) => x + y;
1 2 3 4 5 6
let fn = function(n){ let x = 10, y = 20; return x + y; }; fn();
1 2 3 4 5
let fn = n => { let x = 10, y = 20; return x + y; }
箭头函数中不支持arguments
1 2 3 4 5
let fn = function(){ let arg = Array.prototype.slice.call(arguments); returneval(arg.join('+')); } fn(10, 20, 30, 40); //=> 100
1 2 3 4 5 6 7
let fn = ()=> { console.log(arguments); //=> Uncaught ReferenceError: arguments is not defined //=> 不支持arguments,可以使用ES6中的生于运算符`...`来获取传递进来的所有参数值(相对于arguments的优势:使用剩余运算符接收到的结果本身就是一个数组,不需要再转换了) //console.log(arg instanceof Array); //=> true returneval(arg.join('+')) }; fn(10, 20, 30, 40);
1 2
let fn = (...arg) =>eval(arg.join('+')); console.log(fn(10, 20, 30, 40));
箭头函数中的this问题
普通函数中的this指向问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//=> 普通函数执行this的指向:看函数执行前面是否有点,点前面是谁this就是谁,没有点this指向window或者undefined(严格模式下) let obj = { name: 'obj', fn(){ //=> 这样处理和下面sum的处理是一样的 console.log(this); }, sum: function(){ } } obj.fn(); //=> this => obj document.body.onclick = obj.fn; //=> this => body setTimeout(obj.fn, 1000); //=> this => window obj.fn.call(12); //=> this => 12
functionPerson(name, age) { // console.log(new.target); //=> ES6新增加的语法,如果通过NEW执行,返回的结果是当前创建的实例,如果是当作普通函数执行,返回的是undefined if(typeofnew.target === 'undefined'){ thrownewSyntaxError(`当前Person不能作为一个普通函数执行,请使用new Person 来执行~~`); } //=> new 执行的时候,this是当前类的实例,this.xxx = xxx是给当前实例增加的私有属性 this.name = name; this.age = age; } //=> 原型上存放的是公有的属性和方法:给创建的实力使用 Person.prototype = { constructor: Person, say: function(){ console.log(`my name is ${this.name}, i am ${this.age} years old~`); } } //=> 把person当作一个普通对象,给对象设置的私有属性 Person.study = function(){ console.log('good good study, day day up~'); }; var p1 = new Person('小二', '22');
Person();
ES6中创建类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// console.log(Person); //=> Uncaught ReferenceError Person is not defined 不存在变量提升 classPerson{ constructor(name = '张三', age = '9'){ //=> 给实例设置的私有属性 this.name = name; this.age = age; } //=> 直接再大括号中编写的方法都直接设置在类的原型上,ES6默认把constructor的问题解决了,此时原型上的constructor指向就是Person say(){ console.log(`my name is ${this.name}, i am ${this.age} years old~`); }
study(){ console.log('good good study, day day up~'); } } let p1 = new Person(); // Person(); //=> Uncaught TypeError: Class constructor Person cannot be invoked without 'new' ES6中使用class创建的类,不允许把创建的类当作普通函数执行
classChildextendsPerson{ //=> 创建Child类,并且让Child类继承了Person类: 1、把Person的私有属性继承过来设置给;额子类的私有属性 2、让字类实例的__proto__上能够找到Person父类的原型(这样子类的实例就可以调用父类的方法) // constructor(){} //=> Uncaught REeferencerror: Must call super constructor in dervied class before accessing 'this' or returning from derived constructor //=> 我们不写constructor,浏览器默认会创建它,而且默认就会把父类的属性继承过来(把传给子类的参数值也传给父类了)