js 基础

155 阅读9分钟

js基础

  1. NaN 不等于任何数

  2. null undefined NaN 0 '' false ===>false

  3. if条件必须互斥

  4. break 必须写在循环内部

  5. Number() 不能转化为数字的都为NaN

    a. Number(null) 0

    b. Number(undefined) NaN

  1. parseInt(dome, radix);

    a. dome以radix为基地转化为10进制

    b. radix可以为 2/4/8/10

  1. toString(radix)

    1. undefined null 没有toString()方法

    2. var num = 3 num.toString(8) 将调用toString()方法将123转为8进制 需要将目标是转为几进制基底就传几进制 3.toString() (报错) 3..toString() '3' 3...toString()报错

    3. num= 255 num.toString(16)//'ff'

  1. "+-" 正负 先调用 Number
  2. "+" 字符串加减 先调用 String
  3. undefind != 0 !> 0 !<0 null != 0 !> 0 !<0 undefind == null
  4. NaN !== NaN 啥都不等于
  5. toFixed(3) 科学计数法

js函数

  1. 函数的形参与实参个数相等时会有映射规则

    arguments 实参

  2. 递归 (好处 代码简洁

    a. 找规律 b. 找出口

function mul(n) {
  if (n == 1 || n = 0) {
    return 1;
  }
  return n * mul(n - 1);
}

预编译

  1. 函数声明整体提升
  2. 变量 声明提升

全局 GO === window

  1. 创建GO对象
  2. 变量声明值为undefind
  3. 函数赋函数体

GO{

}

函数体AO对象 执行期上下文 发生在函数执行前一刻

  1. 创建AO对象
  2. 将形参 变量声明 作为AO对象属性名, 值为undefind
  3. 实参形参统一
  4. 在函数体内找函数声明 ,值为函数体

AO{

}

AO里有的先访问自己 即使自己值为undefind ,没值才访问GO里面的内容

暗示全局变量 AO里面没有定义变量赋值会直接到GO上

!!'' false

!!' ' true

闭包

把函数保存到外部 内部函数会保存外部函数的 AO

  1. 坏处 作用域链不释放
  2. 好处 私有化变量

立即执行函数

(function () {}())

  1. 执行完立即释放
  2. 只有表达式才能被 执行符号 执行()
  3. 能被执行符号执行的函数名字会被忽略
var test = function () {}()

"+ - !" 能让函数声明立即执行 同样名字会被忽略

 +function Test(){ console.log(8888) }();

原型

documentWrite 会调用toString();

继承

function inherit(Target, Origin){
    function F(){};
    F.prototype = Origin.prototype
    Target.prototype = new F(); F构造函数实例化了一个对象,这个对象的__proto__会指向F构造函数的原型对象prototype
    Target.constructor = Target;
};
Father.prototype.lasteName = '祖先';
function Father(){
};
function Son(){
};
inherit(Son, Father); //必须在new之前完成,不然就更改地址
var son  = new Son();
var father = new Father();

识别引用类型的3种方法

1.constructor 
2.instanceof
3.Object.prototype.toString.call()

this

var a = 123;
function test(){
	var a = 456;
  this.a = 678;
  console.log(a);
}
test() // 456

var a = 123;
function test(){
  this.a = 456; //this属于window 更改a属性
  console.log(a);
}
test() // 456

var a = 5;
function Test(name){
	this name = name;
} 

var test = Test('sunny')   //this 指向window
var test = new test('bob'); //this 指向Test这个构造函数
test();

 GO{
   a = 0
   this:test{} this里面没有a变量
 }

arguments的callee

var a = (function (n){
  if(n == 1){
  	return 1;
  }
  return n * arguments.callee(n - 1); // 自身的引用
}(10))

函数方法执行的caller

function dome(){
	sum()
}
function sum(){
  console.log(sum.caller) //在自身函数中查找调用自己的函数
}
dome()

克隆 or 浅拷贝

//浅拷贝
let obj = {
	name:'bob',
  age:'12'
}
let newobj = Object.assign({},obj );
//深拷贝
1.let newobj = JSON.parse(JSON.stringify(obj))

2.const obj = {
  name:'bob',
  age:'18',
  list:[1,2,3,4,5],
  color:{
    red:'1',
    green:[1,2,3,4,5,88]
  }
};
    const obj1 = {};
    const deepClone = (origin, target) => {
        var  target = target || {};
        for(const key in origin){
            if(origin.hasOwnProperty(key)){
                if(typeof(origin[key]) === 'object'){
                    // origin[key] instanceof Array ? target[key] = [] :  target[key] = {};
                     Object.prototype.toString.call(origin[key]) === '[object Array]' ? target[key] = [] :  target[key] = {};
                    deepClone(origin[key], target[key])
               }else{
                    target[key] = origin[key] 
               } 
            }
        }
        return target;
    }
    deepClone(obj,obj1);

use strict

不允许使用
with{}
arguments.callee  caller
eval()
不允许var未声明
this指向underfind

date

new Date 记录的是new的一刻

getTime() 1970.1.1 至今的时间戳

function getTime(){
	var date = new Date();
	var list = [date.getFullYear(),date.getMonth()+1,date.getDate(),date.getDay(),date.getHours(),date.getMinutes(),date.getSeconds(),date.getMilliseconds()]
}

事件

1.onChick
div.onChick(()=> { console.log('a') }); 
缺陷 只能绑定一个方法

2.addEventListener 
div.addEventListener('click', fn, false); //事件冒泡 是否使用事件捕获?

class类

 extends 继承
 super 调用父类的方法
 constructor 构造器
 类里面没有变量提升,所以先有类才能实例化对象

class Father{
    say(){
       return '我是爸爸';
    }
}
class Son extends Father{
    say(){
       console.log(super.say()+ '的儿子'); super调用父类方法
    }
}
var test = new Son();



 abstract class Father {
    constructor(x,y){
      this.x = x;
      this.y = y;
    };
    add(){
      return this.x + this.y;
    }
  }
  class Son extends Father{
    constructor(x, y){
      super(x,y);
      this.x = x;
      this.y = y;
    }
    cut(){
      console.log(this.x - this.y);
    }
  }

let test = new Son(10,5);
test.add()//15
test.cut()//5


abstract class Father { 
  // abstract开头就是抽象类 无法创建实例 只能被继承 抽象类可以添加抽象方法
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  say() {
    console.log('我是爸爸的方法');
  }
  //abstract开头就是抽象方法,没有方法体,抽象方法只能定义在抽象类中 子类必须对抽象方法进行重写
  abstract public():void;
}

class Son extends Father {
  color: string
  constructor(name: string, age: number, color: string) {
  //father最大 如果在子类中写了构造函数(constructor)
  则在子类的构造函数中必须调用父类的构造函数 
    super(name, age)//super调用父类的构造函数
    this.color = color;
  }
  say(): void {
    // super.say();
    console.log('我覆盖了爸爸的方法');
    
  }
  public(): void {
      console.log('父类是抽象类定义了抽象方法,就必须在子类中重写');
  }
}

let test = new Son('小明', 18, 'red');

new时

1.内存中创建空对象
2.this指向这个空对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象 所以构造函数不需要return

原型

原型
prototype
作用
共享属性和方法

prototype
构造函数通过原型(prototype)构造的属性方法是所有对象共有的
每一个构造函数都有一个 prototype 属性,指向另一个对象,注意这个 prototype 就是一个对象
这个对象的所有属性和方法都会被构造函数拥有

1.原型是什么
一个对象,我们也称 prototype 为原型对象
2.原型的作用是什么
共享属性和方法

__proto__
对象都有一个方法 __proto__, 指向构造函数的原型对象的 prototype ,之所以我们对象可以使用构造函数
prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在


constructor 
指向构造函数本身

Star.prototype = {
	sum:function(){},
  cat:function(){},
  constructor:Star //如果我们修改了原来的原型对象,如给原型对象赋值一个对象,需要手动设置constructor
}
function Star(){}
var that;
Star.prototype.add = function(){
  that = this; // 在构造函数里面的this指向的是实例对象
}
var test = new Star();
test.add();
console.log(that === test)//true 

test__proto__ === Star.prototype
test.__proto__.constructor === Star.prototype.constructor  //true
Star.prototype.__proto__ === Object.prototype  //true
Object.prototype.__proto__ === null //true

扩展内置对象

不能使用对象赋值,因为会覆盖
Array.prototype = {
	sum: function(){}
}
使用.的方法往上添加方法
Array.prototype.sum = function(){
	var sum = 0;
  for(var i = 0 ;i < this.length;i++){
		sum += this[i]
  }
  return sum;
}
let list = [1,2,3]; //or  let list =new Array(1,2,3);
list.sum();//6

call

function test(x,y){
	console.log(this);
  return x + y; //33
}
test.call(); //this = window

let t = {
 name:'llm'
};
test.call(t,11,22); //this = {name: 'llm'}

类的本质

类的本质是函数 //构造函数另一种写法
是语法糖 一种更便捷的写法

数组方法

forEach() 返回新数组
filter()  返回满足条件的新数组
some() 返回是否满足条件 //布尔值 第一个满足则返回

list.some((function(item){
	if(item === 1){ 
    return true; //return true 说明找到了元素时及时终止循环 效率更高
  }
}))

trim() 去除左右两边的空格 返回新的字符串

对象方法

defineProperty 定义属性

Object.defineProperty(对象,属性值,{
  value:''//属性值
	writable: false ,// 是否可更改
  enumerable:false, //是否枚举
  configurable:false// 是否可删 以及是否允许修改第三个属性里面的特性 false 不允许修改
});
var obj = { 
  id:1,
	name:'bob',
};

Object.defineProperty(obj,'name',{ //修改属性可枚举是因为obj对象自带的
	value:'sunny'
})
Object.defineProperty(obj,'color',{ //添加属性不可枚举 因为enumerable属性默认为false
	value:'red' 
})
Object.defineProperty(obj,'id',{
	writable:false //无法更改ID
})
Object.defineProperty(obj,'address',{
  value:'浙江杭州',
	enumerable:false //无法遍历 false为默认值
})
Object.keys(obj); // ['id', 'name'] 返回属性名组成的数组

函数也属于对象

call apply bind总结

相同点:改变this指向
不同点:
1.call和apply会调用函数,改变this指向,
2.call传递参数num1,num2 apply传递参数为数组[num1, num2]
bind
1.不会调用原来的函数,可以改变原来函数内部的this指向
2.返回的是原函数改变this之后的产生新函数

应用场景
1.call做继承
2.apply跟数组有关系,借助数组的内置对象实现数组的最大值最小值 Math.max
3.不调用函数,却想改变this指向,比如改变定时器函数内部this的指向

'use strict'

变量必须先声明在使用 不能删除已经声明的变量
函数this指向undefined
定时器函数this还是指向window
函数里面的参数不允许有重名现象
不能在非代码块写函数

高阶函数

1.函数的参数是一个函数
function father(callback){
  callback && callback()
}
father(function son(){alert('高阶函数')})
2.函数的返回值是一个函数
function father(){
	return function son(){}
}
函数也是一种数据类型,同样可以作为参数,传递给另一个参数使用,最典型的就是作为回调函数

闭包

一个函数的作用域可以访问另一个函数的局部变量
作用:延伸了变量的作用范围

  var car = (function () {
    let start = 13;
    let total = 0;
    return {
      price: function (n) {
        if (n < 3) {
          total = start;
        } else {
          total = start + (n - 3) * 5
        }
        return total;
      },
      yd: function (flag) {
        return flag ? total + 10 : total
      }
    }
  })();

  car.price(5);

正则表达式

1.var reg = /^abcd/g;字面量
2.var reg= new RegExp(/abcd/,'g')构造函数

^ $
let str = /^a$/   开始结束符的限定
[^] 里面的^表示取反  也就是括号里面有的都返回false 
 
括号合集
1.大括号
 {} 量词
2.中括号
 [] 多选一
3.小括号
 ()优先级

[abc] 没有量词都(单选) a||b||c
let str = /[abc]/ 方括号包含其中任何一个字符都返回true 
()优先级
let str = /^abc{3}$/ 让c重复3let str = /^(abc){3}$/ 让abc重复3次

预定义类
\d  等价于 [0-9] 匹配数字
\D  等价于 [^0-9] 取反 匹配除了数字之外的字符 
\w  等价于 [A-Za-z0-9_] 字母数字下划线 
\W 	等价于 [^A-Za-z0-9_]  取反 字母数字下划线 之外的数
\s	等价于[\t\r\n\v\f] 匹配空格包含(换行符 制表符 空格符等)
\S	等价于[^\t\r\n\v\f] 匹配非空格符的字符


 量词 满足条件true
 * 重复零次或者多次
 + 重复1次或者多次
 ? 重复1次或者0次
中间不要有空格
 {n} 自定义n次
 {n,} 自定义返回n次或者n次以上
 {n,m}自定义大于等于n且小于等于m的
 
 let str = /^a*$/  出现0~无数个a
 let str = /^a+$/  出现1~无数个a
 let str = /^a?$/  出现1 || 0 a
 let str = /^a{3}$/ 出现3个a
 let str = /^a{3,}$/ 出现3个a及以上的会返回true
 let str = /^a{2,4}$/  出现大于等于2且小于等于4的返回true 
 str.test('aa')//true
 str.test('aaaaa')//false
 
座机号码
\d{3}-\d{8}|\d{4}-\d{7}
 
g 全局匹配
i 忽略大小写
gi 全局匹配 + 忽略大小写

let num = '1234446';
num.replace(/4|6/g,'*') //123****

 

js链式调用

var obj = {
    weight : 100 , 
    eat : function(){
        this.weight++;
        console.log('xiao ming cha pang la , tizhong' + this.weight)
        return this;
    },
    run : function(){
        this.weight -=3;
        console.log('xiao ming run , tizhong' + this.weight)
        return this;
    },
    swimming: function(){
        this.weight -=10;
        console.log('xiao ming swiming , tizhong' + this.weight)
        return this;
    }
}

obj.eat().run().eat().swimming()

数据量太大

1.分页 点击页面的时候在加载
2.图片懒加载 占位图片
3.加载小图 原图非常大,但是我们可以只要 220X220 的图片,实现方式为:图片上传阿里云的服务器,第一次查找实时压缩,第二次查找的时候使用缓存
4.虚拟dom 虚拟表格antd

清空数组

1.splice
2.length = 0
3. =[]

缓存

HTTP缓存

  1. 强缓存
    • Cache-control (缓存控制)
    • Expires (过期)
  1. 协商缓存
    • last-Modified
      • If-Modified-Since 通过时间(秒)进行对比 (如果修改自从)
    • Etag
      • if-None-Match 服务器生成的唯一表示 (如果没有匹配)

1.浏览器第一次请求===》请求浏览器缓存

2.没有该请求的缓存结果及缓存规则

3.发起http请求

4.返回该请求的结果以及缓存规则

5.将该请求的结果以及缓存标识保存在浏览器缓存中

结论:

  1. 浏览器每次发起请求都会在浏览器缓存中查找该请求的结果及缓存标识
  2. 浏览器每次拿到返回的结果及缓存标识都会存入在浏览器缓存中

强缓存

强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用缓存结果的过程

强制缓存分为3种

1.不存在缓存结果和缓存标识,强制缓存失效,直接向服务器发起请求(跟浏览器第一次请求一样

2.存在缓存结果和缓存标识,但是该结果已失效,强制缓存失效,则使用协商缓存

3.存在缓存结果和缓存标识,且该结果未失效,强制缓存生效,直接返回该结果

浏览器向服务器发送请求时,服务器会将缓存规则放入HTTP响应报文的HTTP(Response Headers)头中和请求结果一起返回给浏览器

Cache-control (优先级较高

    -   public:所有内容都将被缓存(客户端和代理服务器都可缓存)
    -   private:所有内容只有客户端可以缓存,Cache-Control的默认取值(私人
    -   no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定****
    -   no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
    -   max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

Expires (过期)

    -   Expires 其值为服务器返回该请求结果缓存的到期时间,再次发起请求时,如果客户端的时间小于Expires的时间,则使用缓存结果
    -   Expires 是HTTP/1.0 的产物,到了HTTP/1.1已经被Cache-control 代替,因为它原理是客户端请求的缓存时间和服务器端返回的时间做对比,可能会出现时区不同的情况

两者同时存在时以cache-control为先

cache-control:private, max-age=900 为相对值 在900秒内再次发送请求 强制缓存生效

expires :Wed, 12 Jan 2022 08:49:30 GMT 为绝对值 请求服务端的时间小于expires的时间 强制缓存生效

缓存的存储位置

  1. (内存缓存)memory cache

    • 数度快和时间限制
  2. (硬盘缓存)disk cache

    • 硬盘缓存是直接将缓存文件写入硬盘文件中,读取缓存需要对存放该缓存的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢

浏览器读取缓存顺序为 memory cache(内存) --> disk cache(硬盘)--> 服务器请求

在浏览器中,浏览器会在js和图片文件解析后存入内存缓存,那么刷新页面后就可以直接在内存缓存中读取(memory cache)

而css文件则会存入硬盘中,所以每次渲染页面都需要从硬盘缓存中取(disk cache)

协商缓存

协商缓存就是强制缓存失效后,浏览器带着缓存标识向服务器发送请求,由服务器根据缓存标识决定是否使用缓存的过程

  1. 304 资源无更新 继续使用缓存结果
  2. 协商缓存失效,返回请求结果和200,同时将请求结果和缓存标识存入浏览器缓存中

协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器

  1. Last-Modified / If-Modified-Since

    • 服务器响应请求时,该资源文件在服务器最后被修改的时间
    • If-Modified-Since是客户端再次发起请求时,携带上次返回的Last-Modified 的值,通过这个值告诉服务器,该资源上次最后被修改的时间,服务器收到该请求,发现请求头中包含 If-Modified-Since 的字段,则根据If-Modified-Since值与该资源在服务最后被修改的时间做对比,若服务器该资源最后被修改的时间大于If-Modified-Since则返回最新的资源及最新的Last-Modified 的值,code码200,否则返回304,代表该资源无更新可以继续使用缓存
  2. Etag / If-None-Match(优先级较高)

    • 返回当前资源文件的一个唯一标识(由服务器生成)
    • If-None-Match是客户端再次发起请求时,携带上次返回的唯一标识Etag的值,通过这个值告诉服务器,该资源文件的唯一标识,服务器收到请求后,发现该请求头中包含 If-None-Match的字段,则会将服务器当前的Etag的值和 If-None-Match的值对比,不相同则返回最新的资源及最新Etag的值,code码200,否则返回304,代表该资源无更新可以继续使用缓存