欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【Interview】20201206 模拟

程序员文章站 2022-03-07 21:38:19
原始数据类型 和 引用数据类型原始数据类型 存在栈中 空间小 大小固定 频繁更换UndefinedNullStringBooleanNumberSymbolBigInt引用数据类型 存在栈和堆中 栈保存引用堆的指针Object(Function Array Date)数据类型判断typeof()只用于判断原始数据类型 引用数据类型全是Objecta instanceof b 通过判断是否是b数据类型的实例 不能判断 数字、字符串、布尔 因为他们不是某一数据类型的实例...

原始数据类型 和 引用数据类型

原始数据类型 存在栈中 空间小 大小固定 频繁更换

  • Undefined
  • Null
  • String
  • Boolean
  • Number
  • Symbol
  • BigInt

引用数据类型 存在栈和堆中 栈保存引用堆的指针
Object(Function Array Date)

数据类型判断

  • typeof()只用于判断原始数据类型 引用数据类型全是Object
  • a instanceof b 通过判断是否是b数据类型的实例 不能判断 数字、字符串、布尔 因为他们不是某一数据类型的实例
  • a.constructor === b 判断实例的构造函数
  • Object.prototype.toString.call(a)

隐式类型转换

  1. 字符串连接符与算术运算符
    num+Number(xxx)
    【Interview】20201206 模拟
  2. 关系运算符:会把其他数据类型转换成number之后再比较关系
    【Interview】20201206 模拟
  3. 复杂数据类型在隐式转换时会先转成String,然后再转成Number运算
    【Interview】20201206 模拟
  4. 逻辑非隐式转换与关系运算符隐式转换搞混淆
    【Interview】20201206 模拟
    【Interview】20201206 模拟

【Interview】20201206 模拟

事件流 事件捕获 事件冒泡 事件委托 监听事件(上层绑定 防止内存泄露)

  • 事件流:

用户和网页的交互事件从页面中传播的顺序。

  • 3种事件模型:
  • DOM0:网页中定义监听函数或者JS指定监听
  • IE模型:
    事件处理:执行目标元素绑定的事件
    事件冒泡:从目标元素一直冒泡到document,依次检查经过的节点是否绑定事件监听函数,有则执行
    可以添加多个监听函数,按顺序执行
  • DOM2:事件捕获阶段:捕获的是从document一直向下传播的目标元素,检查经过的节点是否绑定函数事件,有则执行
  • 事件委托 / 代理:
  • 利用事件冒泡,因为冒泡会上传到父节点,并且父节点可以通过事件对象获取到目标节点,所以在父节点设置监听函数统一处理。
  • 减少内存消耗,动态绑定,新增子节点不需要设置监听函数了
  • 事件捕获 / 冒泡:
  • 捕获:window--document--html--body--目标元素
  • 冒泡:当前元素--body--html--document--window
    【Interview】20201206 模拟
    可选参数useCapture,默认值为false,事件将在冒泡阶段中发生,如果为true 则事件将在捕获阶段中发生
  • 事件监听
    第一个参数是:事件的类型(如:“click”,“mousedown”);
    第二个参数是:事件触发后调用的函数。
    第二个参数是:布尔值 用于描述事件是冒泡还是捕获。true:表示捕获;false表示冒泡。(该参数是可选的)
element.addEventListener(event,function,useCapture);

原型和原型链

①所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
②所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
③所有引用类型__proto__属性指向它构造函数prototype

【Interview】20201206 模拟
【Interview】20201206 模拟

①一直往上层查找,直到到null还没有找到,则返回undefined
Object.prototype.__proto__ === null
③所有从原型或更高级原型中的得到、执行的方法,其中的this在执行时,指向当前这个触发事件执行的对象

静态方法 原型方法

    function Person(){
      this.name = '小明';
      // 实例方法
      this.getName = function(){
        console.log('他的名字叫 ',this.name);
      };
      // 内部方法
      const getSex = function(){
        console.log('性别是男的');
      }
    }
    // 静态方法
    Person.sayHi = function(){
      console.log('Hi!');
    }
    // 原型方法
    Person.prototype.sayBye = function(){
      console.log('Bye!');
    }
 
    const p = new Person();
 
    p.getName(); // 实例方法只能被实例调用,内部方法只能被类调用
    Person.sayHi(); // 静态方法只能被类调用
    p.sayBye(); // 原型方法只能被实例调用


class 创建对象 实现继承 instance super

class Point{}
class ColorPoint extends Point{}

子类必须在constructor方法中调用super方法,否则新建实例时会报错,因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法,如果不调用super方法,子类就得不到this对象

classPoint{
	constructor(x, y) {
		this.x = x;
		this.y = y;
	}
}
classColorPoint extends Point{
	constructor(x, y, color) {
		//this.color = color; // ReferenceError
		super(x, y);
		this.color = color; // 正确
	}
}

上面代码中,子类的constructor方法没有调用super之前,就使用this关键字,结果报错,而放在super方法之后就是正确的,正确的继承之后,我们就可以创建实例了

let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true

作用域

作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

作用域链

寻找变量,一层一层往上找。

闭包

闭包就是有权访问另一个函数作用域内变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量
外面的this是外面
但是里面是window

箭头函数的this

具体参考this 指向详细解析(箭头函数)

绑定函数的源码

  • bind

bind的特点:

  1. 接受调用传参和新建对象构造函数传参
  2. 如果是外部没有传入this就要新建一个this
  3. 和call接受的参数和实现的回调功能一样
  4. 返回的是一个新创建的原来传入的this克隆的对象
//函数的构造函数 : Function
//用es6解构rest的方式传参
Function.prototype.myBind = function(objThis,...params){
	//定义指向当前函数this的指针
	const thisTn = this;
	//因为最终返回的是一个函数,所以声明一个函数返回
	//用let表示块作用域
	let funcForBind = function(...secondParams){
		/*因为例如
		let sayClone = obj.say.bind(obj2,1,2,3);
		sayClone(4);
		这里还是可以进行传参,最终传的就是1,2,3,4,所以可以用解构	...secondParams
		*/
		//判断是不是新创建的对象 如果新创建的对象的话 this就是当前函数的this 不是新创建的话就是传进来的那个对象的上下文
		const isNew = this instanseof funcForBind;
		const thisArg = isNew ? this : objThis;
		//返回调用 并分别解构传入的参数params和创建对象传入的参数secondParams
		return thisFn.call(thisArg,...params,...secondParams);
	}
	//因为bind返回的是克隆的对象,所以还要把原型链进行克隆
	funForBind.prototype = Object.create(thisFn.prototype);
	return funcForBind;
}
  • call 和 apply
    之前的例子:
//给obj2增加一个obj的call的函数,然后用传入的参数进行调用返回最终值
obj.say.call(obj2,1,2,3);
Function.prototype.myCall = function(thisArg,...arr){
	if(thisArg == null || thisArg == undefined){
		thisArg = window;
	}
	//定义一个不重复的方法名称
	const specialMethod = Symbol('anything');
	//将这个不重复的方法Function的指针给thisArg的specialMethod方法
	thisArg[specialMethod] = this;
	//调用函数并结果返回
	let result = thisArg[specialMethod](...arr);
	//delete 新增的属性
	delete thisArg[specialMethod];
	return result;
}
obj.say.myCall(obj2,1,2,3);
Function.prototype.myApply = function(thisArg,arr){
	if(thisArg == null || thisArg == undefined){
		thisArg = window;
	}
	//定义一个不重复的方法
	const specialMethod = Symbol('anything');
	//将这个不重复的方法的指针给thisArg的specialMethod方法
	thisArg[specialMethod] = this;
	//调用函数并结果返回
	let result = thisArg[specialMethod](...arr);
	//delete 新增的属性
	delete thisArg[specialMethod];
	return result;
}
obj.say.myApply(obj2,[1,2,3]);

函数柯里化 递归

  • 函数柯里化 指的是 一种将使用多个参数的一个函数 转换成 一系列使用一个参数的函数的技术
  • 感觉像是给函数的解构
function curry(fn, args){
    //获取函数需要的参数长度
    let length = fn.length;
    args = args || [];
    return function(){
        let subArgs = args.slice(0);
        //拼接所有参数,不仅是curry的,还有fn的
        for(let i = 0; i < arguments.length; i++){
            subArgs.push(arguments[i]);
        }
        //判断参数的长度是否已经满足函数所需参数的长度
        if(subArgs.length >= length){
            //如果满足,执行函数
            return fn.apply(this, subArgs);
        }else{
            //如果不满足,递归返回柯里化的函数,等待参数的传入
            return curry.call(this, fn, subArgs);
        }
    };
}

//es6实现
function curry(fn, ...args){
    return fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);
}

GET POST区别

  • 请求

请求次数。
GET发送一次接受一次
POST发送多次接收多次(先发header再发body)

  • 参数

GET放在URL中,POST请求体中

  • 编码

GET在URL上只能ASCII,POST支持更多

  • 缓存

GET主动缓存,POST不行(除了流式传输)

  • 应用场景

GET搜索关键字,分页操作。POST注册。

ajax五个请求 回调 和 promise区别 手写

ajax

创建HTTP请求异步对象
设置回调函数
open方法建立连接
send发送数据
回调函数对响应状态进行处理

promise封装

创建promise对象
新建请求
配置请求头部
设置 状态监听函数resolve / 错误监听reject
设置响应数据类型
发送HTTP请求

状态码

缓存

  • 强缓存 Expires Cache-Control
    1.0 Expires 过期时间点
    1.1 Cache-Control 过期时间段
  • 协商缓存 Last-Modified ETag
    强缓存失效过后,给服务器发Tag,服务器来判断要不要,报304说明直接用协商缓存了
    性能上,Last-Modified优于ETag,Last-Modified记录的是时间点,而Etag需要根据文件的MD5算法生成对应的hash值。
    精度上,ETag优于Last-Modified。ETag按照内容给资源带上标识,能准确感知资源变化,Last-Modified在某些场景并不能准确感知变化,比如????
    编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
    Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。

session id cookie 手动保存到浏览器 每一次打开一个页面 比如存储了账号密码 浏览器自动提交cookie local

【Interview】20201206 模拟

  • cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递
    cookie数据还有路径(path)的概念,可以限制。cookie只属于某个路径下。
  • 存储大小限制也不同
    cookie数据不能超过4K,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如回话标识。
    webStorage虽然也有存储大小的限制,但是比cookie大得多,可以达到5M或更大
  • 数据的有效期不同
    sessionStorage:仅在当前的浏览器窗口关闭有效;
    localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
    cookie:只在设置的cookie过期时间之前一直有效,即使窗口和浏览器关闭
  • 作用域不同
    sessionStorage:不在不同的浏览器窗口都是共享,即使是同一个页面;
    localStorage:在所有同源窗口都是共享的;
    cookie:也是在所有同源窗口都是共享的

本文地址:https://blog.csdn.net/weixin_43698328/article/details/110759774