javaScript
- JavaScript简介
JavaScript一种动态类型、弱类型、基于原型的客户端脚本语言,用来给HTML网页增加动态功能。 JavaScript由三部分组成: ECMAScript(核心)+DOM(文档对象模型)+BOM(浏览器对象模型) ECMAScript作为核心,规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象 - 类型检测篇
1.
typeof使用快速简单 但是不能区分{}、[]、null 检测是都是object
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof null); // object
instanceof能够区分Array、Object和Function,适合用于判断自定义的类实例对象 Number,Boolean,String基本数据类型不能判断
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
3.Object.prototype.toString.call()精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用
window.onload和$(document).ready()的区别
window.onload是在页面中包含图片在内的所有元素全部加载完成再执行;
(document).ready()快于window.onload执行;
0.1+0.2!=0.3怎么处理计算机是采用二进制来表示十进制的 以IEEE 754 双精度64位浮点数
(0.1*10 + 0.2*10)/10 == 0.3 //true
深克隆就是让引用类型的value值从赋址变成赋值 让两个应用类型的值互相不影响
let obj ={
name:"xxxx",
arr:[1]
}
function deepClone(data){
let type = Object.prototype.toString.call(data)
if(type!=='[object Array]'&&type!=='[object Object]') return null;
let result = Array.isArray(data)?[]:{};
for(let key in data){
if(data.hasOwnProperty(key)){
if(typeof data[key] === 'object'&&data[key]!==null){
result[key] = deepClone(data[key])
}else{
result[key] = data [key]
}
}
}
return result
}
let arr = deepClone(obj)
arr.arr.push(2)
console.log(arr,obj);
当然有种简单的方法:JSON.parse(JSON.stringify());undefined、function、symbol 会被忽略;
base64:26个大小写 加1234567890加+/ 只转码 体积增加1/3
['1', '2', '3'].map(parseInt)
// console.log(['1', '2', '3'].map(parseInt)); [ 1, NaN, NaN ] parseInt('1',0) 0是基数代表进制
// 防抖
// 触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
// function debounce(fn,time=2000){
// let timer =null
// return function(){
// clearInterval(timer)
// timer=setTimeout(()=>{
// fn.call(this)
// },time)
// }
// }
// function sum(){
// console.log('do something')
// }
//document.addEventListener('click',debounce(sum),false)
// 节流
// 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
function throttle(fn,time=2000){
let flag = false
console.log('throttle',this);
return function(){
if(flag)return
flag=true
setTimeout(()=>{
console.log('setTimeout',this);
flag = false
fn.call(this,1)
},time)
}
}
function sum(data){
console.log('do something',this,data)
}
document.addEventListener('click',throttle(sum),false)
// var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
// console.log([...new Set(arr.toString().split(',').map(item=>Number(item)))].sort((a,b)=> a-b));
// console.log([...new Set(arr.flat(Infinity))].sort((a,b)=> a-b));
async await
ES2017 标准引入了 async 函数,它就是ES2016 Generator 函数的语法糖。
Generator 异步编程解决方案
async 函数返回值是一个promise对象 并且返回值会是promise对象中resolve方法的参数
function*helloWorldGenerator(){
yield'xia';
yield 'lin';
yield 'hui';
return '你好'
}
let grt = helloWorldGenerator()
let a = grt.next()
let b = grt.next()
let c = grt.next()
let d = grt.next()
let f= grt.next()
// console.log(Object.prototype.toString.call(grt),a,b,c,d,f);
//[object Generator] abc {value: "xia", done: false} d {value:"你好", done: true}
f {value: undefined, done: true}
function*helloWorldGenerator(){
[].forEach(item=>{
yield 1+1; //会报错 yield只能在Generator 函数中 可以使用for循环改进 async 一样
})
}
浏览器http缓存
浏览器缓存:把http请求回来的数据存储在本地的一种行为。
作用:
减少了服务器的负担,大大提升了网站的性能
加快了客户端加载网页的速度
分类:
看是否命中强缓存,再判断是否命中协商缓存!
强缓存:http1.0时使用的是Expires,通过一个绝对时间 ,缺点很明显
服务器与客户端时间偏差较大时,就会导致缓存混乱。
http1.1是Cache-Control max-age=多少秒,
同时启用的时候 Cache-Control 优先级高。
不会发送请求如果命中,则返回 200
协商缓存:会发送请求如果命中,则返回 304
当服务器返回文件时在response header中添加 Last-Modified ,当浏览器请求发现 Last-Modified,
于是添加If-Modified-Since这个request-header,值就是Last-Modified中的值 , 服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存 命中则返回 304
服务器response header中添加 Etag一种唯一标识,浏览器会将上一次返回的Etag值放到request header里的If-None-Match里,服务器发现ETag匹配一致返回 304 , 服务器会优先验证 ETag
浏览器本地缓存
1.localStorage,sessionStorage和cookie,WebSql和IndexDB
websql兼容性好 但是已经被废弃了
IndexDB:浏览器提供的本地数据库 ,提供查找接口,还能建立索引。
面向对象
把具有相同的特征的代码抽象出来,归为一类,把描述这个类的细节、功能挂在这个类的原型上的一种设计开发编程思想。 面向对象有三个特点:封装继承与多态
继承
A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法
1.原型链继承 : Student.prototype = new Person() // 子类型的原型为父类型的一个实例对象。 优点:简单,易于实现 缺点:继承单一,创建子类实例时,无法向父类构造函数传参,所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)constructor 被修改 2.借用构造函数继承(call继承):在子类型构造函数中通用call()调用父类型构造函数
function Person(name, age) {
this.name = name,
this.age = age,
this.setName = function () {}
}
Person.prototype.setAge = function () {}
function Student(name, age, price) {
Person.call(this, name, age) // 相当于: this.Person(name, age)
/*this.name = name
this.age = age*/
this.price = price
}
这种方式只是实现部分的继承,如果父类的原型还有方法和属性,子类是拿不到这些方法和属性的。
console.log(s1.setAge())//Uncaught TypeError: s1.setAge is not a function
优点:可以向父类传参,没有修改constructor 缺点:只能继承父类的实例属性和方法,不能继承原型属性和方法 3.组合继承(组合原型链继承和借用构造函数继承)(常用)
function Person(name, age) {
this.name = name,
this.age = age,
this.setAge = function () { }
}
Person.prototype.setAge = function () {
console.log("111")
}
function Student(name, age, price) {
Person.call(this,name,age)
this.price = price
this.setScore = function () { }
}
Student.prototype = new Person() Object.create(Person.prototype)//优化
Student.prototype.constructor = Student//组合继承也是需要修复构造函数指向的
Student.prototype.sayHello = function () { }
var s1 = new Student('Tom', 20, 15000)
var s2 = new Student('Jack', 22, 14000)
优点:不存在引用属性共享问题,可传参,函数可复用,可以继承实例属性/方法,也可以继承原型属性/方法 缺点:调用了两次父类构造函数,生成了两份实例
4.ES6中class 的继承 class Student extends Person
优点:语法简单易懂,操作更方便 缺点:并不是所有的浏览器都支持class关键字