概述
JS
闭包
闭包就是能够读取其他函数内部变量的函数,
下面是例子
function fn(n,o) {
console.log(o)
return {
fn:function (m) {
return fn(m,n)
}
}
}
const obj = fn(0); obj.fn(1); obj.fn(2);
const obj1 = fn(0).fn(1).fn(4).fn(3);
输入一个参数,打印结果
关于闭包
请你谈谈 Cookie 的优缺点
优点:极高的拓展性和可用性
1)数据持久性
2)不需要任何服务器资源 Cookie 存储在客户端并在发送后由服务器读取。
3) 可配置到期规则。 控制 cookie 的生命期,使之不会永远有效。偷盗者很可 能拿到一个过期的 cookie 。
4) 简单性。 基于文本的轻量结构。
5) 通过良好的编程,控制保存在 cookie 中的 session 对象的大小。
6) 通过加密和安全传输技术( SSL ),减少 cookie 被破解的可能性。
7) 只在 cookie 中存放不敏感数据,即使被盗也不会有重大损失。
缺点: 1) Cookie 数量和长度的限制 。
数量:每个域的 cookie 总数有限。
a) IE6 或更低版本最多 20 个 cookie
b) IE7 和之后的版本最后可以有 50 个 cookie
c) Firefox 最多 50 个 cookie
d) chrome 和 Safari 没有做硬性限制
长度:每个 cookie 长度不超过 4KB ( 4096B ),否则会被截掉。
2) 潜在的安全风险 。 Cookie 可能被拦截、篡改。如果 cookie 被拦截,就有可能取得所有的 session 信息。
3) 用户配置为禁用 。有些用户禁用了浏览器或客户端设备接受 cookie 的能力,因此限制了这一功能。
4) 有些状态不可能保存在客户端 。例如,为了防止重复提交表单,我们需要在 服务器端保存一个计数器。
如果我们把这个计数器保存在客户端,那么它起不到任何作用。
以下代码执行后,控制台的输出是
简单的
var a = 10;
function a(){}
console.log(typeof a)
复杂的
console.log(v1);
var v1 = 100;
function foo() {
console.log(v1);
var v1 = 200;
console.log(v1);
}
foo();
console.log(v1);
变量提升
Array.prototype.slice.call(arr,2)方法的作用是
利用 Array 原型上的 slice 方法,使用 call 函数的第一个参数,让这个方法中 的 this 指向 arr,并传递参数 2,实际上等于 arr.slice(2),即从下标为 2 开 始截取到末尾
call ,apply ,bind 改变this 指向
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
call 与 apply 的相同点:
方法的含义是一样的,即方法功能是一样的;
第一个参数的作用是一样的;
call 与 apply 的不同点:两者传入的列表形式不一样
call可以传入多个参数;
apply只能传入两个参数,所以其第二个参数往往是作为数组形式传入
实现原理
给目标对象创建一个属性,将要调用的方法绑定到这个属性上
直接运行刚刚创建的属性
删除这个属性
这样就间接绑定了this的指向,并实现了call
js 继承怎么实现
原型继承 prototype,构造函数继承
j s继承
Function.prototype.mycall=function(con){ //给Function的原型对象上加上mycall方法
con.fun = this; //this即为要绑定的方法
console.log(this) //function
con.fun();
delete con.fun;
}
let obj1 = {
name:"helloworld"
}
function fn(){
console.log(this.name);
}
fn.call(obj1); //helloworld
fn.mycall(obj1); //helloworld
遍历A节点的父节点下的所有子节点
vue 玩多了。js dom操作不记得了
j s dom
<script>
var b=document.getElementById("a").parentNode.children;
console.log(b)
</script>
递归的方式写1到100求和
vue在实现双向绑定进行数据检验的时候用的也是递归,
递归函数就是在函数体内调用本函数;
递归函数的使用要注意函数终止条件避免死循环;
function add(num1,num2){
var num = num1+num2;
if(num2+1>100){
return num;
} else {
return add(num,num2+1)
}
}
var sum =add(1,2);
页面渲染html的过程?
浏览器渲染页面的一般过程:
1.浏览器解析html源码,然后创建一个 DOM树。并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文本节点。DOM树的根节点就是 documentElement,对应的是html标签。
2.浏览器解析CSS代码,计算出最终的样式数据。构建CSSOM树。对CSS代码中非法的语法它会直接忽略掉。解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置 < 用户设置 < 外链样式 < 内联样式 < html中的style。
3.DOM Tree + CSSOM --> 渲染树(rendering tree)。渲染树和DOM树有点像,但是是有区别的。
DOM树完全和html标签一一对应,但是渲染树会忽略掉不需要渲染的元素,比如head、display:none的元素等。而且一大段文本中的每一个行在渲染树中都是独立的一个节点。渲染树中的每一个节点都存储有对应的css属性。
4.一旦渲染树创建好了,浏览器就可以根据渲染树直接把页面绘制到屏幕上。
以上四个步骤并不是一次性顺序完成的。如果DOM或者CSSOM被修改,以上过程会被重复执行。实际上,CSS和JavaScript往往会多次修改DOM或者CSSOM。
如何中断ajax请求
一种是设置超时时间让ajax自动断开,
另一种是手动停止ajax请求,其核心是调用XML对象的abort方法,ajax.abort()
说一下宏任务和微任务?
宏任务:当前调用栈中执行的任务称为宏任务。(主代码快,定时器等等)。
微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务为微任务。
(可以理解为回调事件,promise.then,proness.nextTick等等)。
宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。
说一下继承的几种方式及优缺点?
借用构造函数继承,使用call或apply方法,将父对象的构造函数绑定在子对象上
原型继承,将子对象的prototype指向父对象的一个实例
组合继承
原型链继承的缺点
字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
借用构造函数(类式继承)
借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。
组合式继承
组合式继承是比较常用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。
说一下闭包?
闭包的实质是因为函数嵌套而形成的作用域链
闭包的定义即:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包
数组去重
两层循环法
利用语法自身键不可重复性
js
var arr=['12','32','89','12','12','78','12','32'];
// 最简单数组去重法
function unique1(array){
var n = []; //一个新的临时数组
for(var i = 0; i < array.length; i++){ //遍历当前数组
if (n.indexOf(array[i]) == -1)
n.push(array[i]);
}
return n;
}
arr=unique1(arr);
// 速度最快, 占空间最多(空间换时间)
function unique2(array){
var n = {}, r = [], type;
for (var i = 0; i < array.length; i++) {
type = typeof array[i];
if (!n[array[i]]) {
n[array[i]] = [type];
r.push(array[i]);
} else if (n[array[i]].indexOf(type) < 0) {
n[array[i]].push(type);
r.push(array[i]);
}
}
return r;
}
//数组下标判断法
function unique3(array){
var n = [array[0]]; //结果数组
for(var i = 1; i < array.length; i++) { //从第二项开始遍历
//indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
if (array.indexOf(array[i]) == i) {
n.push(array[i]);
}
}
return n;
}
es6
es6方法数组去重
arr=[...new Set(arr)];
es6方法数组去重,第二种方法
function dedupe(array) {
return Array.from(new Set(array)); //Array.from()能把set结构转换为数组
}
数组去重
get、post的区别
1.get传参方式是通过地址栏URL传递,是可以直接看到get传递的参数,
post传参方式参数URL不可见,get把请求的数据在URL后通过?连接,通过&进行参数分割。
psot将参数存放在HTTP的包体内
2.get传递数据是通过URL进行传递,对传递的数据长度是受到URL大小的限制,URL最大长度是2048个字符。
post没有长度限制
3.get后退不会有影响,post后退会重新进行提交
4.get请求可以被缓存,post不可以被缓存
5.get请求只URL编码,post支持多种编码方式
6.get请求的记录会留在历史记录中,post请求不会留在历史记录
7.get只支持ASCII字符,post没有字符类型限制
你所知道的http的响应码及含义
1xx(临时响应)
100: 请求者应当继续提出请求。
101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备进行切换。
2xx(成功)
200:正确的请求返回正确的结果
201:表示资源被正确的创建。比如说,我们 POST 用户名、密码正确创建了一个用户就可以返回 201。
202:请求是正确的,但是结果正在处理中,这时候客户端可以通过轮询等机制继续请求。
3xx(已重定向)
300:请求成功,但结果有多种选择。
301:请求成功,但是资源被永久转移。
303:使用 GET 来访问新的地址来获取资源。
304:请求的资源并没有被修改过
4xx(请求错误)
400:请求出现错误,比如请求头不对等。
401:没有提供认证信息。请求的时候没有带上 Token 等。
402:为以后需要所保留的状态码。
403:请求的资源不允许访问。就是说没有权限。
404:请求的内容不存在。
5xx(服务器错误)
500:服务器错误。
501:请求还没有被实现
数据转换
有以下数据结构
const data = [{
key: "name",
value:"华睿投资"
}, {
key: "age",
value: 11
},
{
key: "from",
value:"浦口"
}]
实现一个转换函数 processin,根据对应的 key、value 生成以下对象,要
ES6 的新特性,尽可能的少去声明变量,减少副作用。
对象:
{
name:"华睿投资"
age: 11,
from: "浦口"
}
function processMW(data) {
return data.reduce((prev, cur) => {
prev[cur.key] = cur.value;
return prev;
}, {})
}
arr.reduce(function(prev,cur,index,arr){
...
}, init);
// arr 原数组
// prev 初始值
// cur 表示当前正在处理的数组元素;
// index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
reduce用法
简单说一下浏览器本地存储是怎样的
总的来说,浏览器存储分为以下几种:
1、Cookie 存储,明文,大小限制 4k 等
2、localStorage,持久化存储方式之一,不用在两端之间传输,且限制大小为 10M
3、sessionStorage,会话级存储方式,浏览器关闭立即数据丢失
4、indexDb,浏览器端的数据库
indexDb介绍
对象的拷贝
数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol (es6引入的一种类型) )和引用数据类型(Object、Array、Function)。
基本数据类型特点:直接存储在栈中;
引用数据类型:它真实的数据是存储在堆内存中,栈中存储的只是指针,指向在堆中的实体地址。
二、浅拷贝、深拷贝
深浅拷贝只是针对Array与Object这样的引用数据类型。简单来说,浅拷贝只是拷贝了它在栈中存储的指针,它们指向的都是同一个堆内存地址,所以浅拷贝在某些情况会造成改变数据后导致别的另一份数据也同步被改变的情况;而深拷贝是直接将堆内存中存储的数据直接复制一份,不会有浅拷贝互相影响的问题。
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
浅拷贝: 以赋值的形式拷贝引用对象,仍指向同一个地址,修改时原对象也会受 到影响
Object.assign
展开运算符(…)
深拷贝: 完全拷贝一个新对象,修改时原对象不再受到任何影响
JSON.parse(JSON.stringify(obj)): 性能最快 具有循环引用的对象时,报错 当值为函数、undefined、或 symbol 时,无法拷贝
JSON.parse(JSON.stringify(obj)): 可以实现对象或数组的深拷贝,但是不能处理函数,函数经过这样处理后会变成null
递归进行逐一赋值
new 运算符的执行过程
新生成一个对象
链接到原型: obj.__proto__ = Con.prototype // con 为对象元素
绑定 this. call(obj)
返回新对象(如果构造函数有自己 retrun 时,则返回该值)
// new操作符实现原理:
function news(func) {
var target = {};//生成新对象
target.__proto__ = func.prototype;//实例的__proto__指向原型,构造函数的prototype也指向原型(链接到原型)
var res = func.call(target);//把函数的this绑定在了新生成的对象中
if (typeof (res) == "object" || typeof (res) == "function") {
return res;//如果传入的函数(构造函数)有自己的返回值,则返回该值
}
return target;//如果如果传入的函数(构造函数)没有自己的返回值,则返回新对象
}
new
函数执行改变 this
由于 JS 的设计原理: 在函数中,可以引用运行环境中的变量。因此就需要一个 机制来让我们可以在函数体内部获取当前的运行环境,这便是 this。
因此要明白 this 指向,其实就是要搞清楚 函数的运行环境,说人话就是,谁 调用了函数。例如: obj.fn(),便是 obj 调用了函数,
既函数中的 this === obj fn(),这里可以看成 window.fn(),因此 this === window
但这种机制并不完全能满足我们的业务需求,因此提供了三种方式可以手动修改 this 的指向:
call: fn.call(target, 1, 2)
apply: fn.apply(target, [1, 2])
bind: fn.bind(target)(1,2)
// 一般情况下 this指向最后调用的对象 ,箭头函数指向定义所在的对象
s2 = 1;
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => { this.s1++;}, 1000);
// 普通函数
// let _this =this
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2,s2), 3100);
babel 编译原理
babylon 将 ES6/ES7 代码解析成 AST babel-traverse 对 AST 进行遍历转译,得到新的 AST 新 AST 通过 babel-generator 转换成 ES5
关于AST
AST文档
如何理解前端模块化
前端模块化就是复杂的文件编程一个一个独立的模块,比如 js 文件等等,分成 独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相 互依赖的问题,所以有了 commonJS 规范,AMD,CMD 规范等等,以及用于 js 打 包(编译等处理)的工具 webpack
对象深度克隆的简单实现
function deepClone(obj){
var newObj= obj instanceof Array ? []:{};
for(var item in obj){ var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];
newObj[item] = temple;
}
return newObj;
}
将原生的 ajax 封装成 promise
var myNewAjax=function(url){
return new Promise(function(resolve,reject){
//创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
/*请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法
open(method,url,async) methhod 方式 get/post url ,地址 async 同步还是异步 false true
*/
xhr.open('get',url);
xhr.send(data);
xhr.onreadystatechange=function(){
if(xhr.status==200&&readyState==4){
// responseText获得字符串形式的响应数据 responseXML获得 XML 形式的响应数据
var json=JSON.parse(xhr.responseText);
resolve(json)
}else if(xhr.readyState==4&&xhr.status!=200)
{ reject('error'); }
}
})
}
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
= =和===、以及 Object.is 的区别
object.is
主要存在:强制转换成 number,null= =undefined
= =:自动转换数据类型,
= = =: NaN不等于自身,以及+0等于-0。
es6新的方法Object.is来比较两个值严格相等,它与严格比较运算符(===)基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
setTimeout、setInterval 和 requestAnimationFrame 之间的区别
与 setTimeout 和 setInterval 不同,requestAnimationFrame 不需要设置时间 间隔, 大多数电脑显示器的刷新频率是 60Hz,大概相当于每秒钟重绘 60 次。大多数浏 览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频 率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是 1000ms/60,约 等于 16.6ms。 RAF 采用的是系统时间间隔,不会因为前面的任务,不会影响 RAF,但是如果前 面的任务多的话,会响应 setTimeout 和 setInterval 真正运行时的时间间隔。
特点:
(1)requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次 重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
(2)在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回 流,这当然就意味着更少的 CPU、GPU 和内存使用量
(3)requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览 器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停, 有效节省了 CPU 开销。
将原生的 ajax 封装成 promise
var myNewAjax=function(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send(data);
xhr.onreadystatechange=function(){ if(xhr.status==200&&readyState==4){
var json=JSON.parse(xhr.responseText);
resolve(json)
}else if(xhr.readyState==4&&xhr.status!=200){ reject('error'); }
}
})
}
js 监听对象属性的改变
ES5 中可以通过 Object.defineProperty
Proxy
有了解过事件模型吗,DOM0 级和 DOM2 级有什么区 别,DOM 的分级是什么?
事件捕获阶段
处于目标阶段
事件冒泡阶段
简单讲一讲 ES6 的一些新特性
ES6 在变量的声明和定义方面增加了 let、const 声明变量,有局部变量的概念, 赋值中有比较吸引人的结构赋值,同时 ES6 对字符串、 数组、正则、对象、函 数等拓展了一些方法,如字符串方面的模板字符串、函数方面的默认参数、对象 方面属性的简洁表达方式,ES6 也 引入了新的数据类型 symbol,新的数据结构 set 和 map,symbol 可以通过 typeof 检测出来,为解决异步回调问题,引入了 promise 和 generator,还有最为吸引人了实现 Class 和模块,通过 Class 可以 更好的面向对象编程,使用模块加载方便模块化编程,当然考虑到 浏览器兼容 性,我们在实际开发中需要使用 babel 进行编译 重要的特性: 块级作用域:ES5 只有全局作用域和函数作用域,块级作用域的好处是不再需要 立即执行的函数表达式,循环体中的闭包不再有问题 rest 参数:用于获取函数的多余参数,这样就不需要使用 arguments 对象了, promise:一种异步编程的解决方案,比传统的解决方案回调函数和事件更合理强 大模块化:其模块功能主要有两个命令构成,export 和 import,export 命令用于 规定模块的对外接口,import 命令用于输入其他模块提供的功能
Ajax 使用
所谓异步,就是向服务器发送请求的时候,我们不必等待结果,而是可以同时做 其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是 不会发生整页刷新的,提高了用户体验。
创建 Ajax 的过程:
- 创建 XMLHttpRequest 对象(异步调用对象) var xhr = new XMLHttpRequest();
- 创建新的 Http 请求(方法、URL、是否异步) xhr.open(‘get’,’example.php’,false); 3) 设置响应 HTTP 请求状态变化的函数。 onreadystatechange事件中readyState属性等于4。响应的HTTP状态为200(OK) 或者 304(Not Modified)。
- 发送 http 请求 xhr.send(data);
- 获取异步调用返回的数据
注意: - 页面初次加载时,尽量在 web 服务器一次性输出所有相关的数据,只在页面 加载完成之后,用户进行操作时采用 ajax 进行交互。
- 同步 ajax 在 IE 上会产生页面假死的问题。所以建议采用异步 ajax。
- 尽量减少 ajax 请求次数
- ajax 安全问题,对于敏感数据在服务器端处理,避免在客户端处理过滤。对 于关键业务逻辑代码也必须放在服务器端处理。
map
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
var numbers = [4, 9, 16, 25];
function myFunction() {
x = document.getElementById("demo")
x.innerHTML = numbers.map(Math.sqrt);
}
2,3,4,5
map 对象
Map是一组键值对的结构,具有极快的查找速度。
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉
最后
以上就是感动毛衣为你收集整理的js 更新中总结中的全部内容,希望文章能够帮你解决js 更新中总结中所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复