JavaScript基础

javaScript基础
⦁ 一、简介
⦁ 参考官网:https://zh.javascript.info/bigint
⦁ 1.JavaScript可以在任意搭载了javaScript引擎的设备中都可以执行,浏览器中嵌入了引擎,也称之为js虚拟机
⦁ 2.不同浏览器的引擎可能不一样,如Chrome中的是v8引擎,引擎执行代码的过程:解析代码,编译成机器语言,然后执行
⦁ 3.js不能做的事
⦁ (1)js调用摄像头或者麦克风需要用户授权,否则不会直接调用
⦁ (2)js受同源策略影响
⦁ 二、基础知识
⦁ 1.html4中的js代码需要有type特性
⦁ 2.在引入外部脚本的标签中写js内容会不起作用
⦁ eg:以下的alert不起作用

<script src="/js/script1.js"> alert("hello")</script>

⦁ 3 use strict 严格模式
⦁ ES5增加了很多新js特性,在js文件顶部写"use strict"会启用这些新特性,默认不启用,另外,必须写在顶部否则无效
⦁ 4.声明变量: var和let
⦁ (1)变量命名与java一样,字下美元数骆驼,多单词也是驼峰命名;严格模式下变量必须声明, 否则报错
⦁ (2)const 声明 ,声明后不可修改值,确定有这种值就要明确定义为const,常量一般用大写
⦁ (3)变量该声明就及时声明,不要重用之前已经有明确含义的且使用完的变量
⦁ 5.数据类型
⦁ (1)number类型 数字和特殊数值:Infinity无穷大 ,NaN表示计算错误,不正确的值进行数学运算,有NaN参与的运算结果都是NaN
⦁ ps:在js中做数学运算最坏的结果是得到NaN, 并不会导致js脚本停止运行,即是安全的
⦁ (2)BigInt 表示任意长度整数,数字末尾加n表示BigInt,number类型表示的数在2^53-1范围内,大数字用bigint,但是很少用到eg: let big = 343223423n;
⦁ (3)String类型,

反引号`表示可以在其中对${varName}做计算或者替换,${}中变量可被替换,数字可被运算;另外js中没有char单个字符类型
eg:let name = "zhangshaoxuan";
alert(`${name}`+`${1+2}`);

(4)null表示无、值未知等含义,而非空引用:
eg:document.getElementById(“dfdfd”) 尝试获取一个不存在的元素报null
(5)undefined表示未被赋值,变量已经定义了,但未赋值,undefined是未初始化的默认初始值
eg:let v; alert(v)
⦁ (6)object类型用于保存复杂的对象类型,与上述几种只能保存单个值完全不同,null也不是object类型,但是js最初设计上错误,导致typeof null 为object这是错误的
(7) typeof(x)或者typeof x 效果一样判断类型,以字符串形式返回类型
6.交互的三种框

alert();prompt(message,default)带有输入框的窗口:
带有question 和确定取消的窗口
eg:
let pro = prompt("","默认值")/*接收输入的值*/
let result = confirm("are you ok?");//true or false 

7.类型转化:
(1)一般都会自动转化
(2)显式转化:String(value)
Number(value),数值型转化规则

 undefined--> NaN; null-->0;true-->1;false-->0; string先忽略首尾的空格(包括 \t、\n 以及它们之间的“常规”空格)然后再转化,转换错误是NaN;空字符串则0
 布尔类型:直观上为空(0,空字符串,null,undefined,NaN等)都将为false;其他值为true

Boolean转化注意四个值
以下四个值返回分别为:true、false、false、true
Boolean(“0”)+"–"+Boolean(0)+"–"+Boolean("")+"–"+Boolean(" ")
8.运算符:
(1)只有二元+起到连接字符串的作用,若要字符和数字求和则要先转为number;
其他运算符总是对数字起作用,并将非数字转为数字

eg: 
/*转换*/
alert(6+"2");/*62*/
alert(6+Number(2))//8
alert("6" / "2")//3
alert(+true)/*一元加号是做类型转化的,1*/
alert(+"")//0

(2)还有变量++,–,+=,*=等符号
9.比较值
(1)字符串按照Unicode编码顺序比较;不同类型比较先转化number类型,再比较,转化不了的就是NaN比较结果始终false,eg: “2” >“12” true,Unicode码值从第一位开始比较2>1
ps:不同类型的比较才会转为number
(2)严格相等

==不能区分0 false "",因为比较前都会转化为0===严格相等如果类型不一样则直接返回false,不再比较大小

(3)null和undefined比较:
实用严格等号=== 不相等 因为类型不同; 使用==比较时,js规定二者相等
当使用<><=>=等比较时,null被转化为0,undefined被转化为NaN
eg:

alert(null >= 0 ) //true  null转为0
alert(null == 0 )//false null就是null 只与undefined相等

(4)NaN与任何值比较都返回false,即undefined也一样(转为NaN)

10.switch中是严格相等
eg: let firstName = “0”;
switch (firstName) {
case 0: //这里不匹配
alert(0);
break;
case “0”: “0” === “0”
alert(“字符串0”);
break;
default:
alert(“default”)
}
11.函数声明
(1)参数的默认值

/*调用函数时如果参数没给定,则使用默认值*/
function test(text="defaultValue") {
    alert(text)
}
/*默认会调用函数返回值*/
function test1(text=defaultValue()){
    alert(text)
}

(2)返回值与return之间不要跨行

/*长返回值不应该与return跨行,这样return后会自动添加分号
* 而应该从return这一行开始*/
function defaultValue() {
   /* return
    1+2+3+4;  返回undefined*/
   return 1+
       2+3+4;
}

(3)一个函数只做一件事
12. 函数表达式
(1)函数声明与函数表达式都是创建并将函数赋值给变量:

function say(){} ;  let say = function(){}; //这两种都是给变量say赋值了一个函数

(2)函数能像其他变量一个相互赋值

eg:
function say(){
    alert("hello")
}
alert(say)//结果:显示say方法本身;因为say变量的内容就是这个函数
//变量相互赋值
let say1 = say;
say1()

(3)函数声明和函数表达式的区别
函数声明在声明之前就可以调用,js初始化时会先定义所有的函数,而函数表达式则必须在定义后才能使用,类似变量
13 箭头函数 格式为:(arg0,arg1,…)=>{ repression} 相当于对function的简化,没有参数的话括号为空,但必须留着

eg:  
let sum = (a,b) =>{alert(a+b)}
sum(1,2)
let al = ()=>alert("hello") //入参括号必须有,声明函数非常方便

ps:js代码每一行都要写上;习惯!!!

三、对象基础
1.对象定义
(1)对象可随时添加或者删除属性
eg:

let user = new Object();
delete  u.age;
alert(u.age) //undefined

(2)多单词属性应该使用[]取值,属性应该引号

"alias name":"zsx"
alert(u["alias name"])

(3)方括号与.符号的区别在于:
方括号能够通过实时变量值来获取属性值,.符号不行
eg:

let user = {
    name:"zas",age:33,};
let key = prompt("what do you wanna know about user?","name");
let showObject = (u)=>{
    alert(u[key]);//这里以key变量的值为属性取值,
    alert(u.key);//这里就是取的user的属性key的值,而user本身没这个属性,结果undefined
}

(4)属性值简写,在属性名和属性值得变量名一样时可简写
eg:

let returnUser = function(name,age){
    return {
        name, //name:name
        age //age;age
    }
}
let user1 = returnUser("zhangsahoxuan",33);
showObject(user1.name)

(5)js中属性能够被随便访问,不存在时返回undefined,因此判断属性存在否就用undefined或者in; undefined的问题在于,有可能对象属性本身存储的值就是undefined,这样就会判断失误,因此用in最保险

let user = {
    name:undefined,
  };
let showObject = (u)=>{
    alert("name" in u);//true
    alert( u.name==undefined)//true,但是属性存在,不能判定属性 不存在
}

(6)for(k in obj)遍历对象中的属性和属性值
eg:

let user = {
    name:"zhangshaoxuan",
    age:33,
    "alias name":"zsx"
};
for (let key in u){ //这里key在严格模式下必须定义,也可以定义在外面
    alert(key)//键
    alert(u.key)//这种取值不行
    alert(u[key])//值
}

(7)遍历对象时除非属性都是数字,否则就会按照定义时的顺序显示
2.字面量变量传递,会出现两个独立变量互不影响,对象则是引用传递,拷贝的是内存地址

3 ==和===对于对象比较来说是完全一样的,因为内存地址一样,而两个独立对象只要内存地址不同则不相等,与Java中的==一样比较内存地址

eg:let a ={};let b = {};
a==b//false

4.js中的浅克隆(Object.assign)和深克隆(递归)
eg:

let user = {
    name:undefined,
    age:33,
    "alias name":"zsx"
};
let score = {
    math:22,
    cn:34,
    en:45
}
//目标变量必须也是个对象,否则会报错
let dest ={};
/*合并多个对象,当目标对象已存在属性时,会覆盖值*/
dest = Object.assign(dest,user,score )//第0个是目标,剩下的都是源
alert(dest.cn)

5.垃圾回收,js中的垃圾回收机制判断是否该回收对象跟jvm中类似,标记引用
(1)可达性:全局变量,局部变量,调用链上所有变量成为根,这些明显不能回收,通过这些可直接或者间接引用到的变量也不可回收,否则回收
eg:

let user = {user:name};  //全局变量引用了一个对象,则该对象不可回收
user = null;//对象不可达,则回收

(2)引用传递:let admin =user; user = null;对象依然不可回收,因为admin这个引用了对象
(3)对象内部相互引用,但是没有外部的跟引用对象整体时,对象仍不可达,会被回收
6.OOP面向对象
(1)eg:定义对象简写方法:

let zsx = {
    name:"zhangshaoxuan",
    age:"25",
    sayHi(){ //常用简写
        alert("hello美女,im "+this.name);

    },
    sayFuck:function () {
        alert("fuck");
    }
}

(2)this是自由的,它的值取决于点前面的对象,方法也可以有this,以下例子暂时还是不太理解
eg:

function notify() {
    return {
        fuck:"fuck",
        ref:this, //这里的this其实是undefined
        ref1(){return this}//这里只有对象.ref1()时才能确定下来
    }
}
let user2 = notify();
alert(user2.ref.fuck)//报错
alert(user2.ref1().fuck)//fuck

7.构造函数和new
(1)new 操作符做了以下的事情
eg:

let user = new User("jack");// 约定俗称大写为构造函数
function User(name){
//this = {};//隐士创建this
this.name = name;
//return this  //隐士返回对象
}

(2)js中的构造函数主要目的就是为了重用创建对象的代码
(3)new.target放在函数内部检测是否被new吊用过,是则返回该函数,常规调用则返回空

eg:
function Con(name){
    this.name = name;
    alert(new.target+"alert")
}
let user3 = new Con("newOne");

8.js中对象的属性键可以是任意类型,只是如果是数字,则只能用user[1]这种形式,而不能用.来表示
9.Symbol表示唯一标识符,任何两个Symbol都不相等
(1)symbol不支持隐士转化成字符串,因为Symbol与字符串有本质区别

eg:
let SY = Symbol("id");
alert(SY); //   报错
alert(SY.toString()) //symbol(id)

(2)利用Symbol的唯一性,可以对跨脚本调用的对象进行不重复的属性值添加,或者在不确定对象内容时,还想对对象进行属性添加,用Symbol不错:

eg:
let id = Symbol("id");
let u = {
    name:"zsx"
}
u[id] = "25";
alert(u[id])

(3)Symbol在for in循环中会被跳过, 属性不会被意外访问到
(4)Symbol.for(key)能够取到(没有则创建并返回)全局范围内唯一的Symbol,通过Symbol注册表,对于同一个key返回同一个Symbol
eg:

let id = Symbol.for("id");
let u = {
    name:"zsx"
}
u[id] = "25";
alert(id === Symbol.for("id"));//TRUE
alert(u[Symbol.for("id")])//25

(5)js中有很多系统Symbo,如Symbol.toPrimitive(一种系统内建Symbol)可设置对象原始值的转化等
(6)严格上讲Symbol并非不可见,以下方法可遍历对象所有键,包括Symbol
eg:

let arr = Reflect.ownKeys(u);
for (let a in arr){
    alert(arr[a].toString())
}

10.对象到原始值的转化其实是对特定方法进行重写,类似java中的toString()方法
重写规则
Symbol.toPrimitive方法存在,则调用,否则如果hint是String,则尝试调用toString和valueOf方法,否则调用valueof和toString,实际上日常开发中只实现toString打印对象属性就够了
eg:

let hintUser = {
    name:"zsx",
    age:25,
    [Symbol.toPrimitive](hint){
        alert(hint) //string
        let str = 'name:'+this.name+"--age:"+this.age;
        return hint.toLowerCase()=="string"?str:this.age;
    },
    toString(){ //有上面的方法存在,这个方法不会调用
        return this.name //返回值必须有
    }
}
alert(hintUser);//这样使用相当于hint是string

11.字面量引用变量在调用内部方法时,其实是创建了一个内部对象,然后内部对象的属性有一个是字面量,将字面量传给方法,用完后该对象就 了,,而字面量调用得用两点或者括号
eg:

let num= 255;
num.toString(16),//求数组的16进制
255.toString()报错
alert(255..toString(16));
alert((255).toString(16));
alert(num.toString(16));//这样使用相当于hint是string

12.两个特殊方法:
(1)NaN独一无二,与任何数不相等包括它自己,必须使用isNaN来判断一个数字是否是NaN
isNaN(15)//false
(2)isFinite(string) 判断字符串是否是常规数字(正常的数字,非NaN,Infinity等)
eg:alert(isFinite(""))//true,空格是0

13.Object.is()比较两个值是否===相等,NaN和NaN也可比较

eg:Object.is("we","we")//true
alert(Object.is(15,"15"));//false

14.parseInt(string)和parseFloat(string)能从字符串左边开始读取,直到无法正确读取为止,返回对应类型的数字
eg:

alert(parseInt("12px"));//12
alert(parseInt("a12p"));//NaN,
alert(parseInt("1b2p"));//1
alert(parseFloat("0.3"));//0.3
alert(parseFloat("0..3"));//0
alert(parseFloat("23.34.5"));//23.34

15.js数字部分,浮点数要注意精度内部存储的问题,如6.35四舍五入是6.3而非6.4因为内部存储让6.5小了一点
⦁ 16.字符串
⦁ (1)反引号``允许${…}将表达式嵌入到字符串中,字符串也可跨行
⦁ eg:

let d1 = "1"
let d2 = `2${d1}` //21
alert(`结果:${d2}`)
let d2 = `2..大幅度 //可直接字符串中间换行

(2)使用>和<比较字符串大小时,按顺序使用字符Unicode编码比较字符串
17.数组
(1)pop:取出并 最后一个元素;shift从头删除并取出第一个元素,unshift 在数组端首添加元素,push从后面添加,都可一个性作用于多个元素

eg:
let fruit = ["apple"];
fruit.push("pear","banana");//先压pear,再压banana
fruit.unshift(true,"zsx",1); //按顺序一次性压进去
alert(fruit); //true,zsx,1,apple,pear,banana;

(2) 数组中可放任意元素包括null
(3)数组在内部是个引用的对象,不要用属性值,否则会破坏js引擎对数组的优化, 也不要arr[0]=0;arr[10000]=12000;这样会导致中间内存无法利用
(3)循环 for…of ,比let k in 要快很多,但是拿不到数组下标

eg:for (let f of fruit ){
alert(f);
}

(4)减少length会导致数组被截断,过程不可逆,可用于 元素

eg:fruit.length=0;//清空数组; fruit.length = fruit.length-1//舍弃最后一个元素

(5)new Array会创建新数组,而且会在没有元素的情况下初始化占用空间,不推荐使用

(6).数组方法splice 用于在指定位置删除、替换、插入;

arr.splice(index[, deleteCount, elem1, ..., elemN]),从 index 开始:删除 deleteCount 个元素并在当前位置插入 elem1, ..., elemN。最后返回已删除元素的数组。
eg:let fruit = ["apple","pear","banana"];
//删除从下标1开始,删除2个元素
 //fruit.splice(1,2);
 //替换2两个元素
    //fruit.splice(1,2,true,false);
    //在下标为1的位置,插入两个
fruit.splice(1,0,true,false);
alert(fruit);

(2)slice(start,end),前闭后开,复制数组中的片段值,无参则拷贝数组本身
eg:

let arr2 = [0,1,2,3];
let ar1 = arr2.slice(1,3); //1和2copy

(3)concat 连接数组和其他元素组成新数组

eg:let arr2 = [0,1,2,3];
let ar1 = arr2.concat(true,1,2,[12,13,14]); // 01234true,12121314

(4)forEach
eg:

let arr2 = [0,1,2,3];
//三个参数按顺序分别为:值,下标,数组本身
ar2.forEach((v,index,arr)=>{
    alert(`${v} is in ${arr} at ${index}`)
})

(5)find和findIndex根据数组中复杂对象的某个属性来查找,find没有搜到返回undefined,findIndex返回对象所在下标,没有则-1

eg:let users = [
    {id: 1, name: "John"},
    {id: 2, name: "Pete"},
    {id: 3, name: "Mary"}
];
//参数顺序:值,下标,数组本身
users.find((v,index,arr)=>{
    if(v.id===1){
        alert(index+v.name)
    }
})

(6)转化数组 map 对数组每个元素都调用函数,并用替换原来的值
eg:

users.map((v,idx,arr)=>{ 	//user同上,
    v.id+=10; 	//这里是对数组对象的内存空间进行修改
})7)arr.reverse()颠倒元素顺序
(8)split和join,字符串分割成数组,数组join成一个字符串

eg:

let str = "q,w,e,r";
let arr = str.split(',');
alert(str.split()); //字符串中单字符拆分成数组每个元素
let s = arr.join('。');
alert(s) //字符串s为q。w。e。r

(9)arr.reduce对元素一个一个做操作,然后返回的累积结果
l

et value = arr.reduce(function(accumulator, item, index, array) {
  // ...
}, [initial]);//参数按顺序分别为:累积操作的结果,元素,下标,数组本身,初始值(一般最好写上,否则数组为空时,会报错,不写的话是第0个元素)
eg:let numbers = [1,2,3,4,5];
let re = numbers.reduce((sum,v)=>sum+v,0);//函数每次执行完后返回的值会存在累积中,用于下次传参;如果是多行箭头函数则需要return结果,即 {return sum+v}

(10)typeof不能分辨出数组或者普通对象,因为数组是基于后者的, 应该用内建方法Array.isArray(v),v是数组则true,否则false

eg:
alert( typeof  numbers) //object
alert(Array.isArray(user));//false
alert(Array.isArray(numbers));//true

(11) filte()使用指定的函数测试所有元素,并返回通过测试的元素所组成的新数组,注意filter操作不影响原数组
array.filter(function(currentValue,index,arr), thisValue);
currentValue 必须。当前元素的值; index可选值,arr可选值,当前元素所在的数组
eg: 删除当前数组中选中的元素
this.arr = this.arr.filter((v,ind)=>{return ind!=index })
(12)every方法,对每个元素进行条件测试,如果有一个不满足条件则返回false,并且不再往后进行,否则返回true,不改变原有数组,语法:array.every(function(currentValue,index,arr), thisValue)
eg:

 this.all = this.products.every(item=> item.isSelect===true);

18.映射和集合map和set
(1)map与对象不同在于,map的key是保留类型的,而对象会将所有类型都转为字符串;map也能将对象 键,而对象不行。常用方法:
new Map() —— 创建 map。
map.set(key, value) —— 根据键存储值。
map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined。
map.has(key) —— 如果 key 存在则返回 true,否则返回 false。
map.delete(key) —— 删除指定键的值。
map.clear() —— 清空 map。
map.size —— 返回当前元素个数。

eg:let map = new Map();
let user = {name:'zsx'};
map.set(user,22);//对象作为键
map.set(1,"c");
alert(map.get(1))//c
alert(map.get("1")) //undefined

(2)map[key]不是正确的使用方式,会将map当成普通对象
(3)map迭代 ,map.keys(),map.values(),map.entries,迭代顺序与插入的顺序相同;还有map.forEach循环,与array类似,循环每个元素,注意map.entries()的结果格式为二维数组: [[1,“c”],[2,“b”]]

eg:let map = new Map();
map.set(1,"c");
map.set(true,"b");
map.set(10,"a");
//参数顺序为:value,key,map本身
map.forEach((v,k,map)=>{
alert(k+v)
})

(4)从对象创建map,创建的map与原对象无引用关系,使用Object.entries(obj)即可,实际上创建map时可直接传入键值对格式的二维数组来创建,上述内建方法也是返回了一个map构造器可接受的二维数组

eg:let map = new Map([[1,"r"],[2,"b"],[3,"c"]]);
map = new Map(Object.entries(user));//这里其实是返回的二维数组给了map构造器
for(let entry of map.entries()){
entry.forEach((v,index)=>alert("index:"+index+"---"+v))
}

(5)从map创建对象 let user2 = Object.fromEntries(map);
(6)set集合:不重复值,用法与array类似

eg:let set = new Set([1,2,3,4]);
   set.add("w") ;
   set.delete("w");//删除
   alert(set.has("w"));//是否存在元素
   set.clear();//清空
   set.forEach((v1,set)=>{ //forEach遍历
       alert(v1);
   })

19.WeakMap和WeakSet弱引用,只能key只能是对象,如果对象没有其他引用地方了,就会被回收,即通过map.get时就会undefined
20.普通对象获得keys、values以及键值对数组 Object.keys(obj)等

eg:
let john = {name: "John" }
alert(Object.keys(john));
alert(Object.values(john));
let arr =
Object.entries(john).map((item)=>{ //entries返回key value组成的二维数组
    item[0] = item[0]+1;
    return item
});

21.解构赋值语法 let [var1,var2,var3,…] = 任何可迭代对象;let {item} = Object 解构对象使用加粗样式
eg:

let arr = ["Arr1","Arr2"];
 let[first,second] = arr;
 alert(first+second);
let arr = ["Arr1","Arr2","Arr3","arr4"];
 let[first,,second] = arr; //这里直接忽略第二和其余的,只保留第一个和第三个
let user = {};
[user.name,user.age] = arr; //将对应位置的值赋给对象的属性
alert(user.name);//Arr1
let user = {name:"zs",age:23}; 
//遍历键值对
Object.entries(user).forEach(([key,value])=>{//通过entries和解构遍历键值对
    alert(key+value)
});

(2)交换变量的技巧

eg:[guest,admin] = [admin,guest];//将admin的引用付给guest,而guest给admin

(3)给默认值,一般如果赋值少于变量,则剩余变量都是undefined

eg:
[var1="zs",var2="ls"]=[]; //这种提前给 默认值了

(4)解构对象中的某个属性

eg:let {title} = options; //声明一个变量title并赋值

22.日期时间相关
(1)获取方法

eg:let now = new Date(Date.parse("2020/09/28 22:53:10"));
now.getDay()周日到周六0-6
let format = (date)=>{
    let y = date.getFullYear();//年(4位数)
    let m = 1+date.getMonth();//月(0-11)
    let d = date.getDate();//获取月份中的日期
    let s = date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds();//
    return  y+"-"+m+"-"+d+" "
        + date.getHours()+":"+date.getMinutes()+":"+s;//时分秒
}

(2)set方法设置具体的日期时间

eg:now.setHours(21);//设置Hours,其他日期时间类似的设置方法

(3)自动校准,设置之前或者之后的某个时间

eg:let date = new Date(2019,2,13);
date.setDate(date.getDate()+15);//求当前时间15天后的日期

(4)日期测量,两个日期相减求差
23.JSON
(1)JSON.Stringfy(Obj) //对象转json; JSON.parse(json);//json转成对象;json中只有双引号,没有单或者反引号,属性也被转为双引号;
(2)值为undefined的 、函数、Symbol会被json跳过,json不能转化有循环引用的对象

eg:let user = {
    name:'zsx',
    age:25,
    gender:undefined,
    items:[true,1,"apple"],
    say(){return "hello"}
}
alert(JSON.stringify(user));//{"name":"zsx","age":25,"items":[true,1,"apple"]}

(3)JSON.parse()反序列化时,提供一个reviver函数,能在反序列化之前对内容做修改

let value = JSON.parse(str, [reviver(key,value)]);
eg:let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let strO = JSON.parse(str,function (key,value) {
    if(key==="date"){
    return new Date(value);
    }
    return value;
});
alert(strO.date.getTime());//加了reviver后不报错

24.闭包:内部函数总是可以访问其所在的外部函数中声明的变量和参数
(1)词法环境,每个函数都会有词法环境,存储调用的局部变量和参数,访问变量时会先访问自己的词法环境,访问不到则访问外部词法环境,依次类推直至找到,都找不到时,严格模式下会报错
(2)所有函数创建时都有有一个Enviroment 隐藏属性,保存了该函数对其词法环境的引用
(3)词法环境也是通过可达性判断是否要回收的
(4)嵌套函数
eg:function circleRel(){
let count = 0;
return function () {
return count++;
}
}
let f = circleRel();//返回函数赋值给f, 外部circleRel函数的词法环境只创建一次
alert(f());alert(f());alert(f());//展示0/1/2
25.var
(1)var没有块级概念,只有方法内为局部变量,方法外则全局
eg:

if(1==2){
    var qq = 11;
    let ww = 22;
}
alert(qq);//可读
alert(ww);//不可读

(2)var可重复声明,var可在声明前被使用,即var声明的变量会在 头被定义,与位置无关,即var进行变量声明可被“提升”,但是变量赋值不会被提升

eg:alert(qq);//不报错,但是undefined
var qq;
qq = 33;//赋值在后不被提升

(3)var属于5变量声明方式,不应该再使用
26. 函数在js中被定义为行为对象
(1)name属性可访问方法名,匿名方法则为空字符串
eg:function f() {};//;let f = function(){}一样
alert(f.name);
(2)length属性保存函数对象的参数个数,Rest参数不参与计算

function  ask(question,...handlers) {
    let isYes = confirm(question);
    for( let h of handlers){
        if(isYes&&h.length===0){//根据方法参数数量判断是否应该调用
            h();
        }else{
            h(isYes);
        }
    }
}
ask("ARE YOU OK?",()=>alert("yes"),(re)=>alert(re));

(3)方法对象可以自定义属性,而属性和变量是完全不相干的东西
eg
:function sayHi() {
alert(“Hi”);
sayHi.count++;//这里就是定义的属性动作
}
sayHi.count = 0;//需要初始化;
sayHi();sayHi();alert(sayHi.count);//统计方法调用次数
(4)命名函数表达式,函数有两个名称 :let f = function f1(){}这种,f1两个作用:函数内部可引用f1,f1在函数外部不可见

eg:let f = function f1(who) {
    if(who){
        alert(who);
    }else {
        f("admin");f1("admin");//内外名称都可,但是外部名称f可能被外部词法环境修改掉,因此方法内部调用自己时,一般做法是添加内部名称f1
    }
}
f();// 正常
f1();//报错
//方法对象的练习解释
function makeCount(){
  function counter(){// 这里完全就是定义了一个方法对象的属性而已,只不过这个属性也是个方法
      counter.count++; //属性++
  }
    counter.count = 0;//属性初始化,
    //方法对象定义属性set,属性值也是方法
    counter.set = function (value) {
        counter.count = value;
    };
    //方法对象定义属性,属性值也是方法
    counter.decrease = function () {
        counter.count--;
    }
    return counter;//返回方法对象
}
let c = makeCount();
c();alert(c.count);c.set(4);c.decrease();alert(c.count);

27.绑定函数解决this丢失或者置换的问题

eg:
let user = {
    name:'zsx', 
    say(){alert("Hi,im:"+this.name)}
}
user = {say(){alert("others:"+this.name)}};//在say方法调用前,user发生了变化,this所引用的值也会发生变化
user.say();
//bind解决this丢失问题
//定义对象
let user1 = {    name:'zsx'}
//定义需要绑定的方法
function say(){alert("Hi,im:"+this.name)}
//方法绑定对象,然后返回绑定后的方法
let funcBind = say.bind(user1);
funcBind();//调用

28.箭头函数
(1)箭头函数没有this,访问this时,会从箭头函数外部上下文中获取,也没有super
ps:普通方法的this默认是undefined,对象的属性方法的this默认为该对象

eg:function test(){alert(this.name)};//报错 connot read property of undefined
let user = {
    name:'zsx',
    say(){
        return function () {//该匿名方法的this为undefined
            alert(this.name);
        }
    },
    say1(){
        return ()=>alert(this.name);
    }
}
//let a = user.say();//报错cannot read property of undefined
let b = user.say1();//zsx
b();

29.属性标志和描述符
(1)属性标志
writable --true则属性值可被修改,否则只读,修改时会报错
enumerable — 如果为 true,则会被在循环中列出,否则不会被迭代列出
configurable–true时则可被删除,否则不可删除
(2)获得属性的这些属性标志的描述,通常定义的对象这些属性描述都为true
Object.getOwnPropertyDescriptors
eg:
let ownPropertyDescriptors = Object.getOwnPropertyDescriptors(user,‘name’);//获取描述符,获得是个对象

alert(JSON.stringify(ownPropertyDescriptors));//默认都是true
(3)改变属性描述符 Object.defineProperty(obj, propertyName, descriptor)
eg:
//属性存在的情况下设置描述符
Object.defineProperty(user, ‘name’, {
configurable:false,//不可删除,否则报错
writable:false, //不可写,只读
enumerable:false //不可迭代显示,但是不会报错
})
//属性不存在时,直接定义属性描述符,则默认这些标志默认都是false,需要定义成true
(4)应用:一般内建对象都是只读,不可删除,如Math.PI
30.原型继承
(1)对象中默认有一个Prototype的隐藏属性,要么为null要么为另一个对象,这个对象即原型,类似java中的父类引用
(2)设置原型的方式之一 proto,前后两个下划线,这个是通过setter方法设置进去的
eg:let man = {gender:“male”}
let user = {name:“zsx”}
user.proto = man;//下划线前后各两个
alert(user.gender);
(3)原型只能是对象或者null,同时一个对象不能多继承,js不支持多继承
(4)js方法重写,继承后,子类可以重新定义从父类继承到的方法,而不使用原型的
eg: animal = {eat(){}} ; let rabbit = {}; rabbit.proto = animal;rabbit.eat=function(){alert(“cao”)}
(5)判断属性是自己的还是继承于原型的 内建方法 obj.hasOwnProperty(key)
eg:alert(user.hasOwnProperty(“gender”)?“自己的”:user.gender);
(6)注意几乎所有其他键值得获取方法都会忽略掉继承的属性,Object.values,Object.keys等
31.按照规范,所有的内建原型顶端都是 Object.prototype。这就是为什么有人说“一切都从对象继承而来”。
eg:let obj = {};
let arr = [1,2,3];
//__proto__指继承的原型,而prototype表示在使用构造器new一个对象时,通过prototype指定父类,如果不是构造器的话,它就是个普通属性
alert(“对象原型是否相等”+(obj.proto===Object.prototype));//true
alert(“数组原型是否相等”+(arr.proto===Array.prototype));//true
alert(“数组与对象原型是否相等”+(arr.proto.proto===Object.prototype));//true
(7)应该使用以下方法来替代__proto__的设置,该属性已经被列为不推荐
Object.create(proto, [descriptors]) —— 利用给定的 proto 作为 [[Prototype]] 和可选的属性描述来创建一个空对象。
Object.getPrototypeOf(obj) —— 返回对象 obj 的 [[Prototype]]。
Object.setPrototypeOf(obj, proto) —— 将对象 obj 的 [[Prototype]] 设置为 proto
32.
(1)js中的类class本质是一个函数,主要做两件事创建一个名为类名的函数,以及存储类中定义的方法
eg:

class User{
    constructor(name){
        this.name = name;
    }
    sayHi(){
        alert(this.name)
    }
}
alert(typeof  User);//function
let user = new User("zsx");
user.sayHi(); //像java中一样进行调用

ps:
任何对象都有一个__proto__属性
任何方法都有一个prototype属性和__proto__属性,prototype也是一个对象 ,所以其中也有一个___proto__,
我们可以向其中的prototype塞入各种对象。这些对象会被所有实例继承。而所有的实例都有一个__proto__指针指向着构造函数的prototype属性。
(2)类类似函数,可以在另外一个表达式中被定义,传递,返回和赋值
eg: let User = class{sayHi(){}}
33.类的静态方法和静态属性,与java中的含义和用法类似, 表示一个只属于类本身而不属于 实例的方法或者属性,但js中静态方法可以使用this,表示该类本身,静态方法使用static关键字
eg:

class User{
static publisher = "publisher";//静态属性

    static  userAlert(){
        alert("static method"+this)//this表示User类本身,会打印内容
    }
    constructor(name){
        this.name = name;
    }
}
let user = new User("zsx");
User.userAlert();//通过类直接调用
user.userAlert();//报错

34.回调
(1)回调的使用是在一些异步的场景中的,我们想在某个行为完成时调用某个方法,但是无法确定该行为何时完成,则添加一个回调方法
(2)回调方法定义的方式:
callback 的第一个参数是为 error 而保留的。一旦出现 error,callback(err) 就会被调用。
第二个参数(和下一个参数,如果需要的话)用于成功的结果。此时 callback(null, result1, result2…) 就会被调用。
因此,单一的 callback 函数可以同时具有报告 error 和传递返回结果的作用。
在这里插入图片描述

35.模块就是一个文件,一个脚本就是一个模块,export和import标记了可以导入和导出的变量和函数
(1)导入和导出可以使得不同文件中的方法和变量相互访问
(2)模块支持特殊关键字和功能,需要使用

<script type="module" src="../js/test.js">
test.js中导入并调用:
import {sayHi} from '../js/test1.js';
import {content} from '../js/test1.js';
sayHi("hello boy"+ content);//这里的都是导入的变量和函数
test1.js中导出: 一定要导出,否则浏览器报错
export  function sayHi(content){
    alert(content)
};
export let  content = "import content";

(3)模块的核心功能:
i.模块始终是严格模式,未声明变量直接赋值报错
ii.模块化作用域:如全局变量必须export导出并导入才能被使用,否则只导入而不导出也无法跨脚本使用
(4)同样的文件模块被导入多次(多个文件)时,只有第一次时会被解析,然后将解析后的同一个对象传入所有的导入,该对象全局唯一,任何文件中更改对象内容,都会在其他文件中可见,但是字面量不行,导出的字面量是常量,不可修改
eg:

test.js中
import {sayHi} from '../js/test1.js';
import {content} from '../js/test1.js';
sayHi("hello boy"+ content.c);//这里的都是导入的变量和函数
test2.js中
import {content} from './test1.js';
content.c =  "change";//这里设置对象值后,会在其他文件中应用到

(5)有type="module"这种的外部脚本具有相同src的外部脚本在模块功能中只运行一次,另外,文件源不同导致出现跨域时,需要CORS解决跨域
(6)通过webpack等打包工具的处理的脚本最终import/export语句会被替换成特殊的打包函数,最终的脚本中不含improt和export,可以直接放入

i.声明前导出
eg: export let month="df"; export function sayHi(){}
ii.导出与声明分开也可
eg:  function sayHi(content){
    alert(content)
};
 let  content = {} ;
 export {sayHi,content};//一次性导出很多声明
iii. export default 格式导出时,在导入时不需要加花括号,一般都使用命名格式的导出,默认格式使用 较少
iv.重新导出,语法:语法 export ... from ...通过单个文件入口公布项目的功能,可以先导入,再导出,即:
eg:
// 导入 login/logout 然后立即导出它们
import {login, logout} from './helpers.js';
export {login, logout};
简写成:
// 导入 login/logout 然后立即导出它们
export {login, logout} from './helpers.js'; 

(2)类或者函数前的export不会让他们变成函数表达式,仍然是一个声明,而js的函数和类声明后是不适用分号的,因此导出函数或者类后不需要分号
(3)导入的方式

i.import  xx from xx 一个个导入
ii.批量导入  import {xx,xx}
iii. as对导入的声明重命名,重命名后就不能再使用原本的声明
eg: import {sayHi as hi,content as con } from '../js/test1.js';
hi("hello boy"+ con.c);//这里的都是导入的变量和函数

36.浏览器环境规格标准文档对象模型 DOM 将所有页面内容表示为可以修改的对象、CSSOM解释了如何将CSS表示为对象、浏览器对象模型BOM表示由浏览器提供的用于处理文档之外的其他内容如location、alert/confirm/prompt等
37.DOM树
(1)浏览器会自动修正不正确的HTML,形成完整的DOM,如自动添加body标签、自动关闭标签等
(2)HTML中所有的内容包括注释都会成为DOM的一部分
(3)查看DOM树
i.浏览器中的Elements所有节点就是DOM树节点
ii.在线工具:http://software.hixie.ch/utilities/js/live-dom-viewer/
38.遍历DOM树
(1)document对象是DOM树的入口
(2)null表示DOM中无该节点, 如:在head节点中访问document.body则为null,脚本无法访问 运行时不存在的元素
(3)常用遍历:document.body、document.head、document.childNodes(所有子节点(直接子节点),结果是数集合)、firstChild、lastChild、document.body.parentNode父亲节点、document.head.nextSibling下一个兄弟节点、document.firstChild.previousSibling前一个兄弟节点
(4)DOM集合是只读的,不能通过=赋值操作,DOM集合是实时的
(5)parentElement和parentNode一般是一样的,但是对于根节点则不同,parentNode返回的是任何类型的父节点,而parentElement则返回的是节点类型,在documentElement 这个根节点上两者不同

eg:
alert(document.documentElement);//根节点
alert(document.documentElement.parentNode);//document
alert(document.documentElement.parentElement);//null.因为html是根元素,没有父元素了

(6)childNodes会列出所有直接子节点和其中的所有text节点,不管text节点是否是直接子节点,都会列出,而children则会列出严格意义上的直接子节点
(7)table中特殊的节点属性
table.rows --所有tr的集合; tr.cells–获得特定tr中所有的td;tr.rowIndex–tr的编号;td.cellIndex–在封闭的tr中单元格的编号
eg:

let ta = document.getElementById("table");
alert("row编号:"+row.rowIndex);
alert("row的所有td和第一个td的编号:"+row.cells[0].cellIndex)

39.搜索DOM树
(1)尽量不要直接使用id来获取元素,容易命名冲突
(2)按照css选择器来搜元素 elem.querySelectorAll,返回元素中与给定的css样式匹配的元素
eg:

   let ta = document.getElementById("table");
   let arr = ta.querySelectorAll("tr:last-child > td");//选择tr对应父元素(table)的最后一个tr的子元素td,选择其中的text
for(let row of arr){
alert(row.innerText);
}

(3)querySelector调用返回给定css的第一个元素
(4)getElementsBy*等查找返回的是实时的集合,当元素增加或者改变时,集合元素会动态改变,而querySelectorAll则是静态的集合,一旦赋值不会变化
eg:

<tr class="r">
    <td>
        三行一列
    </td>
</tr>
<script>
    let arr = document.getElementsByClassName("r"); //1
    alert(arr.length);
    let qr = document.querySelectorAll("[class = r]");
    alert("qr:"+qr.length) ;//1
</script>
<tr class="r">
    <td>
        四行一列
    </td>
</tr>
<script type="text/javascript">
    "use strict"
    alert(arr.length); //2
    alert("qr:"+qr.length)//1
</script>

40节点属性和内容相关
(1)innerHTML允许将元素中的HTML获取为字符串形式,也可以修改它,这是更改页面最有效的方式之一
(2)outerHTML不会改变元素,而是在DOM中替换它
(3)innerHTML属性仅对元素节点有效,而对于其他节点则一般使用data取值
(4)textContent一般用于写入字面文本,与innerHTML的区别在于innerHTML会识别文本中的标签,并对页面内容 做相应的修改,而textContent则是纯文本,字面输入什么,就是什么,内容不做处理
eg:

<body>
这是纯文本
<!--this is a  comment -->
<table id="table"></table>
</body>


let bd = document.body
alert(bd.firstChild.innerHTML); //undefined 因为firstChild不是元素
alert(bd.firstChild.data); //展示内容 这是纯文本
alert(bd.firstChild.nextSibling.data);//展示注释内容 this is a  comment
alert(bd.textContent);//纯文本
let tb = document.getElementById("table");
let str = "<tr><td>这是后来插入的字符串</td></tr>"
tb.innerHTML  += str; //重写tb中的html内容,直接增加一行一列
tb.textContent +=str; //这里对内容按照字面量直接展示

41.Attribute 特性和property属性
(1)property是DOM中的属性,是js中的对象,是一个DOM元素作为对象其附加的内容,是多类型的,如CheckBox的checked属性可能是false或者true;attribute是HTML标签上的特性,它的值只能是字符串 https://www.cnblogs.com/lmjZone/p/8760232.html
(2)property可以用对象.的方式获取或者当成特性也可,而自定义特性attribute则只能用getAttribute获得

eg:<input id="put" type="checkbox"   type1="test" >
put.checked = false ; put.getAttribute("checked")=null
put.type1  //undefined;  put.type  //Checkbox ;  put.getAttribute("type") //Checkbox;

(3)自定义特性必须以data-开头,这是js预留给自定义特性用的,防止以后语言发展的冲突,同时这些特性都在dataset属性中保存,可通过该属性以.的方式获取,多词可使用驼峰格式调用
eg:

<input id="put" type="checkbox"   data-type1-test="test" >
let in1  =document.getElementById("put");
alert(in1.dataset.type1Test); //test

42.修改文档
(1)插入节点的几种方法

node.append(...nodes or strings) —— 在 node 内末尾 插入节点或字符串,
node.prepend(...nodes or strings) —— 在 node 内开头 插入节点或字符串,
node.before(...nodes or strings) —— 在 node 前面 插入节点或字符串,
node.after(...nodes or strings) —— 在 node 后面 插入节点或字符串
node.replaceWith(...nodes or strings) —— 将 node 替换为给定的节点或字符串。

以上的文字都是作为纯文本插入的,并不会解析成HTML节点

eg:let tb = document.getElementById("table");
let tr = document.createElement("tr");
    tb.append("tr",tr); //这个会在表格中插入字符串tr以及一个tr节点

(2)将文本作为HTML代码插入的方法 insertAdjacentHTML/Text/Element,格式:elem.insertAdjacentHTML(where,html)
“beforebegin” — 将 html 插入到 elem 前插入,“afterbegin” — 将 html 插入到 elem内 开头,“beforeend” — 将 html 插入到 elem 内末尾,“afterend” — 将 html 插入到 elem 后。
eg:

 let tb = document.getElementById("table");
tb.insertAdjacentHTML("beforeend","<tr><td>五行一列</td></tr>")

(3)移除节点 node.remove()
(4)所有插入方法,都会将元素从旧位置删除,并在新位置插入,所以移动元素时,不用再专门删除原有旧位置元素

eg:<tr id = "first">
    <td>
        一行一列
    </td>
</tr>
<tr id = "second">
    <td>
        二行一列
    </td>
</tr>
<tr id = "third" class="r">
    <td>
        三行一列
    </td>
</tr>
 first.before(third);  //一二三变成三一二

43.设置style和读取style
(1)设置 属性值,直接用元素的style属性

eg:  let tb = document.getElementById("table");
tb.style.border = "1px solid red";

(2)获取属性值,style属性只能获得style特性的属性值,即直接在标签上 通过style设置的样式,而对于css样式,则无法通过style读取,应该通过计算属性 getComputedStyle(element, [pseudo])获取,结果是一个具有样式的的对象

eg:
table{
    background-color: grey;
}
alert(tb.style.background);//空的
    let style = getComputedStyle(tb);
    alert(style.backgroundColor);//rgb格式

44.Window大小和滚动
(1)元素的集合属性
clientWidth/clientHeight — 内容的 width/height,包括 padding,但不包括滚动条(scrollbar)
(2)获得窗口的宽度和高度

eg:
alert("不包括滚动条:"+document.documentElement.clientWidth);
alert("包括滚动条:"+window.innerWidth);

(3)滚动相关操作
i.读取当前滚动位置:

eg:
alert("不包括滚动条:"+document.documentElement.clientWidth);
alert("包括滚动条:"+window.innerWidth);
alert("当前滚动X:"+window.pageXOffset+"当前滚动Y:"+window.pageYOffset)//获得当前滚动位置,都是只读属性

ii.移动窗口

  <button onclick="window.scrollBy(1,10)">相对于当前位置向下移动10px向右移动1px</button>
<button onclick="window.scrollTo(0,0)">绝对位置移动,移动到最顶端</button>

iii.elem.scrollIntoView(boolean/Object) 移动某个元素到窗口顶部或者底部

  elem.scrollIntoView(true);//默认,将元素本身移动到可视窗口的顶端,此时滚动条会向下滚动, 如果下面已经没有可滚动内容,那么当前元素有可能不会移动到顶部
elem.scrollIntoView(false);//底部
element.scrollIntoView({behavior: "smooth",block:"start"});//定义元素滚动是否平滑滚动,默认是auto,非平滑,到窗口顶部,
behavior  定义动画过渡效果, "auto""smooth" 之一。默认为 "auto"  
block 定义垂直方向的对齐, "start", "center", "end","nearest"之一
inline    定义水平方向的对齐, "start", "center", "end"

45.坐标
(1)js处理两种坐标:相对于窗口 clientX/clientY ,元素滚动时该坐标会发生变化;相对于文档pageX/pageY , 元素滚动时在文档中的相对坐标不变
(2)elem.getBoundingClientRect()返回最小矩形的窗口坐标的一个DOMRect对象,返回的坐标是相对于窗口的坐标,内容包括:
x/y — 矩形原点相对于窗口的 X/Y 坐标 width/height — 矩形的 width/height(可以为负) top/bottom — 顶部/底部矩形边缘的 Y 坐标 left/right — 左/右矩形边缘的 X 坐标
在这里插入图片描述

关系为: left=x;top=y,right = left+width; bottom=y+height
(3)元素相对于文档的坐标– elem.getBoundingClientRect() 加上当前页面滚动。

let box = elem.getBoundingClientRect();
top = box.top +window.pageYOffset; bottom= box.bottom + window.pageYOffset,
right = box.right+window.pageXOffset; left= box.left + window.pageXOffset

(4)点击获取鼠标坐标

eg:that.onclick = function(e) { // shows click coordinates
    debugger;
    document.getElementById("result").textContent = e.clientX + ':' + e.clientY;
};

(5)元素的几何图
HTMLElement.offsetWidth 是一个只读属性,返回一个元素的布局宽度。一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(border)、水平线上的内边距(padding)、竖直方向滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)的值。offsetHeight类似
在这里插入图片描述

46.事件委托
(1)利用冒泡将子元素的一些统一的动作委托给父元素去做,减少代码量,类似于将通用方法抽象到父类中

eg:统一给子元素加按钮方法
<div id="buttons">
    <p>df</p>
    <button data-action="save">Save</button>
    <button data-action="edit">Edit</button>
    <button data-action="search">Search</button>
</div>
ocument.getElementById("buttons").onclick=function(event){
    let target = event.target;
    if(target.tagName.toLowerCase()!='button'){
        return;
    }
    let d = target.dataset.action;
    let obj = {
        save:function  (){
            alert("saving")
        },
        edit:function (){
            alert("edit")
        },
        search:function (){
            alert("search")
        }
    }
    obj[d]();//动态调用对象方法的形式
}

ps:js中方法调用的几种方式:
方法调用模式: object.func();func定义在对象中 ,动态调用时object[key].func()
函数调用模式:function f(){};f()方法名调用
apply调用模式 //这中调用方式的优点在于可以指向this指向的对象。
//apply的第一个参数就是this指针要指向的对象,后面的是参数
func.apply(obj,args)
47.浏览器的默认行为
(1)常见默认行为:点击链接触发导航、点击提交表单、按下鼠标选中文字等
(2)阻止:
使用event对象,event.preventDefault()方法;
若监听事件是on则函数返回一个false也可以阻止

eg:在a标签上增加一个click事件,同时阻止a 导航
<a href="http://www.baidu.com" onclick="test0()">这是测试</a>
<a id="a" href="http://www.baidu.com" onclick="event.preventDefault()">这是测试</a>,这里的event其实就是点击事件对象本身
//然后可以通过addEvent的方式增加一个事件监听
 function test(){
     alert("test");
 }
function test0(){return 0}
document.getElementById("a").addEventListener("click",test);

(3)event.defaultPrevented默认行为被阻止时,该属性为true,否则为false

ps:增删改查元素的class
classList下的方法
  增加 class — node.classList.add(); 删除 class — node.classList.remove()
	切换 class — node.classist.toggle();判断 class — node.classist.contains()

48.创建自定义事件
(1)创建

eg:let event = new Event(type,[options]);
options有两个可选项:bubbles: false/true;true表示事件会冒泡; cancelable:true/false 
true则默认行为会被阻止

(2)dispatchEvent分配事件,即需要将新建事件挂在某个元素上

eg: 自定义一个hello事件并冒泡捕捉
//要先监听再创建并分配,内建的事件应该也是这个顺序
document.addEventListener("hello",()=>alert(event.isTrusted));
//创建
let event1 = new Event("hello",{bubbles:true,cancelable:false});
//分配
elem.dispatchEvent(event1);

(3)判断是自定义事件还是内建事件,使用event.isTrusted TRUE则为 内建
49.鼠标事件
(1)点击事件event提供了坐标有两种:
相对于窗口的坐标:clientX和clientY;相对于文档坐标 pageX和pageY
(2)防止鼠标按下时或者按住不放移动选择文本,阻止mousedown的默认事件即可,不是说文本就不能被复制,而是只能从两端被复制

eg:<p  id="pp" onmousedown="return false">按下不选择</p>
document.getElementById("pp").ondblclick=function(){
    alert("double");//双击只会alert,不会复制文本
}

(3)mouseover/mouseout鼠标移动到/离开时事件触发,有个特别的属性 relatedTarget
对mouseover:(relatedTarget → target)。
event.target —— 是鼠标移过的那个元素。
event.relatedTarget —— 是鼠标来自的那个元素;
对mouseout则相反:(target → relatedTarget)。
event.target —— 是鼠标离开的元素。
event.relatedTarget —— 是鼠标移动到的,当前指针位置下的元素
ps:从父元素进入到子元素也会触发父元素的mouseout事件,mouseout和mouseover会冒泡
(4) mouseenter/mouseleave 类似于 mouseover/mouseout,也是进入和离开时触发,区别在于
i.父子元素内部互相移动时不会触发事件;ii.这两个事件不冒泡,同时也就不能进行事件委托

eg:
<div id="father">
    <div id="son1"></div>
    <div id="son2"></div>
    <div id="son3"></div>
</div>
.hightlight{
    background-color: red;
}
let currentTg;
function bgc(event) {
    let h = "hightlight";
    if(event.target.id == "father"){
        return;
    }
    //先移除当前
   if (currentTg){
        currentTg.classList.remove(h);
   }
   event.target.classList.add(h);
   currentTg = event.target;
}
father.onmouseover = bgc //监听这个事件背景色就变化
//father.onmouseenter = bgc;//这个事件由于不会冒泡,因此监听父元素时,子元素的事件不会被监听到

(5)鼠标拖放事件
i.鼠标事件只发生在顶部元素上
ii.基础的拖放算法:
1).在mousedown上准备需要移动的元素,如创建副本,或者添加东西,或者对其属性进行改变等;
2).在mousemove上通过更改position:absolute/relative情况下的left和top来移动元素
3).在mouseup上执行当完成拖放时相关的操作
ps:获得一个点坐标处最顶层的元素,当最顶层元素的hidden=true时,会拿到下一层的元素,依次类推
let droppable = document.elementFromPoint(event.pageX,event.pageY);
eg:让一个球进洞,进洞的时候洞背景色变化,出洞则背景色复原

<div id="target" class="initbgc" style="width: 100px;height: 100px"></div>
<div id="ball"></div>
.initbgc{
    background-color: grey ;
}
.colorchange{
    background-color: orange;
}

 let ball =  document.getElementById("ball");
ball.onmousedown = function (event) {
   ball.style.position = "absolute";//先脱离文档流,并能够通过top和left定位
    //在整个body中活动
    document.body.append(ball);
    //记录下鼠标与球左上角的距离
    let offsetleft = event.clientX-ball.getBoundingClientRect().left;
    let offsettop = event.clientY-ball.getBoundingClientRect().top;
    document.onmousemove = function (event) { //这里的移动事件不能只放在ball上,因为如果鼠标移动过快会脱离ball,那么ball就不再移动了,要监听在整个文档上
        //这是在移动的时候鼠标会跑到圆点
    /*  ball.style.left = event.pageX-ball.offsetWidth/2+"px";
      ball.style.top = event.pageY-ball.offsetHeight/2+"px";*/
    //这样的话鼠标点在球哪里,移动的时候始终在哪里,不会跑到球圆心
        ball.style.left = event.pageX-offsetleft+"px";
        ball.style.top = event.pageY-offsettop+"px";
        //先隐藏ball,这样获得的元素就是ball下面的元素,,即最顶层的元素就会变成下一层元素
        ball.hidden=true;
        //获得坐标位置最顶层的元素
        let droppable = document.elementFromPoint(event.pageX,event.pageY);
        let target = document.getElementById("target");
        if(droppable.id==target.id){
            droppable.classList.add("colorchange");
        }else{
           target.classList.remove("colorchange");
        }
        ball.hidden = false;
    }
    ball.onmouseup = function (event) {
        //移除事件
     document.onmousemove = null;
     ball.onmouseup = null;
    }
}
//对于一开始拖拽的默认事件进行阻止
    ball.ondragstart = function() {
        return false;
    };

实现一个滑块:
在这里插入图片描述

eg:

#bar{
    height: 10px;
    width: 200px;
    border-radius: 5px;
    background-color: darkseagreen;
    position: fixed;
    bottom: 30px;
}
#block{
    width: 5px;
    height: 15px;
    top:-2.5px;
    background-color: blue;
    border-radius: 3px;
    position: relative;
}
<div id="bar"> <div id="block"></div></div>

let block  =document.getElementById("block");
block.onmousedown=function (event) {
    //求初始化相对位置差
    let offsetleft = event.clientX-block.getBoundingClientRect().left;
    document.onmousemove=function (event) {
        //这里的clientX并不是相对于bar的,如果直接给block的话,会有问题,client是相对于窗口的,而left是相对于父元素的,
        //这里是全部都用client长度算出left相对于父类的位置
        let left =  event.clientX -bar.getBoundingClientRect().left-offsetleft;
        if(left<0||left+block.getBoundingClientRect().width>bar.getBoundingClientRect().width){
            return;
        }
        block.style.left = left+"px";
    }

    block.onmouseup=function (event) {
        document.onmousemove = null; //上面滑动是document的,下面也要对应
        block.onmouseup = null;
    }
}
block.ondragstart = function() {
    return false;
};

50.浏览器事件汇总
(1)鼠标事件
click、contextmenu鼠标右键点击、mouseover/mouseout 鼠标 /离开、 mousedown/mouseup 按下或者松开左键时、mousemove
(2)键盘事件 keydown和keyup
(3)表单元素事件 submit 提交表单时,focus input获得焦点时
(4)Document事件 DOMContentLoaded 当HTML加载完,DOM被完全构建时触发
ps:DOMContentLoaded只能通过addEventListener添加监听事件,不能通过DOM属性
(5)CSS事件 transitionend 动画完成时
(6)事件处理器,某个元素一旦第一次监听上了某个事件后,只要是该元素上的动作就会触发该事件
i.一个在事件发生时运行的函数
ii.放置处理器的位置有:
HTML特性上,直接放置在on中,οnclick=“alert(‘hello’)”;或者编写函数,在特性上调用
DOM属性 ,使用DOM属性on来分配处理器
eg:document.ge tElementById(“addDiv”).onclick = function(e) { // shows click coordinates
document.getElementById(“result”).textContent = e.clientX + ‘:’ + e.clientY;
};
ps:在HTML特性上的处理器最终浏览器读到时也是通过DOM属性设置的
(7)移除一个事件,分两种
i: on的事件移除:,elem.onclick = null
ii.addEventListener添加的事件移除: element.removeEventListener(event, handler[, options]),
如果要移除事件句柄,addEventListener() 的执行函数必须使用外部函数,即有引用变量指向函数本身,不能移除匿名函数
(8)处理程序中this的值就是当前的元素
ps:DOM属性大小写敏感
(9)addEventListener可以添加多个事件处理器

eg:
let div =  document.getElementById("addDiv"); 
div.addEventListener("click",()=>alert("this is the first event"));
div.addEventListener("click",()=>alert("this is the second event"));

(10)事件对象event,不同的事件有不同的对象,其中有不同的属性,如点击事件的及格常用属性;
eg:alert(e.currentTarget);//是“当前”元素,其中有一个当前正在运行的处理程序,如冒泡事件中的最外层元素
alert(e.target)//是引发事件的“目标”元素,如冒泡事件中的实际触发元素
alert(e.type);//事件类型
document.getElementById(“result”).textContent = e.clientX + ‘:’ + e.clientY;//焦点坐标
(11)对象处理程序handleEvent,在对象中添加handleEvent函数,然后将对象传参给addEventListener 就会自动触发该函数
eg:

let div =  document.getElementById("addDiv");
let obj = {
    name:"zsx",
    handleEvent(evt) {
        alert(this.name)
    }
}
div.addEventListener("click",obj);

(12)冒泡和捕获
i.event.target 是表单中实际被点击的元素,即目标元素; this = event.currentTarget一般是最外层的元素
ii.停止冒泡 event.stopPropagation() 和 event.stopImmediatePropagation()

eg:
inner.onclick=function (e) {
    alert("this is inner");
    e.stopPropagation();//停止冒泡
    e.stopImmediatePropagation();//会阻止当前元素上其他事件触发
}

ps:冒泡尽量不要用
51.键盘事件
(1)keydown和keyup,keypress虽然保留,但有兼容性,已经弃用了
(2)event.code是物理按键代码,永远不变,即便是换了一门语言也不变,因此判断输入按键时,应该用code,event.key则是实际输出的字符,普通字符物理代码一般是 KeyA,KeyB…, 键为Digit0,Digit1… 特殊按键参考官网: https://www.w3.org/TR/uievents-code/#keyboard-key-codes
(3)keydown事件会自动重复,当按下一个键足够长时,就会自动重复动作,松开时会得到一个keyup,自动重复的event事件对象的even.repeat属性被设置为了true;
(4)keydown的默认行为无法被浏览器阻止,因为太多设备 了
(5)keydown重复执行的解决方法:
i.使用keyup代替,因为keyup只有一个
ii.判断repeat为true时,return
eg:

<input  id="input" style="width: 50px;position: absolute;top: 200px;" type="text"/>
inp.onkeydown=function (ev) {
    console.log(ev.repeat);
//repeat第一次为false,重复时为true
    if(ev.repeat)return;
    dis.textContent +="key:"+ ev.key+"---code:"+ev.code+"\n";
}

52.scroll滚动事件,事件名就为scroll,当屏幕或者可滚动元素发生滚动时触发事件
eg:无限滚动
window.onscroll = function (event) {
let p = document.createElement(“p”);
p.textContent = new Date();
document.body.append§;
}
53.form表单
(1)表单都是document.forms集合的成员,集合中的元素都是form.elements的集合,通过form.elements.eleName和form.eleName都可访问到,当后一种方式在js中改变元素name时,新旧name都被允许来访问元素

eg:<form name="my">
  <input name="one" value="1">
  <input name="two" value="2">
</form>
alert(document.forms.my); // <form name="my"> 元素
alert(document.forms[0].elements.two) ;//都是通过元素name属性来拿的
alert(document.forms.my.two) //直接通过form.eleName拿

(2)反向引用 通过表单元素来访问对应的表单,ele.form

eg:alert(document.forms[0].two.form);//反向引用

(3)表单元素select和option
元素有3个重要属性:
select.options–的集合;select.value-当前所选择的option的value;select.select.selectedIndex-对应的option的编号

(4)允许任何元素上聚焦:tabindex,,而且聚焦后有onfocus监听事件,tab键其实就是根据tablindex的值按顺序进行元素聚焦

eg:<ul>
    <li tabindex="1">One</li>
    <li tabindex="0">Zero</li> //0排最后
    <li tabindex="2">Two</li>
    <li tabindex="-1">Minus one</li> //-1 tab不会聚焦,但是有focus
</ul>
<div tabindex="3">Three</div>

(5)focus和blur不会冒泡,如果要利用冒泡进行事件委托,则可以使用focusin和focusout,这两个事件只能用addEventListener添加处理器,而不能使用on

eg: document.forms[0].addEventListener("focusin",()=>{
    document.forms[0].style.border = "1px red solid";
})

54.表单事件 change、put、cut、copy、paste
(1)change事件:当元素内容改变完成时才会触发input框键入时不会触发change,而当失去焦点时才会触发
(2)事件input,当对输入值修改后立即触发,而对于方向键等不涉及键入值得行为不触发该事件;oninput事件不能阻止
(3)事件:cut,copy,paste 可以通过event.preventDefault来阻止默认的剪切复制或者黏贴行为,它们属于ClipboardEvent类

eg:content.oncut = content.oncopy =  function (e) {
   e.preventDefault();//阻止后 就无法复制内容了 
}

54.表单提交
(1)提交表单时触发submit事件,用于在将表单数据发送到服务器之前进行字段校验不通过时可阻止表单提交
(2)submit事件,表单提交的两种方式:点击 或者在input 中点击enter键都会触发submit事

ps:enter按键会在input<type='submit'>上触发一次click事件
eg:<input type="text">
<input type="submit" onclick="alert('呵呵');return true;">

(3)submit()方法,对于在js中创建的form时,可以调用form.submit()方法,不会触发submit事件
55.页面的生命周期
DOMContentLoaded 事件 —— 浏览器已经完全加载了,但未加载和样式表等外部资源,HTML并构建了DOM数,DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口
load 事件 —— 在构建了DOM树的基础上,外部资源已加载完成,样式已被应用,图片大小也已知了。
beforeunload 事件 —— 用户正在离开:我们可以检查用户是否保存了更改,并询问他是否真的要离开。
unload 事件 —— 用户几乎已经离开了,但是我们仍然可以启动一些操作,例如发送统计数据。
(1)DOMContentLoaded 事件发生在 document对象,只能使用addEventListenter来捕获,该事件必须等待js脚本运行完后才能触发,原因是可能js中会去修改DOM树

eg:<script>
    document.addEventListener("DOMContentLoaded",function (e) {
        alert("script已经加载完成了,t图片大小为:"+ img.offsetHeight); //图片还没加载 是0
    })
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0" alt="">
alert("script loaded!!!") //先触发

(2)window.onload 事件是所有东西都加载完后触发的,可以用window=onload添加监听
(3)window.onbeforeunload事件如果访问者触发离开页面的导航或者关闭窗口,可以做些事情,如询问是否离开,有兼容问题
56.第三方资源加载onload和onerror
eg:img.onerror = function (e) {
alert(“加载失败”);
}
57.范围和选择操作 参考:https://zh.javascript.info/selection-range
(1)Range方法:
设置范围的起点:
setStart(node, offset) 将起点设置在:node 中的位置 offset
setStartBefore(node) 将起点设置在:node 前面
setStartAfter(node) 将起点设置在:node 后面
设置范围的终点(类似的方法):
setEnd(node, offset) 将终点设置为:node 中的位置 offset
setEndBefore(node) 将终点设置为:node 前面
setEndAfter(node) 将终点设置为:node 后面
如前所述,node 既可以是文本节点,也可以是元素节点:对于文本节点,offset 偏移的是字符数,而对于元素节点则是子节点数。
其他:
selectNode(node) 设置范围以选择整个 node
selectNodeContents(node) 设置范围以选择整个 node 的内容
collapse(toStart) 如果 toStart=true 则设置 end=start,否则设置 start=end,从而折叠范围
cloneRange() 创建一个具有相同起点/终点的新范围
如要操纵范围内的内容:
deleteContents() —— 从文档中删除范围内容
extractContents() —— 从文档中删除范围内容,并将删除的内容作为 DocumentFragment 返回
cloneContents() —— 复制范围内容,并将复制的内容作为 DocumentFragment 返回
insertNode(node) —— 在范围的起始处将 node 插入文档
surroundContents(node) —— 使用 node 将所选范围内容包裹起来。要使此操作有效,则该范围必须包含其中所有元素的开始和结束标签:不能像 abc 这样的部分范围。
(2)selection选择
i.选择事件
elem.onselectstart —— 当选择从 elem 上开始时,例如,用户按下鼠标键并开始移动鼠标。
阻止默认行为会使选择无法开始。
document.onselectionchange —— 当选择变动时,只能加载document上
ii.获取选择内容
文本:document.getSelection(0.toString();
作为DOM节点:获取选择范围,并调用range.cloneContents对内容进行复制

eg:
document.addEventListener("click",function (e) {
  let ele = document.elementFromPoint(e.pageX,e.pageY);
  let range = new Range();
  range.selectNode(ele);
  //将范围添加到选择中
    document.getSelection().removeAllRanges();//要先移除已有的选择,否则浏览器会忽略新选择
    document.getSelection().addRange(range);
    alert(document.getSelection().toString());//内容文本化
    for(let i =0;i<document.getSelection().rangeCount;i++){
        document.body.append(document.getSelection().getRangeAt(i).cloneContents());//获得元素
    }
})

(3)表单控件中的选择有专门的API,没有Selection和Range对象
属性:input.selectionStart —— 选择的起始位置(可写),一个字符算一个
input.selectionEnd —— 选择的结束位置(可写),
input.selectionDirection —— 选择方向,其中之一:“forward”,“backward” 或 “none”(例如使用鼠标双击进行的选择)
事件:input.onselect —— 当某个东西被选择时触发。
方法:input.select() —— 选择文本控件中的所有内容,
input.setSelectionRange(start, end, [direction]) —— 在给定方向上(可选),从 start 一直选择到 end。
input.setRangeText(replacement, [start], [end], [selectionMode]) —— 用新文本替换范围中的文本。
eg:

inp.onselect = function (ev) {
   alert(inp.value.slice(inp.selectionStart,inp.selectionEnd));//间接获取选择的字符
}

(4)判断是否元素中有选中的内容,可使用ele.selectionStart==selectionEnd

eg:如果没有选中,则在光标处插入hello,否则替换为hello
sub.onclick = function (ev) {
    ev.preventDefault();
    //没有选择内容
    if(inp.selectionStart==inp.selectionEnd){
        inp.setRangeText("HELLO");
    }else{
        inp.setRangeText("HELLO",inp.selectionStart,inp.selectionEnd,"end")
    }
}

(5)使内容不可选 ,但是应用在input框上暂时无效,没有验证出效果,其他元素ok
i.设置css user-select:none
ii.阻止onselectstart默认行为

eg:document.onselectstart = () => false; //整个文档不可选择

58.跨窗口访问
同源:如果不同源,则无法跨窗口访问变量、文档以及任何东西
(1)iframe标签是一独立的新窗口,window和document都是全新的对象
iframe.contentWindow 来获取 中的 window;iframe.contentDocument 来获取 中的 document
(2)window.frames 子窗口的集合 ,window.parent父窗口的引用,window.top 对最顶级父窗口的引用

eg:按钮展示不同iframe
<nav id="nav">
    <button id="baidu" >baidu</button>
    <button id="sougou">sougou</button>
    <button id="qq">QQ</button>
</nav>
nav.onclick = function (event) {
    switch (event.target.id) {
        case "baidu":
            iframe.src = "https://www.baidu.com";
            break;
        case "sougou":
            iframe.src = "http://www.sougou.com/";
            break;
        default:
            iframe.src = "https://www.qq.com/";
    }
}

59.blob二进制以及下载
(1)blob由可选的字符串type一串二进制字节组成
构造器为new Blob(blobParts,options),blobparts是值数组,options为可选对象{type:“描述类型如image等,endings是否转换换行符”}

ps:第一个参数一定要是数组
(2)blob用做a/img的URL,下载对象,转换base64
ps:a标签download特性强制浏览器下载而非打开

eg:nav.onclick = function (event) {
    let blob;
    switch (event.target.id) {
        case "baidu":
           blob = new Blob(["https://www.baidu.com","百度"],{type:"text/plain"});
            break;
        default:
            blob = new Blob( ["https://www.qq.com/"],{type:"text/plain"});
    }
    let url = URL.createObjectURL(blob);
    //创建临时元素
    let link = document.createElement("a");
    link.id="link";
    link.href = url;
    link.download = event.target.id+".txt";
    link.click();//模拟a标签点击事件
    //移除临时元素
    link.remove();
URL.revokeObjectURL(link.href);//从内存中删除url到
的映射
URL.revokeObjectURL(url) 从内部映射中移除引用,因此允许 Blob 被删除(如果没有其他引用的话),并释放内存。
}

60.file和filereader
(1)常见的获得file对象的方式 ,file对象继承自blob,有相同的属性,同时又name和最后修改时间以及文件大小等属性
eg:

校验file后缀
<input multiple="multiple" onchange="check(this)" type="file"> //加multiple是多文件上传,不加则是单文件上传

function check(input){
 for(let file of input.files){ //这里是类数组对象,是个对象,然后 下标为key,文件为value
  alert(file.name+file.size+new Date(file.lastModified))
download(file)

//files: {0: File(838413), 1: File(2437), 2: File(457), length: 3}
 }
}

ps:下载通用方法

function download(file){
    let a =  document.createElement("a");
    a.download = file.name;
    a.href = URL.createObjectURL(file);
    a.click();
    URL.revokeObjectURL(a.href); //移除url到文件在内存中的映射关系
    a.remove();
}

(2)FileReader对象 从Blob中读取数据
i.构造器 let reader = new FileReader();
ii.方法
readAsArrayBuffer(blob) —— 将数据读取为二进制格式的 ArrayBuffer。
readAsText(blob, [encoding]) —— 将数据读取为给定编码(默认为 utf-8 编码)的文本字符串。
readAsDataURL(blob) —— 读取二进制数据,并将其编码为 base64 的 data url。等于 URL.createObjectURL(file)
abort() —— 取消操作。
iii.过程中的事件
loadstart —— 开始加载。progress —— 在读取过程中出现。load —— 读取完成,没有 error。abort —— 调用了 abort()。error —— 出现 error。loadend —— 读取完成,无论成功还是失败
iv.读取完调用读取结果:
reader.result或者reader.error
eg:

let read = new FileReader();
read.readAsText(file);
//读取成功
read.onload=function () {
    let p = document.getElementById("result");
    p.textContent = read.result;
};

61.Fetch 发送网络请求
(1)基本语法
let promise = fetch(url,[options]); options可选的参数对象:method、header等,默认是get请求
获取响应分两个阶段:
第一阶段 fetch使用返回的promise使用内建的response对象解析
第二阶段 以不同的promise的方法来以不同的格式访问body,如:response.text() —— 读取 response,并以文本形式返回 response,response.json() —— 将 response 解析为 JSON等
62跨域请求
(1 )一些静态文件不受同源策略影响,可跨域标签

;;;;;;;;

(2)跨域请求中,浏览器扮演授信的中间角色,跨域请求中会有一个Origin字段表明源,同域没有这个字段,之所以要这个origin字段是因为referer是可更改的字段不可靠,有时候没法说明源
在这里插入图片描述

(3)简单请求和非简单请求,以及非简单请求的请求步骤
参考:https://zh.javascript.info/fetch-crossorigin
62.xmlhttprequest()发送请求 https://zh.javascript.info/xmlhttprequest
eg:

//使用promise和Xmlhttprequest封装一个ajax方法
function ajax({url,type="GET",data,dataType="json"}){
    return new Promise((resolve,reject)=>{
        let h = new XMLHttpRequest();
        h.open(type,url); //open做基本的网络配置
        h.send(data);//send才是发起一个网络请求
        h.onload=function () {
            resolve(h);
        };
        h.onerror = function () {
            reject(h);
        }
    });
};
ajax({url : "http://127.0.0.1:8888"}).then((h)=>{
    vm.ht = h.response;
},(h)=>{
    console.error(h)
})
  1. websocket连接 https://zh.javascript.info/websocket
    (1)websocket与http的区别参考:https://blog.csdn.net/c_kite/article/details/80033686
    (2)实时向web端展示的传统方案是http固定时间频率发送请求,缺点是http可能包含很多头信息,而body很小,另外可能服务端数据并没有更新,浪费很多带宽
    (3)websocket是HTML5下的新协议,实现了 浏览器和服务器全双工通信,与http相同点在于都是通过建立的tcp连接通信,区别图:
    在这里插入图片描述

(4)优势:全双工通信,不像http有明显的client和server之分;websocket只有在第一次建立连接时发送头部信息,后续都是直接发送data数据
(5)websocket本身数据加密,没有跨域的问题
64.浏览器中存储数据
(1)cookie
i.document.cookie能访问到当前网站的cookie,同时也能更新或者设置 一组cookie,而不会动其他cookie
ii.每个域下面cookie数量大概20左右,浏览器会限制
iii.path url路径前缀,该路径及其子路径下页面可以访问到该cookie, 默认为当前路径,如果一个 cookie 带有 path=/admin 设置,那么该 cookie 在 /admin 和 /admin/something 下都是可见的
iv.domain域 cookie只能在同级域下访问,子域不共享,domain不能设置;
v.不设置expires或者max-age时,浏览器关闭则cookie消失,max-age指明的是cookie的过期时间距离当前时间的秒数 ,删除一个cookie时可以设置max-age为-1或0;expires必须设置成GMS时间,可以通过date.toUTCString()
vi.secure参数表明cookie只能被通过HTTPS传输,cookie传输不区分协议,只区分域和path
vii.samesite防止跨站攻击,samesite=strict(和没有值的 samesite 一样)表明如果用户来自同一网站之外,那么设置了 samesite=strict 的 cookie 永远不会被发送。
viii.httpOnly不属于js的范围,,设置完后cookie处的http会有个对勾,可以由服务器进行cookie的设置,设置为true时,禁止任何js代码读取该cookie,document.cookie也访问不到
viiii. cookie的name可以重复,只要path或者domain不同即可
x.子path的document没有权限修改或者删除父path的cookie

eg:document.cookie = "name=zsx1;max-age=3600";
alert(document.cookie);
setTimeout(()=>{
    document.cookie="name=zsx;max-age=0"; //删除cookie
    console.log("sdfsdfs")

},5000)
	

(2)localStorage 浏览器存储对象,http header不能修改,不会过期,重启仍然有效,同源的所有窗口共享,存储形式key-value,key和value都字符串

eg://访问方式
localStorage.setItem("qq","qq");
alert(localStorage.getItem("qq"));
//访问方式
localStorage.ww="ww";
alert(localStorage.ww);
delete localStorage.qq; //删除
//存储对象不可迭代,只能下标遍历
for(let i = 0;i<localStorage.length;i++){
    alert(localStorage.key(i))
}

(3)IndexedDB 浏览器数据库,普通的bs用不上,更适合离线应用

65.window的hash和hash事件
hash即URL中"#"字符后面的部分。

①使用浏览器访问网页时,如果网页URL中带有hash,页面就会定位到id(或name)与hash值一样的元素的位置;

②hash还有另一个特点,它的改变不会导致页面重新加载;

③hash值浏览器是不会随请求发送到服务器端的;

④通过window.location.hash属性获取和设置hash值。
hashchange事件(IE8已支持该事件)

①当URL的片段标识符更改时,将触发hashchange事件(跟在#符号后面的URL部分,包括#符号)

②hashchange事件触发时,事件对象会有hash改变前的URL(oldURL)和hash改变后的URL(newURL)两个属性:

                       <li role="presentation" :class="{active:currentHash==='all'}"><a href="#/all" >全部完成</a></li>
window.addEventListener('hashchange',function(e) { console.log(e.oldURL);  console.log(e.newURL) },false);
  1. 判断滚动条是否滚到底部
  //判断滚动条是否到底部
                //参与的css属性:当前元素内容全文高:document.documentElement.scrollHeight
                //网页被卷去的高度即在y轴上滚动过的距离document.documentElement.scrollTop
                //当前元素可见区域高:document.body.clientHeight
                //属性解释 参考:https://blog.csdn.net/lhjuejiang/article/details/79492290
                
                //每次执行的时候,先清除上次的定时器,然后只保留最近的一个定时器,
                // /防止稍微一滚动就频繁的调方法
                clearTimeout(this.timer);
                console.log("sfsdfs");
                this.timer =  setTimeout(()=>{
                    //是否滚动到底部的条件为
                    if(this.$refs.scroll.clientHeight+this.$refs.scroll.scrollTop>=this.$refs.scroll.scrollHeight){
                        this.getbooks();
                    }
                },500);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值