JavaScript笔记

JavaScript

1.基本认识

1.1 可以直接在标签中添加事件

123
gogogogogo 233333

1.2 script标签只能放在head或者body里面

  • 一个html中可以放无数个script标签
  • script标签载入有先后顺序
  • 如果一个script标签已经用来引入外部的js文件了,那么在标签内写代码无用

1.3 系统弹窗 confirm prompt

let a = confirm('确认不要媳妇啦?');
console.log(a);  //获得用户选择的结果,  "boolean"

let b = prompt('请输入你媳妇的名字:');
console.log(b);  //用户输入的结果,     取消-> null -> "object"      确定 -> string

2.数据类型

2.1 ES5、ES6定义变量的区别

ES6 定义变量,4种方式
- let      
- const    常量,不可更改,初始必须赋值
- function
- class

ES5 定义变量,2种方式
- var
- function

变量命名规则:

  1. 严格区分大小写;
  2. 只能包含 字母 数字 _ $ 四大类,且不能以数字开头;
  3. 不能使用 关键词/保留词/已有的API;
  4. 见名知意。
  5. 函数声明时会覆盖掉同名变量

2.2 ES6的七大数据类型

  • number 数字
  • string 字符串
  • boolean 布尔值
  • undefined 未定义
  • null 空 但是在浏览器上 typeof null = "object"
  • symbol ES6新增的一种数据类型
  • object 对象
// number 
let x = 10;

// string 
let x = "10";
let x = '10';
let x = `456`;   //模板字符串  ES6中新的字符串定义方式
let x = "true";

// boolean 
let x = true;
let x = false; //布尔值有两种,true 和 false

// undefined
let x;
let x = undefined;
const x = undefined;  //const不允许初始不赋值

// symbol  
let x = Symbol(123);
let y = Symbol(123);      // x和y都是独一无二的   Symbol(变量)

// object  
let x = [10,true,10];  //数组是对象的一种
function 和 class 定义的变量 typeof 显示"function", 其本质是object

2.3 typeof

let a = typeof NaN;       //number
let b = typeof a;         //b是string类型
let c;                    //undefined
let d = null;             //typeof在检测null类型时返回object类型,其本质是null类型
let e = Symbol(123);      //symbol
let f = document;         //object
let g = function(){       //typeof在检测function数据会返回"function",其本质是object
};

console.log(typeof(b));
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);
console.log(typeof f);
console.log(typeof g);

3. js获取dom元素节点

let a = document.getElementById("wrap");   //a就是节点对象
console.log(a);  //  
//ClassName不唯一,所以Elements有s let b = document.getElementsByClassName("box"); console.log(b); //类(似)数组 HTMLCollection(3) [div.box, div.box, div.box] console.log(b.length); // 3 console.log(b[0]); //
1
b[1].innerHTML = '阿飞'; let d = document.getElementsByName('name'); //应用在input标签 console.log(d); // NodeList [input]

3.1 html唯一标签获取

注意:打印的是标签,不是类数组节点

console.log(document.body);       // body标签及其子标签
console.log(document.head);       // head标签及内容
console.dir(document.title);    //标题

//获取HTML,此处是引用,尽管在后面改变,但引用也会跟上
console.log(document.documentElement);   //打印的是整个html页面

document.title = "阿飞";
document.documentElement.id = '狗蛋';

3.2 querySelector

let aaP = document.getElementById("wrap")
            .getElementsByTagName("div")[0]
            .getElementsByTagName("p");  //一层层查找,但性能仍然较querySelector好
console.log(aaP);  // HTMLCollection(3) [p, p, p]

let aP = document.querySelectorAll("#wrap div p"); //All多个,参数类似css选择器
console.log(aP);  // NodeList(3) [p, p, p]

/*最低支持IE8*/
let sP = document.querySelector("#wrap div p");  //只能选到第一个       打印出的就是标签

3.3 操作元素属性

w3c允许的标签属性,既是合法
合法的标签属性,直接 . 操作

 - `class`比较特殊,需要使用`className`代替操作
 - `style` 这个属性非常特殊,是个对象
let oDiv = document.getElementById("wrap");

//oDiv.title = '狗蛋';     直接写
oDiv.className = 'wrap';  //属性class是保留词,这里用className

oDiv.id = 'goudan';
oDiv.innerHTML = '

666

'; //虽然改了id,但oDIV仍指向这个节点对象整体,id只是其中一个属性,不能影响整体 //oDiv.innerHTML += '456'; 可以直接+= let oGouDan = document.getElementById("goudan"); console.log(oDiv === oGouDan); //完全相等
/*
css样式
  js中css属性名用驼峰法:
        操作复合样式的时候,去掉 - 号,后面的第一个字母大写
*/
let oWrap = document.getElementById("wrap");
console.log(oWrap.style);

oWrap.style.height = "100px";
oWrap.style.backgroundColor = "pink";    //将background-color改为驼峰命名法,backgroundColor

oWrap.style.cssText +="width:100px;height:100px;background-color:pink"; // 也可以这样写

/ oWrap.className += " box";     /   /* 操作className代替复杂的css样式设置  */

3.4 自定义标签属性

  • getAttribute()
  • setAttribute()
  • removeAttribute() 移除属性
let oWrap = document.getElementById("wrap");

//获取自定义标签属性
console.log(oWrap.getAttribute("afei"));

//设置自定义标签属性
oWrap.setAttribute("afei","456");
oWrap.setAttribute("zhuque","123");

//移除自定义属性
oWrap.removeAttribute("afei");

//可以操作合法属性,但一般不用,没有直接.操作方便
console.log(oWrap.getAttribute("id"));

3.5 标签数据 innerHTML、innerText(火狐低版本,textContent)、value

阿飞飞 小浪浪 海文文 银时时 朱雀雀

3.6 css超级选择器

 
        
        Title
        
    
    
        

4. 算术运算

4.1 隐式类型转换

  • "+" 两边任意一边有字符串,那么都会进行隐式字符串转换,再进行拼接
  • 布尔值和数字运算,会转换成 1 0
  • 除开number string boolean之外,比如去讨论一个对象和另一个对象的加法等是没有实际意义的
let a = 10;
let b = "20";
//alert(a + b);                 //  弹出  "1020",结果是字符串
//alert("123" + {});            //  123[object Object]
//alert("123" + document);      //  123[object HTMLDocument]
//alert("123" + undefined);     //  123undefined
console.log(true + 8);          //  返回9

//没意义
// console.log({}+{});             //[object Object][object Object]
// console.log([]+{});             //[object Object]
// console.log([]+[]);             //

//同级运算从左到右
alert(1 + 2 + "3");             //  返回 "33"
alert("8" + 1 + 2);             //  返回 "812"

// 将字符串转成数字, 前面带一个 +
console.log(+"86867");
// 数组和任何东西相加,都会转换成字符串
[1,2,3]+3           // "1,2,33"
[1,2,3]+true        // "1,2,3true"
[1,2,3]+null        // "1,2,3null"
[1,2,3]+undefined   // "1,2,3undefined"
[1,2,3]+''          // "1,2,3"
[1,2,3]+NaN         // "1,2,3NaN"
undefined+[]        //  "undefined"
{}+[]               // "[object Object]"
- * / %都会变成数字再进行运算

出现非法运算(字符串非数字字符串进行计算)时,会出现NaN(not a number)
    
let a = '50p';  //非数字
let b = "40";

console.log(a - b);      // NaN
console.log(a * b);     // NaN
console.log(a / 20);    // NaN
console.log(a % 20);    // NaN

console.log(typeof(NaN));    //NaN是number类型,但不是一个数字

console.log(NaN + 10);   // 返回NaN

4.2 自增和自减

let a = 10;
console.log(a++);        //返回10

// let a = 10;
// let b = 5;
// console.log(a++ + b);     //返回15

let a = "5";
a ++;  // ++ 或 -- 会强行变数字进行计算,最终a的值也是数字
console.log(a);  // 6

4.3 模板字符串

/*
      单引号 或者 双引号 描述的字符串,内部不能换行
      ` ` 模板字符串可以
*/

let oWrap = document.getElementById("wrap");

let x = "阿飞老师有点皮"

// oWrap.innerHTML = "
    "+ // "
  • "+ // "

    "+ // ""+x+""+ // "

    "+ // "
  • " + // "
"; /* ${}可以直接引用变量,{}内是JS代码 */ oWrap.innerHTML = `
  • ${x} \$\{\}

    \`\`是ES6的特点

`;

5. 运算符

5.1 赋值运算 a+=1

let a = 15;

a -= 1;     //a = a - 1
a *= 2;     //a = a * 2
a /= 3;     //a = a / 3
a %= 4;     //a = a % 4

alert(a);

5.2 比较=运算

/*
                   ==   只比较值相等与否,不关心数据类型
                   ===  值与数据类型都要相等

                   !=   不等
                   !==  不全等
*/
let a = 10;
let b = "10";

console.log(a == b);    //true
console.log(a === b);   //false

console.log(a !== b);   //true
console.log(a != b);    //false

5.3 对象引用类型比较地址

/*
基础数据类型  (栈内存)   只比较值与类型
number string boolean undefined null symbol

引用数据类型  (堆内存)   比较地址
object
*/

/* a 和 b 是不同的对象,有自己的地址  */
let a = [10];
let b = [10];

console.log(a == b);       //false
console.log(a === b);      //false

console.log(a[0] === b[0]);  //true

//console.log(false == [0]);   //这样不科学的,建议 ===

5.4 字符串比较

/*
            > < >=  <=
*/

//字符串比较,从首位的ASCII码开始比较
let a = '3';
let b = '20';

console.log(a > b);  // '3' > '2' 的ACSII码,所以返回 true

5.5 逻辑运算&& || !

/*
                &&  与      //只考虑布尔值时:真真为真,其他都是假
                            真正的作用:遇到假就停,然后取假值,否则取后面的值
                ||  或      //只考虑布尔值时:假假为假,其他都是真
                            真正的作用:遇到真就停,然后取真值,否则取后面的值
                !  非      //只考虑布尔值时:取反
                            真正的作用:取数据对应布尔值的非

                那些数据在被转成布尔值的时候是 false:
                    0  undefined  null  false  ''  ""  NaN
*/

// let a = true && false;
// console.log(!a);

let a = 5 && 0;
console.log(a);  //取假值,返回 number 0

let b = 8 && 9;
console.log(b);  // 返回 9

console.log(NaN || 7 || 0);    //返回7

console.log(!1);        //返回 false
console.log(!0);        //返回 true
//取一个数据对应的布尔值
console.log(!! NaN);    //NaN的布尔值是false

5.6 逗号运算

/*
        逗号运算符,从左到右 从上到下 运算
*/

let a = (4,5,6);    //算到6后停止
console.log(a);     //返回 6

5.7 运算优先级

/*
        运算符优先级
            . [] ()
            ++ -- - ~ ! delete new typeof void
            * / %
            + -
            < <= > >=
            == != === !==
            &&
            ||
            三目
            =
            ,
*/

// let a = 8 || 9 && 0;
// console.log(a);       //返回8

let a = 10;
let b = 5;

//浏览器会惰性运算,||的左边已经确定,右边不会计算
// a = 8 || 5 && (b=6);
//console.log(a);         //8
//console.log(b);         //5  ,b的赋值没有计算
a = 0 || 5 && (b=6);         //返回 a = 6, b = 6


console.log( 6 || (b=6) && 10  || 11);  //返回6
console.log(b);              //b仍未赋值

5.8 位运算(先取整再算)

/*
                二进制
                位运算时会将数值转换为32位整型来进行运算,
                所以位运算遇到小数时,直接处理掉小数部分当成整数来运算。
*/

let a = 15;
// 00000000 00000000 00000000 00001111

// -15的二进制
// 11111111 11111111 11111111 11110000   取反码
// 11111111 11111111 11111111 11110001   反码+1


/**
* 位运算操作符:按位非`~` 、按位与`&`、按位或`|`、按位异或`^`
*左移`<<`、 无符号右移`>>>`、 有符号右移`>>`
*/

//按位取反,  满足条件 a + ~a=-1
let a = 7;           // 0111
console.log(~a);     // -8 ( 1..1000 结果 取反 +1 )   (0...0111 -> 0...1000)

//按位与
console.log(10 & 8); // 1010 & 1000 = 1000 => 8

//按位或

//左移
a << 2;    //a * 2^2;

6. 判断和循环

6.1 三目运算

/*
 哪些数据是假:
     六大假  0 undefined null false "" NaN
     
 当条件、真语句、假语句都是一条语句时,我们可以使用三目来改写if    
 条件 ? 真语句 :假语句
*/
4<5 ? alert('真') : alert('假');



let val = true;
//三目运算符的 优先级 低于 +
let name = "val is" + val ?"狗蛋":"大锤";
//"val is true" ? "狗蛋" : "大锤"
console.log(name);

// 多级三目,从左到右
function f(n) {
    let a = n>100 ? n-100 :    n>99 ? n-99 : n;
    console.log(a);
}

6.2 switch

let a = '海文';

// if (a === "阿飞") {
//     alert(a + "老师一般帅!");
// }else if (a === "小浪") {
//     alert(a + "老师??");
// }else if (a === "海文") {
//     alert(a + "斯文");
// }else if (a === "朱雀") {
//     alert(a + "可爱");
// }else{
//     alert(a + "喵喵喵");
// }

//switch 是全等判断
switch (a) {
    case "阿飞":
        alert(a + "帅!");
        break;
    case "小浪":
        alert(a + "也帅!");
        break;
    case "海文":
        alert(a + "斯文");
        break;
    case "朱雀":
        alert(a + "可爱");
        break;
    default:
        alert("喵喵喵?");
        break;
}

6.3 逻辑运算符代替判断

let a = true;

function b() {
    console.log(123);
}

// if (a) {
//     b();
// }
a && b();         //遇到假停止,b()会运行


//先与再或,勉强可以代替三目运算
let x = 5;
let y = 6;
//console.log(x

6.4 for循环

// 2+2^2+2^3+2^4+...+2^10
let a = 1;
let sum = 0;
for(let i = 1; i <= 10; i++){
    console.log("i=" + i);
    a *= 2;         //a = a*2
    sum += a;
    console.log("sum=" + sum);
}

6.5 综合案例,生成尖括号

/*
                 5   3
                 6  3
                 7   4
                 8  4
                 9   5
                 10 5
*/

let oWrap = document.getElementById("wrap");
let HTML = '';

let num = 11;
let mid = 0;

//计算oWrap的宽高
if(num & 1){          //奇数判断
    mid = (num+1)/2;
}else{
    mid = num/2;
}
oWrap.style.width = num*50 + 'px';
oWrap.style.height = mid*50 + 'px';

for(let i = 0; i < num; i++){
    let x = i>(mid-1) ? num-i-1 : i;   //箭头朝下
    let y = i>(mid-1) ? i+1-mid : mid-1-i;  //箭头朝上
    HTML += `
${i+1}
`; } oWrap.innerHTML = HTML;

7. 循环

7.1 break vs continue

/*
    break:
        switch里面的break只对switch有用,不会影响到外面的for
        if里面的 break ,结束上级 for 循环 
    continue:  该次循环结束,进入下一个循环  
 */
for(let i=0;i<10;i++){
    switch (i) {
        case 5:
            break;   //作用不到for
    }
    console.log(i);
}


for(let i=0;i<9;i++){
    if(i===5){
        //continue;            //执行到continue,即刻停止,进入下一个循环
        break;         //结束 for 循环
    }
    console.log(i);
}

//break只能跳出一个for,要想跳出第二层,定义一个伪变量表示for循环,break aaa;
aaa:for(let i=0;i<5;i++){
    for(let j=0;j<4;j++){
        if(i*j ===6){
            break aaa;
        }
        console.log(`i===${i},j===${j}`);
    }
}

7.2 while

//let在for循环内定义时,是局部变量
for(let i = 0;;)
//var在for循环内定义时,相当于全部变量
for(var i = 0;;)


let i = 0;
for(;i<4;i++){

}
console.log(i);       //返回4



//全局变量下的for循环可以用while代替
var i =0;
for(;i<5;){
    console.log(i);
    i++;
}

var j=0;
while(j<5){
    console.log(j);
    j++;
}

// do while
let x = 5;
do{
    console.log(x);
    x++;
}while(x<5);

8. 函数

8.1 定义函数方式

/*
                let a = function () {
                    alert(1);
                }
                a();         //函数加括号,自执行
*/


/*
                a(); //可以放在function之前,let、var函数表达式定义的函数,不允许提前调用
                function a () {
                    alert(1);
                }
*/


/*  let、var定义的函数,不允许提前调用

                a();
                var a = function () {
                    alert(1);
                }
*/

let a = function b() {
    alert(2);
    console.log(b);      //在函数里面可以获取b,此时b === a
    console.log(b === a);
}
a();
//b();  //显示b()未定义,函数外面不能使用b

8.2 函数表达式

/*   使用fuction直接定义的函数不能直接加括号执行,只能通过名字再加括号执行
            function a() {
                alert(3);
            }
            a();
*/

//let定义的函数表达式,可以直接在后面加括号执行
let b=function () {
    console.log(4);
}();
console.log(b);    //undefined,此时b不能代表函数,b成为了函数的返回值

//匿名函数只能传参或赋值,不允许直接出现
//[function () {}]   //允许

// function{}   //不允许

//匿名函数加括号变成函数表达式,括号可内可外
(function () {
    console.log(5);
})();

(function () {
    console.log(6);
}());

//改变函数的返回值,也是函数表达式
+function(){          //一元运算符 + - 可以变为函数表达式
    console.log(7);
}();

~function () {        //位运算非
    console.log(8);
}();

!function () {          //逻辑运算非
    console.log(9);
}();

8.3 参数

/*
                参数
                    形参
                    实参
                    不定参
*/
//定义函数的时候()里面是允许写变量名字的,这些变量名字就是形参,形参只针对函数内容起作用
function a(x,y=200){
    alert(x+y);
}
//函数调用的时候,()里面写的就是实参
a(7);


function f(a,b,c) {
    console.log(a);
    console.log(b);
    console.log(c);
}
f(1,8);       //从左到右进入形参,没有传入实参的,显示undefined
f(1,5,3,4);   //实参多了,多的那个无效


function sum(a,b) {
    console.log(a+b);
}
sum(7,8);
sum(45,1);


//求 n 个数的和,每次不一定是相同的个数,实参传入几个数,就求几个数的和
function sum(a,b,c,d) {
    //不定参    它是一个类数组,存储着 所有实参
    //  console.log(arguments);
    let s = 0;
    for(let i=0,len=arguments.length;i

8.4 上下文this

console.log(this);     //打印Window  是顶层属性

//  window.alert(4);
//  alert(a);       //未定义  报错
//  alert(requestAnimationFrame);

//不存在即报错
if(window.requestAnimationFrame){      //直接判断时,如果不支持,直接报错,不能进行判断,此时最好用类属性判断
    console.log(requestAnimationFrame);
}


/*  函数声明,默认位于window对象内
    函数(声明式or表达式一样)自执行,this指向window
*/
function a() {
    console.log(this === window);
}
console.log(a === window.a);          //  相等
a();


 //let定义的函数不挂载window内,var定义的函数在window内
let b = function () {
    console.log(this);        //this都是指向window
}
console.log(b === window.b);      
b();


/*
     对象内的this,找 爸爸 所在的对象
*/
let afei = {
    name:'阿飞',
    x : function () {
        console.log(this);
    }
}
afei.x(); //对象方法自执行。this指向对象

let zhuque = {
    xx:{
        name:"朱雀的xx",
        a:function () {
            console.log(this === zhuque.xx);
        }
    }
}
zhuque.xx.a();      // 打印 父级的对象

8.5 每个函数都有返回值,默认 return undefined

//函数运行到return即停止,return后面的不执行
function a() {
    alert(1);

    return 2;

    alert(3);
}

console.log(a());

8.6 ES6{}就是一个作用域

let关键词定义的变量,起作用的范围就是包含这个变量最近的{}

var关键词,只有在function内定义的变量,才是局部变量,while、if、for内定义的都是全局变量

同名函数会被覆盖

function a() {
alert(2);
}

function a(x,y) {      //覆盖上一个定义
alert(x+y);
}
a();

8.7 获取元素的动态方法

动态有三个,意思是存储节点的变量会随着页面的改变实时改变,少了或者多了

  • getElementsByClassName()
  • getElementsByTagName()
  • getElementsByName()

静态有以下,获取后,选择器被改也指向原对象

  • querySelectorAll
  • getElementById

9.作用域与解析顺序

9.1 var、function在全局作用域定义的变量默认是window对象的属性

//script标签是最大的作用域,也是全局作用域
//如果var、function在全局作用域里面定义变量。相当于给window添加了属性
var b = 10;
console.log(window.b,this);   //window的属性


//ES5定义变量的关键词 var   funtion
//作用域是往上离变量最近的函数

function a() {
var g = 10;      // var在function内定义的才是局部作用域
console.log(g,this.b,this);           //函数自执行this指向window
}
a();

//任意作用域里面,如果不加var直接产生了没有定义过的变量,那么这个变量相当于window的属性
//但是实际开发不允许这样写
function aa() {
bb = "bb";      // 赋值产生变量才行,如果直接使用则会报错
}
aa();
console.log(bb);

//面试题
function f() {
var x=y=5;
console.log(x);  //x是局部的5
}
f();
console.log(y);  //y未声明,因此算是window的属性,y=5
//console.log(x);  //因为x是局部变量,外部访问不到,故报错

9.2 作用域链

//作用域链,操作变量时,一层层的作用域查找变量声明的地方,
//如果没有找到,调用变量会报错
//如果是赋值,在非严格模式下,变量成为windows的属性

var x=10;
function a() {
x=15;       //本作用域找不到,去父级作用域找,找到后并赋值
var y=5;    //局部作用域
return x+y;
}

console.log(a());
console.log(x);     //全局变量被修改了,因此是15

9.3 es5解析顺序

var、function解析顺序

第一步:定义
    找出当前作用域里面所有的var和function定义的变量名,不赋值,赋值是执行
    此时function定义的函数,是个完整的函数,所以函数定义可以在函数执行的前后任意位置

第二步:执行
    从上到下执行
alert(x);     // 返回不是报错,是undefined,变量已有,但未赋值
var x=10;
//let x=10;    // 报错
/*
                1.定义
                    var x;
                2.执行
                    alert(x);   //undefined
                    x=10;
*/


alert(b);
function b() {

}
/*
                1.定义
                    function b(){}
                2.执行
                    alert(b);
*/

9.4 变量重名与覆盖

/*
    定义过程中,多个var声明同一个变量,我们只需要留一个
               多个函数声明重名,只留最后一个函数
               var和function重名,无论先后,只留function
 */
function v() {
    alert(5);
}
function v() {       //  被打印 
    alert(10);
}

var v;
console.log(v);

9.5 闭包

函数执行每次都会产生一个新的作用域 (父级也是新的) ,彼此不相干

/*
JS自带变量回收机制,只有全局变量不会被回收,除非网页关闭;
        闭包:一个使用了外部函数的参数或者变量的函数(作用域嵌套作用域,ES5只有函数能产生作用域)
 */
function a() {
    var x=10;
    function b() {
        x++;
        console.log(x,this);
    }
    return b;
}
//函数执行每次都会产生新的作用域,
var c=a(); //c指向函数体内的函数b,局部变量x只在a()时产生了一次,所以不会回收
//alert(c);  c是函数
//c()每次执行使用的都是同一个父级作用域下的变量x
c();  //11
c();  //12
c();  //13
c();  //14

//a()每次执行后返回的都是新的作用域,使用的变量x是新的,
a()();  //11
a()();  //11
a()();  //11

闭包的作用之一,闭包避免局部变量被回收

aaaaaaaaaaa

bbbbbbbbbbb

cccccccccc

dddddddddd

eeeeeeeeee

练习

fn()();
var a = 0;
function fn(){
    alert(a);
    var a = 3;
    function c(){
        alert(a)
    }
    return c;
}

/*
        1.定义
            var a;
            function fn(){}
        2.执行
            fn()  ===>    新作用域
                            1.定义
                                var a;
                                function c(){}
                            2.执行
                                alert(a)   undefined
                                a=3
                                return c;
            fn()()   ===>新作用域
                        alert(a),a从父级找,弹出3
 */
var a = 5;
function fn(){
    var a = 10;
    alert(a);
    function b(){
        a ++;
        alert(a);
    }
    return b;
}
var c = fn();
c();
fn()();
c();

/*
    10
    11
    10
        11
    12
 */

9.6 function属于对象类型,相等判断时是比较地址

console.log(5 === 5);

console.log([] === []);   //引用,需要比地址,false

var h = function () {};
var l = function () {};
console.log(h === l);     //false

function a() {
    return function () {};
}
var b = a();
var c = a();
console.log(b ===c);  //false

9.7 ES6的作用域

只要是在作用域里面let过的变量,那就不允许提前使用

/*
       ES6定义变量
            let const function class

                 let 和 const没有预解析,不同于var
                 先对定义function,进行解析
 */
alert(a);   //报错
let a = 10;


let a = 20;
function b() {
    //从上到下读
    //暂时性死区,只要是在作用域里面let过的变量,那就不允许提前使用
    alert(a);
    let a = 30;  //死区了,报错
}
b();


//var的作用域只认函数
if(false){
    var a=10;
}
console.log(a);  //undefined


//let的作用域是大括号
if(true){
    let a=1;
}
console.log(a);  //无法访问局部作用域
//for的小括号()是{}的父级作用域,但var不认这是作用域


const g = 10;  //不允许重新赋值的常量
const a = [];  //对象不能被重新赋值
a[0] = 10;         //但允许改变其内容
console.log(a);

10. call apply bind

10.1 函数内的this

function a() {
    console.log(this);
}

a();
/*
    普通模式下, 自执行this指向window,
    严格模式下, this指向undefined
    被动模式下,this指向触发事件的对象
 */
document.onclick = a;

10.2 call apply

/*  call()内第一个参数是函数内this的指向,后面跟的是实参,调用后会执行  */
function a(x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}
a(8,9);        //自执行
//a.call();   //call()不加参数与自执行a()效果一样
a.call(document,8,9);  //this指向document


/*  apply(),与call()类似,但是只有两个参数,第二个是传参的数组  */
a.apply(document,[8,9]);  //this指向document
//多个参数要用数组的形式传入

10.3 bind

bind之后相当于生成一个新的函数,还未执行

/*  bind不能执行  */
function a(x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}

//a.bind(document);  这样直接写是没有效果的,只是相当于生成了一个新的函数,将this绑定给document

function b(x) {
    x();
}
b( a.bind(document) );  //bind后生成了有this新指向的函数,bind是定义函数,不能直接执行,需要手动执行

a.bind(document)(10,20);  //新的函数内的this指向 document

a.bind(10)(0,1);  //新的函数内this指向number  10
//bind定义this指向

document.onclick = function (x,y) {
    console.log(x);
    console.log(y);
    console.log(this);
}.bind({name:'阿飞'},200,250);        //这里类似于call传参,bind产生新函数

10.4 H5新API classList

oWrap.classList.[attr] attr = add、remove、toggle

let aDiv = document.querySelectorAll("#wrap .title"),
    aList = document.querySelectorAll("#wrap .friend .list"),
    len=aDiv.length;


for(let i=0;i

11. ES6的解构赋值

// ES6 定义变量的解构赋值
let a = 10,
    b = 20,
    c = 30;
//结构模式对应,赋值效果同上
let [a,b,c] = [10,20,30];

//多了   显示  undefined
let [a,b,c,d] = [20,30,41];       //  d = undefined

//不用let的变量赋值语句,变量默认是window的属性
[a,b] = [20,30,41];

//变种写法
function fn() {
    let x=[];
    for(let i =0;i<5;i++){
        x[i]=i*i;
    }
    return x;
}
let [a,b,c,d,e] = fn();


//对象的解构赋值,属性是用来对应的,只有变量定义了
let {a:x,b:y} = {a:10,b:20};
console.log(x);
console.log(a);  // 报错,属性不是定义的


let {x:x,y:y} = {a:10,b:20,y:30};
console.log(x);      //找不到右边对象的x属性,所以变量x显示未定义
console.log(y);      //属性对应才能赋值 y=30


//注,属性和变量相同时,可以只写一个
let {x,y} = {x:10,y:30};
console.log(x,y);

//ES6新增简写规则
let a = 10,
    b = 20,
    c = {
        a,
        b
    };
/*属性名和变量名相同,可以简写,对象c的定义同下
    c = {
        a:a,
        b:b
    }
*/
console.log(c);

11.1 深层解构赋值

let [a,[b,c],d] = [1,[2,3],4];
console.log(a,b,c,d);


let [a,b,{x,y}] = [1,2,{x:10,y:20}];
console.log(a,b,x,y);

11.2 解构赋值时默认值写法

只有右边**严格等于undefined**时取默认值

不允许前面的默认值用后面的变量值
/*使用解构赋值,取默认值的方法*/
function fn(data) {
    let a = data.a;
    let b = data.b;
    let c = data.c || 100;  // 要确保传入的值不是假,否则走默认值,这种不严格

    // 必须严格的走 全等undefined,再添加默认值
    if(c === undefined){
        c = 100;
    }
}
fn({a:10,b:20});


//ES6的默认值写法,左边写一个等于,只有右边严格等于undefined时取默认值
function fn(data) {
    let {a:a=1,b:b=2,c:c=100} = data;  //左边严格上说不能认为是对象,只有右边是对象
    console.log(a,b,c);    // c = null
}
fn({a:10,b:20,c:null});   // 这里 null===undefined 不成立,


//数组默认值写法
let [d,e,f=90] = [7,8];
console.log(d,e,f);

//默认值是表达式时,如果不需要默认值,则默认值无法执行
function f1() {
    console.log("12");
}
let [x = f1()] = [1];     //  x=1,  f1未执行
let [y = f1()] = [undefined];  //  y=undefined,  是f1执行后的返回值

//不允许前面的默认值用后面的变量值
let [m=n,n]=[undefined,1];
console.log(m,n);  //报错

12. 字符串方法

12.1 基本数据类型包装对象无意义

undefined null 等不能进行点操作,会报错的

//基础数据类型虽然可以点操作,但没有意义,拿不到包装对象;
//点操作本质上是针对数据的包装对象进行操作,每一次的包装对象都是新产生的对象,不能确定
//undefined null 等不能进行点操作,会报错的
let a='阿飞';
a.index = 20;    //不能给字符串添加自定义属性,不会报错,显示undefined,这是操作的a的包装对象,用了即消失,存不下来
console.log(a,a.index);   //第二次的点操作是操作的全新的包装对象,用后即消失


/*
let b={};
b.index = 20;      //对象可以添加自定义属性
console.log(b);
*/


let a = new String("阿飞");       //这里的a是字符串对象
a.index = 20;                    //a的包装对象是 new String(),可以添加自定义属性
console.log(a+"朱雀",a.index);

12.2 str.charAt() 取出字符串中的第几位字符,不能赋值

let a = '阿飞';
//console.log(new String(a));   //可以打印包装对象属性为String的对象

//针对a的包装对象的charAt
console.log(a.charAt(1));   //取出字符串中的第几位字符
console.log(a[0]);  // a的包装对象有a的内容,对象访问时可以的,但是IE6,7不支持,最好用charAt

//包装对象不能赋值,没有意义;使用即消失,存不了
a[0]="5";

console.log(a[0]);

12.3 str.charCodeAt() 获取ASCII编码

/*
    charCodeAt()
    调用第几个字符的编码,

    String.fromCharCode()
    与之相反,从ASCII码到字符
 */

let a = "阿A飞";
let b = `阿
飞`;

console.log(a.charCodeAt(1));   //  65

console.log(b.charCodeAt(1));  //换行码是 10

console.log(String.fromCharCode(39134));  // 飞


//加密,利用ASCII码
let c = "小卑鄙我爱你";
let d = "";

for(let i=0,len=c.length;i

12.4 str.substring(x,y) 字符串截取一段[x,y),xy大小无所谓,y默认为len

/*substring(x,y)  从第x位到第y位截取,x要,y不要*/
// slice可以倒着截取
let a="abc阿飞789456";

let b = a.substring(3,5);  //包含3,不包含5
console.log(b);  //阿飞

let bb=a.substring(5,3);   //没有前后要求,会自动调整
console.log(bb); //阿飞

let c = a.substring(3);    //从3到结尾
console.log(c);  //阿飞789456

let d = a.substring(-2,3);   //没有负值,会认为0
console.log(d);  // abc

let e = a.slice(-5,-2);      //负值表示从后开始数,倒着数,要满足先后顺序
console.log(e);  // 894

12.5 大小写转换toLocaleUpperCase

//主要针对英文字母大小写
/*
        toLocaleUpperCase()
 */
let a = "abc";

let b = a.toLocaleUpperCase();
console.log(b);

console.log(b.toLocaleLowerCase());

12.6 indexof()返回坐标,默认-1

/*
        找位置,返回num
 */

let a = "我觉得阿飞老师是最皮的";

console.log(a.indexOf("阿飞"));

//指定位置开始找,后面加一个参数
console.log(a.indexOf("老师",3));

//找不到返回 -1

12.7 split(",")切割返回数组,join(",")拼接成字符串

// 使用split()进行切割,返回一个包含分开特定字符前后元素的数组
let a = "阿飞,朱雀,心艾,岚岚,丫丫,艾米";

let b = a.split(",");
console.log(b);

console.log(b.join("php"))
// let c = a.split("");
// console.log(c);

12.8 ES字符串扩展

function fn(a,b) {
    console.log(arguments);  // [ 0:["1,2", "阿飞", ""], 1:5 , 2:6 ]
    console.log(a+b);  // 1,2,阿飞,5
}
//fn(1,2);
let b=5;
let a = 6;
fn`1,2${b}阿飞${a}`;

13. 数组方法

13.1 push pop shift unshift

增加,返回数组长度,删除,返回被删的内容

/*
    push
        参数:任意数据
        功能:直接改变原数组
        返回值:返回改变后数组的长度
    pop
        参数:null
        功能:改变原数组,删除最后一位
        返回值:删除的元素
    shift
        功能:改变原数组,删除第一位
        返回值:删除的元素
    unshift
        功能:改变原数组,从第一位添加
        返回值:数组长度
        
 */

let a = ["阿飞","无虑"];

console.log(a.push("小浪","海文"));
console.log(a);
console.log(a.pop());
console.log(a);
console.log(a.shift());
console.log(a);
console.log(a.unshift("first"));
console.log(a);


//骚操作,
// pop()返回的是删除的最后一个函数,后面跟参数执行
let x = [5,function(x){alert(x)}];
x.pop()(x[0]);

13.2 a.indexOf() a.slice()

//类数组除了.length,不能执行其他api

let a = ["阿飞","无虑","朱雀"];

console.log(a.indexOf("朱雀"));       //2

//数组截取
let b = a.slice(1); 
console.log(b);    //  ["无虑", "朱雀"]

13.3 数组切割splice()

返回被切割的部分

//数组切割,单个参数时,包含前面而不含后面的
let a = ['阿飞','无虑','小浪'];

console.log(a.splice(1));  //从第1个切,切到最后       ["无虑", "小浪"]
console.log(a);            // ["阿飞"]


//第二个参数表示切除几个
console.log(a.splice(1,1));  //从第1个开始切除1个   ["无虑"]
console.log(a);     // ["阿飞", "小浪"]


//添加与替换
a.splice(1,1,'朱雀','心艾');  //切除一个,替换了2个    ["无虑"]
console.log(a);     // ["阿飞", "朱雀", "心艾", "小浪"]

13.4 数组排序a.sort() a.reverse()

二分法排序

不加参数,默认升序数组被改变了,但引用地址没变,仍相等

//一般只是针对num类型数组排序,其他类型没有意义
// sort()从小到大排序,升序
// reverse()  反序,元素从后往前排,可以先升序再反序实现降序排列
// 返回值是排列完成之后的数组,
let a=[12,78,50,20,32,40,90];

a.sort();
console.log(a);
a.reverse();
console.log(a);

console.log(a.sort() === a);  //改变之后还是a本身,相等

//降序
console.log(a.sort().reverse());


//JS二分法排序   a-b: 为升序          b-a: 为降序
a.sort(function (a,b) {
    return a-b;           
})
console.log(a);
let a = [
    {name:'阿飞',age:20},
    {name:'朱雀',age:30},
    {name:'丫丫',age:18},
    {name:'心艾',age:80},
    {name:'岚岚',age:22},
    {name:'发发',age:22},
    {name:'艾米',age:28}
];

//a.sort();  无法直接对对象排序

a.sort(function (a,b) {
    return b.age-a.age;   //后者减前者,降序
})

console.log(a);

13.5 数组拼接数组 a.concat(b)

//  concat   拼接数组

let a = [1,2,3];
let b = [4,5,6];

let c = a.concat(b);   //将b拼接到a的后面

console.log(a,b);  //不改变原数组
console.log(c);

13.6 数组方法 Array.isArray(a)

//  只有 Array 可以使用 isArray()方法

let a = [1];
let b = document.querySelectorAll("div");

console.log(Array.isArray(a));
console.log(Array.isArray(b));    //常用于判断类数组,其没有数组常用的方法

13.7 数组拼接字符串 a.join(",")

let a = ["阿飞",'心艾','朱雀'];

let b = a.join("<==>");    //通常将字符串数组元素拼接成一个新的长的字符串

console.log(a);  //不改变原数组
console.log(b);  //b是返回的长字符串   阿飞<==>心艾<==>朱雀

13.8 数组遍历 a.forEach(v,i)

//forEach  遍历数组,必须要有函数作为参数,自动执行length次,不支持函数return
/*
    接收函数,该函数第一个形参代表每一位的数据,
                 第二个形参代表每一位的序号,
                 第三个形参代表原数组
 */

let a = [4,5,6,7,8,9];
let b=a.forEach(function (x,y,z) {
    console.log(x,y,z);
});
console.log(b);  //undefined

//与forEach效果一样
for(let i=0;i

13.9 数组遍历 a.map(cb(val,i))

//map是有返回值的数组遍历,返回一个基于原数组结构的数组
let a = [1,2,4,5];

let b = a.map(function (x,y,z) {
    console.log(x,y,z);
    return x*x;
});

console.log(a);  //map不改变a
console.log(b);  //b是基于a结构的新生数组   [1, 4, 16, 25]
**ES6 的Map对象,可用于记数**
let a = [1,2,4,5];
let c = new Map()
a.map(function (val,index) {
    c.set(index,value)     // 实例方法,设置 map数据
})
console.log(c);       // Map对象实例  Map(4) {0 => 1, 1 => 2, 2 => 4, 3 => 5}

c.get(3);    // 5      按set时的index查找   
c.has(0);    // true   index
c.keys();    //  MapIterator {0, 1, 2, 3}
c.values();  //  MapIterator {1, 2, 4, 5}
[...c];      //  [[0,1], [1,2], [2,4], [3,5]]   

13.10 过滤 a.filter(cb(val,i))

/* 遍历
    func:过滤
        生成一个过滤后的数组,return true 留下,false 过滤掉

 */

let a=[10,20,5,7,89,41];
let b=a.filter(function (x,y,z) {
    console.log(x,y,z);
    return x>10;   //将x>10的留下,新生一个数组
});

console.log(a);  //不改变原数组
console.log(b);  //b是过滤后的数组

13.11 ES6 ...扩展

let a = [1,2,3];
console.log(...a);  //去除数组括号,拆解成单个,ES6兼容,babel可转
console.log(1,2,3); //与上等价


//param形参
function f(param) {
    console.log(param);    // 只有一个形参  1
}
//f(1,2,3);
f(...a);

/*
let c = (...a);   //这样做是不允许的
console.log(c);
*/

...数组拼接

// ...数组拼接

    let a = [1,2,4];
    let b = [5,6,7];

    //let c = a.concat(b);
    let c = [...a,...b];

    console.log(c);

...解构赋值

//b是数组,拆开后赋值,  ...b只能放在后面,表示接受全部
let [a,...b]=[1,2,3,4];

console.log(a);  // 1
console.log(b);  // [2, 3, 4]

...与iterator接口

//常见的Iterator遍历器接口
/     Array String nodelist arguments     /

// Nodelist是节点对象集合

function fn(a,b,c) {
    console.log(a,b,c);
}

fn("753");       //   753 undefined undefined
fn(..."753");    //   7 5 3

...与NodeList

let aP = document.getElementsByTagName("p");
// 类数组不能用数组的遍历
// aP.forEach(function (val,index) {
// });

//ES5就有办法将 aP 先搞成数组,之后再使用forEach
//slice不传参数就不切割,数组切割,方法slice使用call改变切割对象执行,返回一个真数组
let x = [].slice.call(aP);    //生成一个新数组
console.log(x);
x.forEach(function (node,index) {
    node.onclick = function () {
        alert(index);
    }
})

//ES5   类数组=>真数组遍历遍历
[].slice.call(aP).forEach(function (node,index) {
    node.onclick = function () {
        alert(index);
    }
});


//ES6 ,  ...将Nodelist拆了,加上[]成为真数组
console.log([...aP]);
[...aP].forEach(function (n,i) {
    n.onclick = function () {
        alert(i);
    }
});

...与function

//任何拆解都要放在最后面
function fn(a,...b) {
    console.log(a);
    console.log(b);
}
fn(4,5,6);


function fn(...argu) {
    console.log(argu);     //ES6的...可以直接代替arguments
}
fn(7,8,9);

14. 数学对象

14.1 Math

  • Math.pow(x,y)表示x的y次方
  • Math.trunc(-5.999991) 去小数点取整 -5
/*
    Math 对象
        属性:
        方法:
 */

//小数表示方式: 0表示正负   10表示小数点的位置为2  10.1010的整数部分为2,小数部分是1010/2^4,    10/16
//var a = 0 10 10.1010;    //表示 2.625

/*
    Math.abs()
        1.传入的值是正确的,返回一个新的绝对值结果,字面量赋值
        2.传入的值是数字字符串,会取value值取绝对值
        3.单个数字元素的数组也会取值,多个数字元素也是NaN
        4.传入的值其他类型,返回NaN,表示not a number
 */
console.log(Math.abs(["-888"]));      //  888

//Math.pow(x,y)表示x的y次方
console.log(Math.pow(2,10));       // 1024
//开方,y小于1
console.log(Math.pow(256,1/2));    // 16
//过气的开二次方
console.log(Math.sqrt(256));       // 16

//取整,floor接地气,往小了取整,正负一样
console.log(Math.floor(2.5),Math.floor(-2.01));      //2    -3
//向上取整
console.log(Math.ceil(2.5),Math.ceil(-2.9));         //3    -2
//四舍五入取整
console.log(Math.round(4.49),Math.round(-4.6));      //4 -5
//去小数点取整
console.log(Math.trunc(-5.999991));     // -5

14.2 三角函数

/*
    圆周  2PI    360deg
          PI/6   30deg
          PI/3   60deg

          sin  正弦   对/斜
          cos  余弦   邻/斜
          tan  正切   对/邻

          反三角
          arcsin
 */

console.log(Math.sin(Math.PI/6),Math.cos(Math.PI/3),Math.tan(Math.PI/4));  //结果有小数,不精确

console.log(Math.asin(0.5),Math.PI/6);

14.3 随机数 Math.random()

/*
        Math.random()     返回一个[0,1)的数
 */

//console.log(Math.random(),Math.round(Math.random()*10));

//  生成一个n到m的随机数,m取不到
const rdm = function(n=0,m=n+1){
    return Math.floor((m-n)*Math.random()+n);
}
console.log(rdm(1,7));

14.4 parseInt() parseFloat()

/*
    非数学对象
         parseInt(a,b)
            a   需要转换的数值,隐式转换成字符串
            b   进制(2,36)  10+26
 */

console.log(parseInt("123abc"));   //返回字符串中的整数部分,遇到NaN停止 返回123

//第二个可选参数是进制
console.log(parseInt("ff",16));    //按16进制解析,结果是10进制255
console.log(parseInt("0xa"));     // 10

/*
        parseFloat()返回带小数点的
            在底层parseFloat会先判断传入的参数类型,转换成字符串;
            如果传入对象,会默认调用对象的toString()方法
 */
console.log(parseFloat("12.3254a"));

console.log({}.toString());   //  打印 "[object Object]"


//ES6次方简写
console.log(3**2);  //表示3的平方

14.5 立方根cbrt,e的幂exp, 单精度浮点 fround

//   cbrt是取立方根结果,类似  Math.pow(27,1/3)
console.log(Math.cbrt(27),Math.pow(27,1/3));          //3 3

//   exp是自然对数e的幂函数,e^ln2 = 2;
console.log(Math.exp(Math.LN2),Math.exp(Math.LN10));  //2 10

//  转成最近的单精度浮点数的数字
console.log(Math.fround(100.1));

15. 对象方法

15.1 对象遍历 for in

let a={
    name:'阿飞',
    'age':18,
    marry:true,
    handsome:true
}

//for in循环,遍历对象,也可以是数组
for(let key in a){
    console.log(key,":",a[key]);
}

15.2 对象的增删改查

//对象的属性是无序的,一般按照字母先后顺序展示
let a={
    name:'阿飞',
    age:18,
    marry:true
}

console.log(a);  //这里a是引用,后面改了,这边也能相应

//增
a.GF = ['朱雀','丫丫','岚岚','茜茜'];

//改
a.age = 21;

//删除
delete a.marry;

//查找,是否存在
console.log('age' in a);

15.3 json JSON.stringify() JSON.parse()

//json  是一个格式非常标准长得像对象的字符串
//通用字符串,基本上所有语言都能识别的字符串格式

//let a = '{"name":"阿飞","age":18,"marry":true}';

let a={
    'name':'阿飞',
    age:18,
    marry:true
};

//将一个对象转为JSON格式  JSON.stringify() 反序列化
let b=JSON.stringify(a)
console.log(b);

//将JSON序列化,  JSON.parse()   解析成对象
let c = '{"a":10,"b":"狗蛋","c":true}';
//必须是标准严格的JSON格式才能解析,里面必须用双引号包起来""
console.log(JSON.parse(c));

15.4 es6的默认值

let [a,b=10]=[5];                  // a=5  b=10
let {x:hh,y:tt=20} = {x:11};       // hh=11  tt=20
 
// function fn([a,b]) {
//     console.log(a,b,arguments);
// }
// fn([5]);

function fn({a=10,b=100}) {
    console.log(a,b,arguments);
};
//fn({a:5});
//fn({a,b});
fn({});  // 10 100

//无实参取形参的默认值{x,y},有实参对应实参的默认值{x:10,y:30}
function ffn({x,y} = {x:10,y:30}) {
    console.log(x,y);
}
ffn();     //10  30
ffn({});   //un un

15.5 箭头函数

/*
    ES6     箭头函数
        () =>
 */
/*      形参  返回值 */
let fn = v => v;
//ES5写法如下
var fn = function (v) {
    return v;
}


/* 加法写法 */
var fn = function (a,b) {
    return a+b;
}
let fn = (a,b) => {a+b};


/*  函数内容较多   */ 
var fn=function (a,b) {
    let c = a+2;
    let d = b-3;
    return(c+d);
}
let fn = (a,b)=>{
    let c = a+2;
    let d = b-3;
    return(c+d);
}


/*  如果返回对象时,需要再加上()  */
var fn = function () {
    return {a:10,b:20};
}
let fn = () => ({a:10,b:20})


/*
document.onclick = function () {
    console.log(this);
}
*/

//通常用在回调函数内,方便使用
let arr=[1,2,3];
arr.forEach((value,key)=>{
    console.log(value);
});
let b = arr.map(v=>v*v);  //结果平方返回
console.log(b);

16.定时器

16.1 setTimeout(cb,T)

/*
    setTimeout  一次执行定时器
        param1:回调函数,或者是字符串包裹的js脚本,或者是引号包裹的全局作用域内的函数自执行
        param2:数字(毫秒单位)
 */

setTimeout(function () {
    alert("timeout!");
},1000);



let fn = function () {
    alert(1);
    return function () {
        alert(3);
    }
};
setTimeout(fn(),1000);    //不能是返回值,第一个参数是函数



let str = "let a=10;alert(a);";    //可以接收字符串参数,当成JS代码来读
setTimeout(str,2000);


let fn = function () {          // 如果fn不在全局作用域内,则 "fn()"找不到将报错
    alert(4);
};
setTimeout("fn()",1500);         //默认在全局中执行引号的内容,作用域在全局

16.2 setInterval(cb,T)

/*
    setInterval   循环定时
 */

let num=0;
let fn = function () {
    console.log(++num);
}
setInterval(fn,1000/60);       //最小时间间隔最多是60次每秒,

16.3 定时器队列

主程序执行完之后才执行定时器队列

//读到setTimeout时将定时器放入队列中,主程序执行完之后才执行队列
//所以先弹出3,后弹出4

setTimeout(function () {   //进入队列后执行
    alert(4);
},0);

!function fn() {        //先执行
    alert(3);
}();

16.4 参数

回调函数带参时,放在定时器第二个参数之后

//定时器的函数有参数时,直接放在第二个参数之后

(function () {
    function fn(a,b) {
        console.log(a+b);
    }

    //setInterval(fn(2,7),1000);   //这样会直接执行
    
    /*
    setInterval('fn(2,7)',1000);        //双引号内的内容默认丢在全局中执行,全局中找不到fn,报错
    window.fn = fn;  //将局部fn赋值到window
    */
    
    setInterval(fn,1000,25,14);      //参数接着放
})();

16.5 返回值

/*
       返回值是按定时器出现顺序从1号开始的编号,作用是用来清除定时器的
       编号不区分作用域
 */
let x = setTimeout(function(){alert(3);},50000);
let y = setTimeout(function(){alert(4);},60000);
let z = setTimeout(function(){alert(5);},70000);
let w = setInterval(function(){alert(6);},80000);
let v = setInterval(function(){alert(7);},90000);
console.log(x,y,z,w,v);       // 1 2 3 4 5

16.6 清除定时器

  • clearInterval(t)
  • clearTimeout(t)
let x = setTimeout(function(){console.log("a")},2000);         // 1

let y = setTimeout(function(){console.log("b")},2000);         // 2

console.log(x,y);

clearTimeout(y);      //清除编号为2的定时器

// 定时器的队列编号跟作用域没关系,按出现顺序编号
(function () {
    let x = setTimeout(function(){console.log("a")},2000);     // 3

    let y = setTimeout(function(){console.log("b")},2000);     // 4
    console.log(x,y);
})();

16.7 requestAnimationFrame(cb)

canselAnimationFrame()

/*
    H5出的新的API
    requestAnimationFrame()   不需要第二个参数,间隔是浏览器的刷新频率,单次执行
    主要是让动画很流畅,浏览器准备好就刷新

    CSS3关于动画的API底层都是它

    取消
    canselAnimationFrame()
 */

let oW = document.getElementById("wrap");
let start=0;
function m(){
    start += 2;
    oW.style.left = start+'px';
    requestAnimationFrame(m);
}
requestAnimationFrame(m);


// 兼容
window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
    setTimeout(fn,1000/60);
};
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

16.8 案例,自动无缝轮播图

关键点: oImg.style.transitionDuration = 0+'s';



    
        
        Title
        
    
    
        
< >

17. 时间API

17.1 Date类

/*Date类
    new Date()
        本地此时此刻的日期对象/时间戳
 */

let d = new Date();             //获取的是对象
console.dir(d);

console.log(d.getTime());        // 时间戳
let t = new Date(d.getTime());
console.log(t);

//以下API返回数字   number
console.log(d.getFullYear());         //得到  年
console.log(d.getMonth()+1);          //得到  月(从0开始计数,应该+1返回)
console.log(d.getDate());             //日
console.log(d.getHours());            //时
console.log(d.getUTCHours());         //0时区  UTC
console.log(d.getMinutes());          //分
console.log(d.getSeconds());          //秒
console.log(d.getDay());              //星期   星期日是0

console.log("====================");

console.log(d.toUTCString());
let x = new Date();  //日期对象可以做减法,会自动调用getTime进行相减
//定时器都不是 精准的计时
setInterval(function () {
    let y=new Date();
    console.log(y-x);
    x=y;
},50);      //周期很小,则误差较大

17.2 设置时间戳

//无参是获取,有参是设置
let x=new Date(2018,8-1,8,1,1,1);    //月份从0开始的,所以设置8月应输入7
let x=new Date(2018);    //只有一个参数时,会被认为是毫秒时间戳,从1970年开始加
let x=new Date(2018,5-1);  //默认1日,0时0分0秒
console.log(x);


let a = new Date().getTime();
console.log(new Date(a-3600000));   //打印一个小时前的时间

17.3 网页倒计时跳转

404 页面未找到~~

8秒后,返回 主页

17.4 新年倒计时

(function () {
    let oW = document.getElementById("wrap");

    let x = new Date(2020,2-1,24);  //过年时间

    function fn(){
        let d = x - new Date();    //差了多少秒

        let DD = Math.floor(d/1000/60/60/24);   //天
        let HH = Math.floor(d/1000/60/60%24);
        let MM = Math.floor(d/1000/60%60);
        let SS = Math.floor(d/1000%60);

        if(DD<10) DD = '0'+DD;
        if(HH<10) HH = '0'+HH;
        if(MM<10) MM = '0'+MM;
        if(SS<10) SS = '0'+SS;

        oW.innerHTML = `距离过年还有 ${DD}${HH} 小时 ${MM}${SS} 秒;`;
    };
    fn();

    setInterval(fn,1000);
})();

18. 运动框架

18.1 基础的移动



    
        
        Title
        
    
    
        

18.2 封装好的运动框架



    
        
        Title
        
        
        
        
        
    
    
        
'use strict';
/*
 * 运动框架
 * param:
 *      ele     - object 必须 表示要进行运动的节点
 *      attr    - string 必须 表示要改变的css属性
 *      target  - number 必须 表示属性的终点值
 *      step    - number 选填 表示运动速度的正值,默认5
 *return:
 *
 */
window.Move = function () {
    //兼容定时器
    window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
        setTimeout(fn, 1000 / 60);
    };
    window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

    //框架函数
    return function Move(ele, attr, target) {
        var step = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;

        //ele.style.marginLeft  只能获取行内样式
        //console.log(getComputedStyle(ele));              //原生JS,存储着节点对象全部的样式

        //获取存储着ele展示样式的对象
        var cssObj = ele.currentStyle || getComputedStyle(ele); //解决兼容性问题IE8用currentStyle
        //初始的值
        var sVal = parseFloat(cssObj[attr]); //去掉单位,变成数字
        //兼容IE的opacity
        if(attr === "opacity" && isNaN(sVal))sVal=1;

        //考虑初始值与目标值大小的问题
        var bool = sVal>target;
        if(sVal > target){
            step = -Math.abs(step);   //负值
        }else if (sVal < target){
            step = Math.abs(step);    //正值
        }else{
            return;
        }

        function f() {
            sVal += step;         // + -step
            if (bool?sVal<=target:sVal>=target) {
                sVal = target;
            }else {
                requestAnimationFrame(f);
            }
            if(attr === 'opacity'){
                ele.style[attr] = sVal;
                ele.style.filter = "alpha(opacity="+100*sVal+")";      // IE浏览器兼容
            }else if(attr === 'zIndex'){
                ele.style[attr] = sVal;         //不加单位
            }else{
                ele.style[attr] = sVal + 'px';   //加单位
            }

        }
        requestAnimationFrame(f);
    };
}();

19. DOM

19.1 节点nodeType nodeName nodeValue

 /*
     元素节点的nodeType是   1     nodeName是 大写的标签名   nodeValue=null
     元素属性的nodeType是   2     nodeName是 属性名        nodeValue=属性值
     文本节点的nodeType是   3     nodeName是 #Text         nodeValue=文本内容
     注释节点的nodeType是   8     nodeName是 #comment      nodeValue=注释内容
  */
 let oW = document.getElementById("wrap"),
 oC = document.getElementsByClassName("content")[0];

 console.dir(oW);
 console.log(oW.nodeType);       //1  元素节点
 console.log(oW.nodeName);       //DIV

 console.log(oW.childNodes);     //子节点,包含所有节点类型

console.log(oW.attributes[2].nodeType);         // 2
// console.log(typeof oC.childNodes[0].nodeValue);

 oW.attributes[2].nodeValue = '朱雀';   //不建议这样修改,应该坐标是不确定的
 console.log(oW.attributes[2]);        // afei='朱雀'

19.2 子节点 childNodes children

阿飞飞

gg

ss

gg

19.3 插入节点createElement

  • createElement 创建元素节点
  • createTextNode 创建文本节点
  • appendChild 创建的是子节点
  • insertBefore(A,B) 创建子节点,A元素节点放在B元素节点之前
阿飞飞

pp

gg

123

19.4 修改节点位置

阿飞

朱雀

19.5 删除节点 removeChild()

555

666

19.6 获取节点

  • firstChild 第一个子节点,一般获取的都是文本节点 ->换行符
  • firstElementChild 第一个元素子节点
  • nextSibling 下一个兄弟节点
  • nextElementSibling 下一个兄弟元素节点
  • previousElementSibling 上一个兄弟元素节点

11

22

33

  • parentNode 父亲节点
  • offsetParent 定位父级,离得最近的拥有定位的父级,都没有时就是body

    
    Title
    


    

4545454

19.7 克隆节点 oP.cloneNode()

节点的事件不被克隆

  • oP.cloneNode() 默认不复制内容
  • oP.cloneNode(true) 包括内容全部复制,但事件不会复制

745545

444

19.8 节点替换 replaceChild(A,B) , A将B替换掉

123
456

19.9 节点片段 document.createDocumentFragment()

(function () {
    let oW = document.getElementById("wrap");

    //生成10个小球
    (function () {
        //节点片段,暂时存放节点的对象
        let oF = document.createDocumentFragment();

        //生成十个小球,一次性append进oW内,省的渲染多次
        for(let i=0;i<10;i++){
            let oP = document.createElement("p");
            oF.appendChild(oP);
        }
        oW.appendChild(oF);
    })();

    //运动
    (function () {
        let aP = [...oW.children];
        let MaxL,MaxT;

        window.onresize = (function r(){
            MaxL = window.innerWidth - 100;
            MaxT = window.innerHeight - 100;
            return r;
        })();

        //随机初始速度
        let speedArr = [];
        aP.forEach((ele,index)=>{
            speedArr[index] = {
                stepX : Math.floor(Math.random()*12+4),
                stepY : Math.floor(Math.random()*12+4)
            };
        });

        //随机颜色
        function changeColor(ele) {
            let [r,g,b] = [
                Math.floor(Math.random()*256),
                Math.floor(Math.random()*256),
                Math.floor(Math.random()*256)
            ];
            ele.style.backgroundImage = `radial-gradient(white,rgb(${r},${g},${b}))`;
        }

        //遍历运动
        !function m(){

            aP.forEach((ele,index)=>{
                let left = ele.offsetLeft + speedArr[index].stepX;
                let top = ele.offsetTop + speedArr[index].stepY;

                if(left >= MaxL){
                    left = MaxL;
                    speedArr[index].stepX = -speedArr[index].stepX;
                    changeColor(ele);
                }
                if(left <=0){
                    left = 0;
                    speedArr[index].stepX = -speedArr[index].stepX;
                    changeColor(ele);
                }
                if(top>=MaxT){
                    top = MaxT;
                    speedArr[index].stepY = - speedArr[index].stepY;
                    changeColor(ele);
                }
                if(top<=0){
                    top = 0;
                    speedArr[index].stepY = - speedArr[index].stepY;
                    changeColor(ele);
                }
                ele.style.left = left+'px';
                ele.style.top = top + 'px';
            });

            requestAnimationFrame(m);
        }();

    })();


})();

20. DOM宽高属性与事件对象

20.1 视图页面宽高,无单位

  • window.innerWidth
  • document.documentElement.clientWidth

20.2 元素宽高,无单位

  • getComputedStyle(oWrap).width css样式宽度,有单位
  • oWrap.clientWidth 客户端宽度 width+padding 无单位
  • oWrap.offsetWidth 客户端宽度 + border
  • oWrap.scrollWidth 滚动宽度,一般用在出现滚动条, = 客户端宽度
/*
number类型
    clientHeight/clientWidth        width+padding
    offsetHeight/offsetWidth        width + padding + border
    scrollHeight/scrollWidth        滚动宽度,超出视图仍显示正常宽度,不管有没有超出隐藏
*/

let oWrap = document.getElementById("wrap");

console.log(getComputedStyle(oWrap).width);       //获取元素css样式设置的宽度,有单位
console.log(oWrap.clientWidth);   //width + padding
console.log(oWrap.offsetWidth);   //width + padding + border

//scrollWidth  元素占用的宽度,生成滚动条,内容不超出时数值等于clientWidth
console.log(oWrap.scrollWidth);   //如果有超出部分,正确的反映出超过之后的宽度,不管有没有加超出隐藏

20.3 定位left值offsetLeft与top值offsetTop

只有距离定位父级的左值和上值 ,没有右下



    
        
        Title
        
    
    
        
8888

20.4 body的滚动高度,用document.documentElement.scrollTop


    

20.5 元素的滚动高,父级的scrollTop



    
        
        Title
        
    
    
        

20.6 scrollTop无单位,可以赋值


    

20.7 getBoundingClientRect()获取边界客户端矩形,对象形式,无单位



    
        
        Title
        
    
    
        
8888

20.8 oW.scrollIntoView(true) 滚动到可视区



    
        
        Title
        
    
    
        

20.9 event事件对象

/*
    event事件对象
        事件函数执行时,第一个形参就是事件对象:存储着和该次事件相关的一些信息
        IE8及以下浏览器,使用event全局变量来表示事件对象

    该对象里面比较重要的一些属性
        clientX/clientY  事件触发时,鼠标距离可视区的距离
        pageX/pageY      鼠标距离文档的位置(IE8 不兼容)
 */

//IE的事件函数没有形参
//兼容
document.onclick = function (ev) {
    ev = ev || window.event;  // IE的Event是全局变量
    console.log(ev);         
}

20.10 鼠标事件 onmousedown onmousemove onmouseup

document.onmousedown = function () {
    console.log("down");
    document.onmousemove = function () {
        console.log("move");
    }
}

document.onmouseup = function () {
    console.log("up");
    document.onmousemove = null;         //默认属性是null
}

20.11 案例:可拖拽的盒子



    
        
        Title
        
    
    
        

20.12 案例:十球发射



    
        
        Title
        
        
        
        
    
    
        

21. DOM事件

21.1 事件冒泡

冒泡触发顺序:从子元素开始到窗口

  • event.stopPropagation() 主流浏览器阻止冒泡:
  • event.cancelBubble = true; IE阻止冒泡
box1
box2

21.2 事件监听

  • attachEvent("onclick",cb) IE8
  • detachEvent(事件类型,回调方法);
  • addEventListener(事件类型,回调方法,捕获|冒泡) 主流浏览器
  • removeEventListener(事件类型,回调方法,捕获|冒泡);

捕获与冒泡顺序相反

var oW = document.getElementById("wrap");

//DOM 0级事件,   相同名字的事件被覆盖,只能监听一个事件
oW.onclick = function () {
    console.log(1);           //被覆盖
};
oW.onclick = function () {
    console.log(2);
};



/*
     事件监听(默认事件冒泡)
        用到事件的地方最好就是使用 DOM2级来监听

     监听事件
        主流浏览器         事件类型  "click"
            ele.addEventListener(事件类型,回调方法,捕获|冒泡)
            1.this指向节点本身
            2.捕获与冒泡
                默认是false  冒泡事件
                true为捕获,与冒泡的顺序相反,从最大父级到子级开始(也能使用阻止冒泡的方式)

        ie浏览  ie8       事件类型  "onclick"
            oW.attachEvent(事件类型,回调方法)
            1.this不再指向节点本身,指向window
            ie8没有事件捕获,默认是冒泡事件

     移除事件
        主流浏览器
            ele.removeEventListener(事件类型,回调方法,捕获|冒泡);

        IE8
            ele.detachEvent(事件类型,回调方法);

 */
//事件监听DOM   2级事件
//IE8
oW.attachEvent("onclick",function (e) {
    e = e||window.event;
    console.log(this);      //this 不再指向监听事件的节点本身
    console.log(e);
});

/* 主流浏览器  */
oW.addEventListener("click",function () {
    console.log("我又监听了一次点击事件,理解一下DOM 2级事件");
})


var callback = function () {
    console.log(1);
};
oW.addEventListener("click",callback);

//文档双击,注销事件
//该事件必须事先用变量保存,removeEventListener的参数必须与添加事件监听的参数一样,才能移除
document.ondblclick = function () {
    oW.removeEventListener('click',callback);
}

21.3 事件默认行为

  • oncontextmenu 默认行为指右键可选事件
  • return false; dom0级阻止默认行为
  • event.preventDefault(); 阻止默认行为
  • event.returnValue = false; IE8阻止默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

默认行为

21.4 滚轮事件

  • mousewheel 滚轮事件 event.wheelDelta 滚动的幅度 下负上正 120 谷歌+ie
  • DOMMouseScroll 火狐的滚轮事件 event.detail 滚轮的幅度 上负 3
let oW = document.getElementById("wrap");
/*
        谷歌以及ie
        event.wheelDelta   滚动的幅度
            -120  下滚
            120   上滚

        火狐的  滚动事件名都不一样
            DOMMouseScroll  只能通过DOM 二级事件监听
            event.detail   滚动的幅度
                3  下滚
                -3 上滚

        只有谷歌和ie有onmousewheel事件属性,默认值为null
        火狐根本就没有onmousewheel属性,为undefined
 */

/*
oW.addEventListener("mousewheel",function (e) {
    console.log(e.wheelDelta);
})
*/

//只能通过创建一个新的节点来判断兼容
if(document.createElement("div").onmousewheel === null){
    console.log("谷歌");
}else{
    console.log("火狐");
}

兼容的事件监听

var oW = document.getElementById("wrap");

//元素的事件
var fn = addEvent(oW,'click',function () {
    this.style.backgroundColor = 'red';
});

//文档双击移除事件
addEvent(document,"dblclick",function () {
    removeEvent(oW,'click',fn);
})

//滚轮事件
addEvent(oW,'mousewheel',function () {
    console.log('我滚动了');
})


//添加监听事件
function addEvent(ele,eType,callback,capture) {

    //主流浏览器
    if(ele.addEventListener){

        //兼容一下火狐的滚轮事件
        if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
            eType = 'DOMMouseScroll';
        }

        ele.addEventListener(eType,callback,capture);

        return callback;
    }else{
        //处理ie的this指向,ie低版本不支持bind
        var codeCall = function(){
            callback.call(ele);
        }
        ele.attachEvent('on'+eType,codeCall);

        return codeCall;
    }
}

//移除事件
function removeEvent(ele,eType,callback,capture) {
    ele.removeEventListener? ele.removeEventListener(eType,callback,capture)
                            : ele.detachEvent("on"+eType,callback);
}

兼容的文档滚动

//自定义滚动
addEvent(oW,'mousewheel',function (event) {
    event = event || window.event;
    var dir;
    if(event.detail){       //火狐的滚动值
        dir = event.detail / 3;        //下滚
    }else{
        dir = event.wheelDelta / -120; //下滚
    }
    //console.log(dir);
    this.scrollTop += dir*50;
})

21.5 案例 自定义滚动条



    
        
        Title
        
        
        
        
    
    
        
  • 1. It is never too old to learn.

    活到老,学到老。

  • 2. There is no royal road to learning.

    学问无坦途。书山有路勤为径,学海无涯苦作舟.

  • 3. A man becomes learned by asking questions.

    不耻下问才能有学问。

  • 4. A young idler, an old beggar.

    少壮不努力,老大徒伤悲。

  • 5. Study to be what you wish to seem.

    学习可成为你所理想的人物。

  • 6. By reading we enrich the mind, by conversation we polish it.

    读书使人充实,交谈使人精明。

  • 7. Books and friends should be few but good.

    读书如交友,应求少而精。

  • 8. Readingis to the mind while exercise to the body.

    读书健脑,运动强身。

  • 9. A good beginning makes a good ending.

    良好的开端就是成功的一半。 善始者善终。

  • 10. No matter how bad your heart has been broken, the world doesn’t stop for your grief. The sun comes right back up the next day.

    不管你有多痛苦,这个世界都不会为你停止转动。太阳照样升起。

  • 11. Experience is the mother of wisdom.

    实践出真知。

  • 12. Don't trouble trouble until trouble troubles you.

    不要自寻烦恼。

  • 13. Everybody dies, but not everybody lives.

    人人都会死,但非人人都曾活过。

  • 14. Doing is better than saying.

    行胜于言。

  • 15. Commitment in many, can do. It is just a lie.

    承诺再多,都做不到。那也只不是是谎言。

  • 16. No cross, no crown.

    不经历风雨,怎能见彩虹。

22. 表单事件

22.1 表单事件

455454

22.4 案例,限制焦点

多按键同时控制




    
    Title
    
    
    
    


    

23. 正则表达式

23.1 有什么用

不用正则时,一般用 !isNaN(121)=true 来提取数字

/*
    正则表达式
        对象
        配合一些api来验证字符串
 */
let a="456阿飞789朱雀12";   //["456","789,"12"]
let b="454sjjdsiaodao5454";
let c="sds45sd45s21a";

console.log(fn(a));
console.log(fn(b));
console.log(fn(c));
console.log("*************************");
console.log(zz(a));
console.log(zz(b));
console.log(zz(c));

function zz(str) {
    return str.match(/\d+/g);
}

function fn(str) {
    let len = str.length;
    let s ="";
    let arr = [];
    for(let i=0;i

23.2 正则表达式

创建正则表达式对象的两种方法

  • let a = /abc/
  • let b = new RegExp("abc")

验证正则的方法

  • a.test(str) 返回 true or false
/*
    正则表达式对象 两种创建方式
        1. 双斜杠包括的字符
        2. new RegExp("")
 */

let a = /abc/;
console.log(typeof a);      //object
let b = new RegExp("abc");  //和第一种创建的效果一样

/*api1

    test()
    正则.test(字符串)
    匹配成功返回true,否则返回false
 */
let a = /abc/;    //匹配完整连续的abc字符串
console.log(a.test("阿飞abc朱雀"));;



/*
     / /不能传变量
 */
let s = "abc";
//let a=/s/;       //这种定义方式,是没有办法根据变量来制定正则的
let a = new RegExp(s);      //可以用变量
console.log(a.test("阿飞abc朱雀"));

23.3 转移符号\的用法

字符串中实现转义 "\\" 打印 "\"

/*
    \转义符号,默认在字符串中的\有特殊意义,不能单独出现
 */
console.log("阿飞\"love\"朱雀\n123456\t789021");

//转义符号将有特殊意义的字符变成没有特殊意义
let str = "/\\";
let a=/\/\\/;          //用转义字符"\"转义"/"和"\"
console.log(a.test(str));


/*
    转义符号配合一些字母使用,有非常独特的意思
        \s   各种空格, \t  \n  \r  " "
        \S   非空格,\s的补集

        \d   数字
        \D   \d的补集

        \w   数字、字母、下划线   一般匹配用户名的
        \W

        \b  连词符 起始  结束  (空格 以及 (除了\w之外)  所有内容都是独立部分)
        \B
 */
let a = /\s/;
let s = "   ";

let a=/\d\d/;        //连续两个数字
let s="fffff79pppp";

let a = /\w/;
let s = "abc";

/*  算作"afei"独立的字符
        "I am afei-1"
        "I am afei阿飞"
        "I am afei.abc"

    \b只能用于匹配英文,中文本身就不独立,不能使用\b独立匹配
 */
let a = /\bafei\b/;    //要匹配独立的部分
let s = "I am afei.abc";   //可以   "afeihui"就不行
console.log(a.test(s));

23.4 修饰符 i m g

验证正则的方法 match

  • str.match(a) 返回所有匹配正则的元素组成的数组,(a是加了g的全局匹配)
/*
    修饰符(写在//后面
        i   不区分大小写
        g   全局匹配
        m   换行匹配
 */
let a = /g/i;
let s = "G";
console.log(a.test(s));


/*
    .match()
    字符串.match(正则)
    寻找匹配的内容,拿到并组成一个数组返回,否则返回null
 */
let a = /xx/ig;
let s = "XxgfxxhxXx";     //xXx只能识别前两个
console.log(s.match(a));  //加了g后是纯粹的数组,没有别的属性

23.5 量词 {n}

/*
    量词 { }
        {n} n个
        {n,m} n~m包含n也包含m
        {n,} n~无穷大 包含n

            默认按多的取(贪婪模式)
            量词后面加问号"?"就成了(惰性模式)

    几个特殊量词有专属的符号代替
        {1,}   +            至少一个
        {0,}   *            至少0个
        {0,1}  ?            要么有要么没有

 */
let a = /\d\d\d\d\d\d\d\d\d\d\d/g;
let s = "阿飞18860900316阿飞";

let a = /飞\d{11}/g;  //{11}只表示\d重复11次
let s = "阿飞18860900316阿飞15357875321";

let a = /\d{2,4}?/g;   // 惰性匹配,所以只匹配2个的 
let s = "1-23-234-456阿飞18860900316阿飞15357875321";
// ["23", "23", "45", "18", "86", "09", "00", "31", "15", "35", "78", "75", "32"]

let a = /\d{2,}/g;          //至少2个
let s = "1-23-234-456阿飞18860900316阿飞15357875321";
// ["23", "234", "456", "18860900316", "15357875321"]


//let a = /\d+/g;      //最少一个取
//let a = /\d+?/g;     //匹配到后,一个个取
//let a = /\d*?/g;     //返回的全是空  相当于 //g
let a = /\d??/g;       //全是空
let s = "gh777scsf45dsdsd454s35";
console.log(s.match(a));

23.6 子项()

加了括号的成为子项,使用全局g,则不打印子项

获取第一个子项 s.match(a)[1]

匹配失败,返回null

/*
    子项 ( )
 */

let a = /(ab)+/;    //  不加括号,只能匹配abbbb
let s = "abababab"; //  ["abababab", "ab", index: 0, input: "abababab", groups: undefined]

let a = /gg(ab)+f(f)/;    //加了括号的子项也会打印出来,使用全局g,则不打印子项
let s = "ababggababffababa";  
//不加g,打印子项["ggababff", "ab", "f", index: 4, input: "ababggababffababa", groups: undefined]


//利用子项,只获取子项中的号码
let a = /阿飞:(\d{11})/;
let s = "阿飞:12121212321,朱雀:32321232123";
console.log(s.match(a),s.match(a)[1]);
// ["阿飞:12121212321", "12121212321", index: 0, input: "阿飞:12121212321,朱雀:32321232123", groups: undefined] "12121212321"

23.7 一个[]字符集只匹配一个字符

/*
    |   或者
    []  字符集,一个字符集只匹配一个字符
        [a-z]  字符区间("-"在"[]"内有了特殊意义)
        [abc]  或者的意思
        [^abc] 放在正则字符的首位,表示除了这些,(不放在首位表示一个单纯的字符)
        [{}?*.+()] 这些原来有特殊意义的字符放在[]内没有了特殊意义,就是单纯的字符

        [a-z]
        [A-Z]所有的字母

 */

let a = /abc|edf/g;       //或者匹配
let s = "edfabcedfabc";

let a = /(阿飞|朱雀)老师/g;       //用子级匹配,加外面公用的
let s = "朱雀老师美,阿飞老师帅";

let a = /1|2|3|4|5|6|7/g;      //1或者7中的任何一个
let a = /[1-7]{5}/g;           //区间,代表1到7之间任何一个连续5个

//ascii码的匹配,注意要有前后顺序
let a = /[2-B]/g;
let s = "23456789:;C<=>?@AB";

//unicode字符编码也能匹配
let a = /[阿-飞]/g;      //意义不大
let s = "阿飞老师";


let a = /[abc0-9]/g;       //a或b或c,0到9
let s = "2345abc";

//匹配所有的数字和字母
let a = /[a-zA-Z0-9]/g;
let s = "2345abcAfejnfjGHjfbj";

let a = /[^abc]/g;       //除了,取反只能放在首位
let s = "2345abcAfejnfjGHjfbj";

let a = /[{}?*./+()[\]\-]/g;       //字符集内的字符失去了特殊意义
let s = "2345abcAfejnfjGHjfbj";
console.log(s.match(a));

23.8 起止字符

/*
    起止字符
       ^    起始位置
       $    结束位置
 */

let a = /^abc$/;      //只能匹配"abc",空格都不可以有
//let s = "gabcgg";   //必须是a起始的字符串才能匹配
let s = "gabcgg";
console.log(s.match(a));


//
console.log("ddabcdd".match(/(a|^)bc/));     // abc   a是子项
console.log("bcjfjfjfjfj".match(/(a|^)bc/)); // bc    子项为""

23.9 .字符

/*
    .  匹配任意字符   除了换行等之外  \n  \r

    [.]的.是单纯的匹配字符.
 */

let a = /./g;
let s = ".123\r46\n5";
console.log(s.match(a));

//匹配所有的字符
/[\s\S]/
/[\w\W]/

23.10 应用案例

/*
                /a/
                new RegExp()
                \s \S \w \W \d \D \b \B
                修饰词  igm
                量词{} *+?      惰性?取短的
                子项()
                字符集[]
                | ^  $  .

             */

let reg={
    //qq:5~10,只能是数字,第一位不是0
    qq: /^[1-9]\d{4,9}$/,
    //用户名:6~18,数字字母_,必须要字母开头
    user:/^[a-z]\w{5,17}$/i,
    //密码:6~18,数字字母_所有符号
    pwd:/^[\w<>,.?/\-+=*@#$%^&()[\]`~|\\{}<>]{6,18}$/,
    //手机号:
    tel:/^1[3-9]\d{9}$/,
    //邮箱
    mail:/^[a-z1-9_]\w{0,17}@[0-9a-z]{2,}(\.[a-z]{2,4}){1,2}$/i,
    //身份证
    IDCard:/^[1-9]\d{5}(18|19|20)\d{2}(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))\d{3}[0-9x]$/i,

}

// let a = reg.qq;
let b = reg.mail;
// let s = "3045282682";
// console.log(a.test(s));
console.log(b.test("[email protected]"));

// let a = reg.IDCard;
// console.log(a.test("341221199411178765"));

//大月
//31天
/*
            /(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])/
            //30天
            /(0[469]|11)(0[1-9]|[12][0-9]|30)/
            //2月
            /(02(0[1-9]|[12][0-9]))/
            //一起
            /(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))/

            /((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9])))/
            */

23.11 捕获组

捕获的是子项 RegExp.$1 最近的一次正则结果中的子项

捕获用 \n 表示,代表一个子项

let a = /a(b)(c)/;
let s = "abc";
console.log(a.test(s));


let a = /(阿飞|朱雀)老师/;
let s = "abc阿飞老师";
let s1 = "abc朱雀老师";
a.test(s);
s1.match(a);
console.log(RegExp.$1);      //离它最近一次正则结果的子项1  朱雀
console.log(RegExp.$9);      //最多存9个子项  没有就是 空



//捕获组,1表示重复第1个子项,没有加g,所以第一次匹配到后就结束匹配
let a = /(\d)\1/;     //捕获组,重复子项   aa bb
let a = /(\d\d)\1/;   //捕获组,重复子项   abab
let a = /(\d(\d))\1\2/; //捕获组,重复子项   ababb
let a = /(\d\d)\1{9}/;  //捕获组,可以用量词   abab*n
let a = /(\d(\d))\2\1/; //捕获组,重复子项   abbab
let s = "797994545545";

console.log(s.match(a));

23.12 案例 表单验证



    
        
        Title
        
        
        
        
    
    
        

注册

请先输入密码!

23.13 正向断言(?=a)

/*
    断言,JS只有正向断言,放在后面,括号不算子项
        (?=a)    格式限定后面紧接着必须是a,但不希望匹配结果中有a
        (?!a)    格式限定后面紧接着不能是a
 */

 // let r = /(阿飞|朱雀)老师,\1老师/;
 // let s = "阿飞老师,阿飞老师";

let r = /Window(?=XP)/;   //希望格式是WindowXP,但不希望结果中有XP,所有用?    这个()不是子项
let s = "WindowXPx";

let r = /Window(?!XP)/;   //不希望格式是Window后接着XP,?!  这个()不是子项
let s = "Window111";

console.log(s.match(r));
console.log(RegExp.$1);

23.14 replace

/*
    replace
        str.replace(正则,字符串|函数);
        替换匹配到的内容变成第二个参数的内容
        (如果是字符串直接替换,如果是函数,替换返回值)
 */
let reg = /(阿飞|风屿|海文)(老师|先生|大大)/g;
let str = "阿飞老师是个纯粹的大猪蹄,风屿先生真自恋,海文大大脾气不好";

let newStr = str.replace(reg,"小浪");

let newStr = str.replace(reg,(...rest)=>{
     //经过了很多运算之后,得到用来替换的字符串
     console.log(rest);
     return '小浪';
});


let newStr = str.replace(reg,(a,b,c)=>{
    //经过了很多运算之后,得到用来替换的字符串
    console.log(a,b,c); //a表示正则形参,b表示第一个子项,c表示第二个子项
    return '小浪'+c+c.slice(1);
});

console.log(newStr);

23.15 脏字过滤器

    /*
        适合小数据的存储,字符串缓存,存在本地的
        1.不同的浏览器存放的cookie位置不一样,也是不能通用的
        2.cookie的存储是以域名形式进行区分的
        3.cookie的数据可以设置名字的
        4.一个域名下存放的cookie的个数是有限制的,不同的浏览器存放的个数不一样
        5.每个cookie存放的内容大小也是有限制的,不同的浏览器存放大小不一样
            本地文件不支持cookie,火狐浏览器支持,通过Webstorm打开支持
     */
    
    /*
        如果不给cookie设置过期时间,那么浏览器关闭之后,cookie就清除了
        在存储本地cookie肯定是需要设置过期时间的
        expires  一个日期对象转换成的字符串,默认是UTC时间
     */
    //每条cookie都需要单独设置,不支持一次赋值设置多个cookie
    document.cookie = "user=阿飞;pwd=123";     没用的
    
    let date = new Date(new Date().getTime()-7*24*3600*1000);
    document.cookie = "goudan=阿飞;expires="+date.toUTCString(); //date转成UTC时间进行赋值
    document.cookie = "pwd=123";
    
    //获取全部cookie
    console.log( document.cookie );
    

    24.2 封装cookie的增删改查API

    let Cookie ={
       //设置,修改
        set(mJson,day) {
            //设置过期时间,不设置day默认undefined,计算时 = NaN,此时设置的cookie关闭浏览器释放
            let date = new Date(new Date().getTime()+day*24*3600*1000).toUTCString();
            Object.entries(mJson).forEach(([key,value])=>{
                document.cookie = `${key}=${value};expires=${date}`;
            })
        },
       //获取
        get(key) {
             //不传值返回全部cookie构建的对象
            if(!key){
                let json=document.cookie;
                let obj={};
                while(json){
                    let reg=/(^|\s)(\w+)=([^;]+)(;|$)/;
                    let arr = json.match(reg);
                    json = json.split(arr[0])[1].toString();
                    obj[RegExp.$2]=RegExp.$3;
                }
                return obj;
            }else{
                let str = document.cookie;
                //  /(^|\s)aaa=([^;]+)(;|$)/
                let reg = new RegExp("(^|\\s)"+key+"=([^;]+)(;|$)");
                if(reg.test(str)){
                    return RegExp.$2;      
                }else{
                    return undefined;   //匹配不成功返回undefined
                }
            }
        },
       //删除
       remove(key) {
           Cookie.set({
               [key]:""    //清空
           },-1);
       }
    };
    
    Cookie.set({
        a:'阿飞',
        b:123,
        goudan:"afei"
    },7);  //7天
    
    //测试get
    console.log(Cookie.get("goudan"));
    //删除cookie
    Cookie.remove("b");
    

    24.3 ES6的Object的API

    //ES6写法 ,属性名的变量写法
    
    let a = "name";
    let obj= {
        [a]:"阿飞"          // 这里a加【】代指变量 “name”
    };
    console.log(obj);
    
    
    let afei= {
        name :"阿飞",
        age:18,
        sex:0
    };
    
    console.log(Object.keys(afei));        //提取对象所有属性名,返回数组
    console.log(Object.values(afei));      //提取对象所有值,返回数组
    console.log(Object.entries(afei));     //提取对象的键值,返回二位数组
    

    24.4 案例,cookie记录访问时间

    
    
        
            
            Title
            
            
            
        
        
            
    欢迎访问本站!您上次访问本站的时间为:2018-11-10,20:50:20

    25. ajax

    /*
        Ajax
            异步的javascript和xml
                同步
                    一心一意
                异步
                    三心二意
            功能
            无刷新页面的情况下,实现与后台的数据交互,同时在页面进行更新
        跨域
            默认不允许跨域请求资源
            安全问题
            前端能不能请求到数据,是后端说了算
     */
    
    //创建  ajax对象
    const ajax = new XMLHttpRequest();
    //监听状态的改变
    /*
        0~4
            0   初始化状态  ajax已经被创建
            1   open()方法已经调用
            2   send()方法已调用
            3   所有的响应已经收到
            4   http响应已经完全接收
     */
    ajax.onreadystatechange = function(){
        if(ajax.readyState === 4 & ajax.status === 200){
            //前端 就能够接收到数据了
            //console.log(ajax.response);
            //把对应的数据  转换成对应的数据类型
            console.log(JSON.parse(ajax.response));
        }
    }
    //路径不能出现中文
    //本地测试
    //ajax.open('get','./data.php',true);      //通过什么样的方式,向什么样的后端服务器  发送什么的请求(true表示异步)
    //ajax.send();                             //执行请求命令
    
    //真实服务器, 数据先行, 数据驱动视图
    ajax.open('get','http://www.tanzhouweb.com/48/data.php',true);
    ajax.send();
    

    25.1 封装一个ajax

    //调用方式
    ajax({
        url:"www.baidu.com",
        method:"get",
        data:{
            name:"peter",
            age:18
        },
        success:function(msg){
            
        },
        error:function(err){
            
        }
    })
    function ajax(json){
        var method  = json.method.toUpperCase() || "GET";
        var data = json.data || {};
        
        var xhr = new XMLHttpRequest();
        switch(method){
            case 'GET':
                xhr.open(method,json.url+"?"+jsonUrl(json.data),true);
                xhr.send(null);
                break;
            case 'POST':
                xhr.open(method,json.url,true);
                //设置post请求头
                xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
                xhr.send(jsonUrl(json.data));
                break;
        }
    }
    
    xhr.onreadystatechange=function(){
        if(xhr.readyState === 4){
            if(xhr.status>=200 || xhr.status<=300 || xhr.status === 304){
                json.success(xhr.responseText);      //responseText 才是服务器返回数据
            }else{
                json.error(xhr.status);
            }
        }
    }
    
    
    function jsonUrl(data){
        var arr=[];
        for(var key in data){
            arr.push(key+'='+data[key]);
        }
        return arr.join("&");
    }

    25.2 jsonp跨域解决方案

    /*
        jsonp   一种跨域问题的解决方案
    */
    function getData(data) {
        console.log(data);
    }
    
    //核心本质   就是后端服务器  返回一个函数调用   getData('js')
    createJsonp();
    function createJsonp() {
        const s = document.createElement('script');
        // s.src='http://www.tanzhouweb.com/48/jsonp.php?callback=getData';
        s.src='http://localhost/data.php?callback=getData';
        document.body.appendChild(s);
    }
    

    25.3 CORS服务器允许跨域

    设置响应头,res.writeHeader(200,{'Access-Control-Allow-Origin':'*'})

    /*
        cmd检测nodejs的安装
                node -v
                npm  -v
     */
    //通过 node的原生模块  http  搭建服务器  提供数据接口
    const http = require('http');
    
    http.createServer(function () {
        res.writeHeader(200,{
            'Access-Access-Control-Allow-Origin':'*'
        })
        res.end("hi~这里是node服务器返回的数据");
    }).listen(6060);
    

    express

    const express = require('express');
    const app = express();
    //在中间件设置允许前后端跨域
    app.use((req,res,next)=>{
        res.set('Access-Control-Allow-Origin','*');
        next();
    })
    

    26. 面向对象

    26.1 封装一个对象函数

    /*
        OOP
        封装  继承  多态
     */
    
    var afei = teacher(1111,'阿飞',18);
    var zhuque = teacher(2222,'朱雀',20);
    
    //封装一个对象函数
    function teacher(id,name,age) {
        var o = {};
        o.id = id;
        o.name=name;
        o.age=age;
        o.showID = function () {      //堆内存占用了多个
            alert(this.id);
        }
        return o;
    }
    

    26.2 new

    /*
        new Date()
        new Image()
        new XMLHttpRequest()
        new RegExp()
        new Array()
    
        new 关键词     后面紧跟一个  函数
            通过new执行函数对函数的影响:
                ①:函数内部生成一个全新的对象,函数的this指向这个对象
                ②:函数默认返回上述对象
     */
    
    //fn();    //函数自执行;非严格模式指向window,严格模式指向undefined
    function fn() {
        // console.log(this);   //new的this指向全新的对象,只有this能指向这个对象
        this.x = 10;
    }
    new fn();  //先初始化一个空{},然后将{}的proto即隐式原型指向fn的prototype,然后执行了fn.call({})将this作用域交予{},完成实例化
    console.log(new fn());   // fn {x: 10}
    
    var afei = new Teacher(1111,'阿飞',18);
    var zhuque = new Teacher(2222,'朱雀',20);
    
    console.log(afei.showID === zhuque.showID);  //false       每个对象都占用一个堆内存存放函数
    
    //构造函数  / 类
    function Teacher(id,name,age) {
        this.id = id;
        this.name=name;
        this.age=age;
        this.showID = function () {      //堆内存占用了多个
            alert(this.id);
        }
    }
    

    26.3 原型

    /*
        原型
        prototype  是一个对象数据类型
        它是构造函数的一个属性
    
        每一个实例都共享这个原型的属性
     */
    
    //构造函数
    function Teacher(id,name,age) {
        this.id = id;
        this.name=name;
        this.age=age;
    }
    // console.dir(Teacher);
    Teacher.prototype.x = 10;     //原型也是对象
    Teacher.prototype.showID=function () {       //所有实例公用一个showID属性
        alert(this.id);
    }
    
    var afei = new Teacher(1111,'阿飞',18);       //  实例
    var zhuque = new Teacher(2222,'朱雀',20);
    
    
    console.log(afei);
    console.log(afei.x,zhuque.x,afei.__proto__===zhuque.__proto__);
    console.log(afei.__proto__ === Teacher.prototype);  //实例的__proto__ 全等于 构造函数的 prototype属性
    // 构造函数的原型是对象数据类型 {x: 10, showID: ƒ, constructor: ƒ}
    
    //afei.showID();
    console.log(afei.showID === zhuque.showID);   // true   共享一个堆内存
    

    26.4 原型链

    /*
        当访问对象的属性时,先从自身找,自身没有,才进入原型中找;原型找不到去原型的原型里面找,直到Object.prototype 为止,因为Object没有__proto__属性,原型链到此结束
        实例没有 prototype 属性;Object没有__proto__属性
        
        构造函数的隐式原型是Function:   A.__proto__ === Function.prototype
        构造函数的原型是其实例的隐式原型:A.prototype === new A().__proto__  
        Function比较特殊               Function.__proto__.__proto__ === Object.prototype
        
        goudan.__proto__ = Fn.prototype   
        Fn.prototype.__proto__ = Object.prototype
     */
    function Fn() {
        this.x=10;            //实例的x属性
    }
    Fn.prototype.x=20;        //原型的x属性
    console.log(Fn.prototype.constructor === Fn);      //true  构造属性
    
    var goudan = new Fn();       //  实例
    
    console.log(goudan.x);
    console.log(goudan.__proto__ === Fn.prototype);            //true   Fn的原型
    
    console.log(Fn.prototype);
    console.log(Fn.prototype.__proto__ === Object.prototype);   //true   Fn.prototype 是 Object的原型
    // 构造函数的原型 是 Object 的实例化对象
    
    //Object不存在 .__proto__  属性,
    
    /*
        私有属性写在构造函数里面
        公共属性写在原型上
        先有原型,再有实例
     */
    function Teacher(n,a,i) {
        this.name = n;
        this.age = a;
        this.id = i;
    }
    /*
    Teacher.prototype.showID=function () {
        alert(this.id);
    }
    */
    Teacher.prototype = {      //重写了 prototype属性,注意保留constructor属性
        constructor:Teacher,
        showID:function () {
            alert(this.id);
        },
        showName:function () {
            alert(this.name);
        },
        showAge:function () {
            alert(this.age);
        }
    }
    
    var afei = new Teacher("阿飞",18,1111);
    afei.showID();
    
    /*
        原型链继承
            构造函数的原型 = 一个函数的实例化对象    实现继承该函数的原型链
     */
    function C() {}
    C.prototype.x = 10;
    
    function B() {}
    B.prototype = new C();       // B的原型指向C
    
    function A() {}
    A.prototype = new B();
    
    
    Object.prototype.x = 40;   //顶层链
    
    
    var a = new A();
    console.log(a.x);    //  10         原型链查找,就近原则
    
    /*
        得到一个实例的构造函数
     */
    function A() {}
    
    var a = new A();
    console.log(a.constructor);    //  A(){}   a没有constructor,实际上是原型 A.prototype.constructor
    
    
    //注意。原型链可能导致不确定
    function B() {}
    B.prototype = {};   // 这里将原型置为{},上一级原型不存在constructor,
    var b = new B();
    console.log(b.constructor); // Object() { [native code] }  再向上级找,找到Object原型的构造函数
    
    
    //所有大括号构建对象都相当于new一个Object对象
    // let x={};                   // 原型 = Object.prototype
    let x = new Object();
    

    26.5 ES5的继承

    先继承私有属性,然后是原型

    function A(n,a) {
        this.name = n;
        this.age = a;
    }
    A.prototype.getName = function () {
        return this.name;
    }
    
    //ES5实现继承(组合继承)
    function B(n,a,i) {
        A.call(this,n,a);    //1.继承了A的私有属性
        this.id = i;   //新增的私有属性
    }
    //2.再继承A的原型,这里只继承原型,所以使用中间构造函数,如果用new A(),原型会有A的属性
    function Fn(){};
    Fn.prototype = A.prototype;
    B.prototype = new Fn();         //这里只传递了原型,但原型缺少构造函数
    // 新增原型
    B.prototype.constructor = B;   // 补上构造函数
    B.prototype.xx=10;             // 新增原型
    
    
    var afei = new A('阿飞',18);
    var xinai = new B('心艾',20,5555);
    
    console.log(afei);
    console.log(xinai);
    

    26.6 instanceof实现对象的深拷贝

    /*
        instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
                       对象  instanceof 构造函数(一般是顶层构造函数Object,Array,Function)
    
    */
    function deepclone(obj) {
        var o = obj instanceof Array?[]:{};
        for(var key in obj){
            if(typeof obj[key] === 'object'){
                o[key] = deepclone(obj[key]);
            }else{
                o[key] = obj[key];
            }
        }
        return o;
    }
    
    var a = {
        a:20,
        b:50,
        k:{             //不支持复杂类型
            aa:1,
            cc:{
                h:2333
            }
        }
    }
    
    var b = deepclone(a);      //深拷贝后,引用值类型不会被影响
    
    b.c = 40;
    b.k.bb = 2;
    b.k.cc.i=120;
    
    console.log(a);
    console.log(b);
    

    26.7 JSON的API实现对象拷贝

    /*
            JSON只会传数字和字符串,不能存 函数 等其他类型
     */
    var a = {
        a:20,
        b:50,
        k:{        
            aa:1,
            cc:{
                h:2333
            }
        },
        f:function () {      //JSON  不支持函数类型,所以过滤掉
            console.log(1)
        }
    }
    
    console.log(JSON.stringify(a));     //没有函数 f
    var b = JSON.parse(JSON.stringify(a)); //这样实现的b也和a不一样了
    
    b.z=30;
    b.k.o=80;
    console.log(b);
    console.log(a);
    

    26.8 对象案例,选项卡

    
    
        
            
            Title
            
            
            
            
        
        
            
    • A内容
    • B内容
    • C内容
    • A
    • B
    • C

    26.9 对象继承案例,自动轮播选项卡

    
    
        
            
            Title
            
            
            
            
        
        
           
            
    • 开黑吗?
    • 我压缩贼六
    • 只要E的够快
    • 队友的问号
    • 就追不上我

    26.10 多态

    function fn(x) {
        if(x<10){
            return '0'+x;
        }else{
            return ''+x;
        }
    }
    

    26.11 ES6面向对象class

    /*
            ES5的构造函数和原型是分开的,ES6的类都定义在一个{}内
     */
    function A(n,a) {
        this.name = n;
        this.age = a;
    }
    A.showName = function () {       // 这里的函数是 构造函数A的属性,并不属于原型的函数
        alert(this.name);
    }
    A.prototype.showName = function(){      //这里才是给原型的函数,A的实例化对象能调用的函数
        alert(this.name)
    }
    
    
    
    /*ES6
        构造函数,也就是私有属性,写在constructor里面
        其他内容就是原型里面的内容
        原型里面加属性(可以在外面加,A.prototype.x=10)
        每个方法结束后,千万不要写 , 号
     */
    class A{
        constructor(n,a) {
            this.name = n;
            this.age = a;
        }
        showName(){
    
        }
        x(){
            return 10;
        }
    }
    
    //
    A.prototype.x=10;

    26.12 ES6继承extends

    class A{
        constructor(n,a) {
            this.name = n;
            this.age = a;
        }
        showName(){
            alert(this.name);
        }
        showAge(){
            alert(this.age);
        }
        x(){
            return 10;
        }
    }
    
    class B extends A{
        constructor(n,a,id){
            super(n,a);     //必要的super,把父类的私有属性继承一下(传参),类似ES5的 call
            this.id = id;
        }
        x(){
            //return A.prototype.x()+10;       //原型的super代表 A.ptototype
            return super.x()+10;
        }
    }
    
    let a = new A('阿飞',18);
    let b = new B('朱雀',81,111);
    
    console.log(a);       // {name: "阿飞", age: 18}
    console.log(b);       // {name: "朱雀", age: 81, id: 111}
    console.log(a.x());   // 10
    console.log(b.x());   // 20

    26.13 选项卡案例 ES6对象

    
    
        
            
            Title
            
            
            
            
        
        
            
    • 开黑吗?
    • 我压缩贼六
    • 只要E的够快
    • 队友的问号
    • 就追不上我

    27. ES6

    27.1 默认值

    /*
        函数的小括号,会被当成作用域
     */
    
    let x=5;
    function fn(x,y=x) {
        console.log(x,y);
    }
    fn(1);    // 1 1

    27.2 for of只限于遍历iterator接口

    作用是遍历拿到数组的value值

    对象使用for of 遍历时,先拿到对象的成员, for (let [key,value] of Object.entries(obj))

    let arr=[
        '阿飞',
        '风屿',
        '小浪',
        '海文'
    ];
    console.log(Object.keys(arr),Object.values(arr));  // 一维数组
    console.log(Object.entries(arr)); // 二维数组
    
    let obj={
        name:'afei',
        age:18,
        sex:'男',
        marry:true
    }
    
    /*
        for of只限于用于 iterator接口
    
     */
    for (let string of arr) {
        console.log(string);          //拿到数组的值value
    }
    
    for (let objElement of Object.values(obj)) {
        console.log(objElement);
    }
    
    for (let objElement of Object.entries(obj)) {      //打印数组
        console.log(objElement);
    }
    
    for (let [key,value] of Object.entries(obj)) {     //结合使用适合遍历obj的键和值
        console.log(key,value);
    }

    27.3 ...用于对象合并

    • 合并后的对象是新的对象
    • 合并对象时同名属性被覆盖
    let x={
        aa:1,
        bb:2
    };
    let y={
        bb:0,
        cc:3,
        dd:4
    };
    
    let z = {...x,...y}
    
    x.aa=10;
    console.log(x);
    console.log(z);

    27.4 symbol

    Object.getOwnPropertySymbols(obj); 获取对象内部所有的symbol属性,返回一个数组

    Symbol.for('a')的名字比如a相同,就代表相同的Symbol

    //独一无二的Symbol
    console.log(Symbol() === Symbol());    //false
    
    let obj = {name:'阿飞'};
    let n=Symbol();        //独一
    obj[n]='朱雀';
    
    n=Symbol();        //n被赋值,只是‘朱雀’取不到了,但仍存在
    obj[n]='心艾';
    console.log(obj[n]);  //获取的是 心艾
    
    obj[Symbol.for('name')]='朱雀';    // obj中添加一个属性  
    //  {name: "阿飞", Symbol(): "朱雀", Symbol(): "心艾", Symbol(name): "朱雀"}
    
     //获取所有的Symbol
     let symbolArr = Object.getOwnPropertySymbols(obj); // [Symbol(), Symbol(), Symbol(name)]
     console.log(obj[symbolArr[0]]);       //找到朱雀
    
    
    
     //传值是别名
     console.log(Symbol('a'),Symbol.for('a'));
     //Symbol的名字相同,仍不同
     console.log(Symbol('a')===Symbol('a'));     //false
     //Symbol.for的名字相同,就代表相同的Symbol
     console.log(Symbol.for('a') === Symbol.for('a'));      //true

    27.5 Set

    new Set(data) data必须是能被迭代的数据

    实例的add方法,可以追加数据到对象内

    /*
        对象
            特点:没有重复值
            只接收一个参数,必须能被迭代的数据,字符串,数组,NodeList,argument,Set,Net
     */
    let set = new Set([1,2,3]);
    
    
    
    let set = new Set("阿飞老师阿飞老师朱雀老师");        //默认去重
    set.add('心艾');          //add的内容被 当成一条数据传入,不被拆开
    set.add('心');
    console.log(set);         // 心艾 和 心  并不会去重
    
    
    //去重
    let arr=[1,2,4,5,6,1,2,4,2,3];
    let s = new Set(arr);
    console.log([...s]);

    27.6 Map

    map.set(key,value); 队列设置

    /*
        Map可以使用一个对象当成键名
            支持各种数据类型当键使用,对象,实例,
     */
    
    let map = new Map();
    
    // let key = 'name';
    // let value = '阿飞';
    
    let key = {goudan:'狗蛋'};         //对象当成键
    let value = 'afei';
    
    map.set(key,value);
    console.log(map);
    //取值
    console.log(map.get(key));

    27.7 Object的toString方法

    var a={m:'n'};
    var b= a.toString();
    
    console.log(b,typeof b,b.length);  //  [object Object] string 15 

    27.8 Proxy

    //Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,
    // 因此提供了一种机制,可以对外界的访问进行过滤和改写。
    let o ={
        a:1,
        b:2
    }
    
    let obj = new Proxy(o,{
        //拦截对象的获取
        get(target,key,receive){
            console.log(target);    // {a: 1, b: 2}
            console.log(key);       // a
            console.log(receive);   // Proxy {a: 1, b: 2}
            return target[key];     // 1
        },
        //拦截对象的赋值
        set(target,key,value,receive){
            console.log(target);    //{a: 1, b: 2}
            console.log(key);       //a
            console.log(value);     //123
            console.log(receive);   // Proxy {a: 1, b: 2}
        }
        //...  针对框架开发使用
    })
    
    console.log(obj.a);    //触发get
    obj.a = 123;           //触发set

    27.9 Promise

    new Promise() 返回一个promise对象

    Promise.all([new Promise(),newPromise()]).then().catch() 批量执行,all传入的是数组包裹的promise对象,都成功走then回调,都失败,走catch回调,只显示失败的

    Promise.race([new Promise(),newPromise()]).then().catch() 竞争执行,哪个实例先改变状态(不论resolve还是reject),那么then和catch就走哪个实例

    //回调地狱->解决异步编程
    setTimeout(()=>{
        console.log("123")
    },0)
    console.log("abc")
    
    //resolve 表示成功      reject表示失败
    let x = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("200");       //成功,永远在当前环境的最后执行
            console.log("我先打印,再进入resolve事件")
        },0)
    }).then((val)=>{            //then表示成功回调
        console.log("成功回调"+val);
    },(err)=>{                   //第二个函数是失败回调
        console.log("失败回调"+err);
    })
    
    
    //all  只有数组成员都成功才执行then
    let p = Promise.all([
        new Promise((resolve,reject)=>{
            resolve('1');
        }),new Promise((resolve,reject)=>{
            resolve('1');
        }),new Promise((resolve,reject)=>{
            reject('0');
        })
    ]).then(data=>{
        console.log(data);     //都成功[1,1,0]
    }).catch(err=>{
        console.log(err);      //有一个失败,就走失败,这里只显示失败的 '0'
    })
    
    /*
        Promise.race()  有竞争的意思
        只要`p1`、`p2`、`p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。
        那个率先改变的 Promise 实例的返回值,就传递给`p`的回调函数。
     */
    let p1 = Promise.race([
        new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('1');
            },100);
        }),new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('2');
            },101);
        }),new Promise((resolve,reject)=>{
            setTimeout(()=>{
                reject('3');
            },99);
        })
    ]).then(data=>{
        console.log('resolve '+data);     //只显示最快的  3,无论是 resolve还是reject
    }).catch(err=>{
        console.log('reject '+err);
    })
    

    转载于:https://www.cnblogs.com/danew/p/11415740.html

    你可能感兴趣的:(JavaScript笔记)