js部分知识点

面试必备

为什么要写这个?人生来到这里,我第一次经历到公司倒闭了!!!扯不扯?又要出去找活了,尴尬的一批

  1. 有时会出现好多小数位

    1
    2
    var a = .3 -.2;
    a == .1 //false
    • 因为计算机是二进制的,转换为十进制的小数相减的话就会失去准确性,因为.3-.2等于.0999999998。所以,以后计算价格之类的,一定要toFixed()一下。
  2. toString()方法,可以把数组转成字符串

    1
    2
    let arr = [1,2,3];
    arr.toString() //'1,2,3'
  3. 0/0的结果是NaN。

  4. 求余运算符的操作通常都是整数,但也适用于浮点数。比如,6.5%2.1结果是0.2。
  5. 隐式转换类型:
    1
    2
    2+null          //2  null会转换为0
    2+undefined //NaN undefined会转换为NAN

6.当+号运算符和字符串和数字一起使用时,需要考虑加法的结合性对运算顺序的影响。

1
2
3
1+2+'bind mice';    //"3 bind mice"
1+(2+'bind mice'); // "12 bind mice"
//这些细节要特别注意

  1. in 运算符

    好屌的in运算符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //对象
    var porint = { name:'张三',age:20}
    "name" in porint //true;
    "age" in porint //true;
    "sex" in porint //false;
    "toString" in porint //true

    /* 对象拥有的属性和内置对象属性,以及原型上的属性都可以用in运算符去判断。 */

    //数组:
    var arr = [7,8,9];
    "0" in arr //true
    1 in arr //true
    2 in arr //true
    7 in arr //false

    /* 只能判断索引,感觉用处不大 */

比in更屌的hasOwnProperty(),可以检测对象属性是自有属性还是继承属性

1
2
3
4
5

var o = {x:1}
o.hasOwnProperty("x") //true o有一个自有属性x
o.hasOwnProperty('y') //false o不存在属性y
o.hasOwnProperty('toString') //false toString是继承属性

史上最屌propertyIsEnumerable() 只有检测到是自有属性且这个属性的可枚举性为true时才返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//先补充一个通过原型继承创建一个新对象的函数
function inherit(p){
if(p==null) throw TypeError() //p是一个对象,但不能是null
if(Object.create) //如果Object.create()存在
return Object.create(p) //直接使用它
var t = typeOf p;
if(t !== 'object' || t !== 'function')
throw TypeError()
function f(){}; //定义一个空的构造函数
f.prototype = p; //将其原型属性设置为p
return new f(); //使用f()创建p的继承对象
}
//--------------
var o = inherit({y:2});
o.x = 1;
o.propertyIsEumerable('x') //true o有一个可枚举的自有属性x
o.propertyIsEumerable('y') //false y是继承来的。
Object.prototype.propertyIsEumerable('toString') //false 不可枚举
o.propertyIsEumerable('toString') //fasle 不可枚举

8、对象的get和set

可以利用get设置一些规则,每次调用都会随规则变化,以随机数为例 每次产生的随机数都在0-255之间。

1
2
3
4
5
6
7
8
9
10
11
var random = {
get octet() {
return Math.floor(Math.random()*256)
}
}

console.log(random.octet) //{} 空对象
random.octet //每次调用都会产生一个
random.octet //0-255之间的随机数

//有点意思哈,对象的属性值可以一直变。

9、对象属性的设置

1
2
3
4
5
6
7
8
9
10
11
12
13

Object.getOwnPropertyDescriptor({x:1},"x");
//{value:1,writable:true,enumerable:true,configurable:true}
//value:设置值
//writable:可读写
//enumerable:可枚举
//configurable:可配置
//那么这些属性有什么用呢
var o = {x:2};
Object.defineProperty(o,"x",{value:1,writable:false,enumerable:false,configurable:true})
o.x = 3 ;
console.log(o) // {x:1} 因为只读了,且重新赋值了。
Object.keys(o) //[] 因为不可枚举

filter使用总结

判断数组中是否存在某值

1
2
3
4
let newArr = [{type:1,id:1,name:'aa'},{type:2,id:2,name:'ab'},{type:1,id:3,name'cc'}]

newArr.filter(item => item.type == 1)
//得到:[{type:1,id:1,name:'aa'},{type:1,id:3,name'cc'}]

去掉数组中空字符串,undefined,null

1
2
3
4
5
6
7
let arr = ['1','2',undefined, null,'']
let newArr = arr.filter(item => item)
//得到: newArr 是 ['1','2']

let a = [{name:'12'},{name:''}]
let b = a.filter(item => item.name)
//得到: b 是 [{name:'12'}]

去掉不符合项

1
2
3
var arr = [20,30,50, 96,50]
var newArr = arr.filter(item => item>40)
// [50,96,50]

数组去重

1
2
3
var arr = [1, 2, 2, 3, 4, 5, 5, 6, 7, 7,8,8,0,8,6,3,4,56,2];
var arr2 = arr.filter((x, index,self)=>self.indexOf(x)===index)
console.log(arr2); //[1, 2, 3, 4, 5, 6, 7, 8, 0, 56]

箭头函数和普通函数的区别

1、普通函数会改变this的指向。箭头函数不会。

2、普通函数入参不固定时可以用的argruments箭头函数没有。

3、箭头函数不能当作构造函数,也就是说,不能使用new命令,否则会报错。

4、箭头函数没有原型属性。

5、箭头函数不可以使用yield命令,因此箭头函数不能用作Generator函数。

6、变量提升:由于js的内存机制,function的级别最高,而用箭头函数定义函数的时候,需要var(let、const)关键字,而var所定义的变量不能得到变量提升。故箭头函数一定要定义于调用之前。

this的六大指向

1、普通函数中,this指向其函数的直接调用者;

2、箭头函数中,this指向其定义环境,任何方法都改变不了其指向,如call( )、bind()等;

3、构造函数中,如果不使用new,则this指向window,如果使用new创建了一个实例,则this指向该实例。

4、window内置函数中,如setInterval,setTimeout等,其内部的this指向Window。

5、匿名函数的this指向Window。

6、apply()、call()、bind()可以改变this的指向

node和es6的事件处理机制

node同步。es6异步

浅拷贝和深拷贝

浅拷贝就只是复制对象的引用 (直接等于就好了)

深拷贝是都复制,且元对象改变,复制的不会跟着改变

一维深拷贝:

  1. 巧用slice() 和 concat()
    这两种方法,只能实现一维数组的深拷贝(多维数组无效
  2. for循环遍历 这个方式很好理解,就是一一赋值。多维数组的深拷贝也可以用嵌套for循环实现。
  3. JSON.stringify()/JSON.parse()。这种方式相当于是把原数组转成字符串类型,之后再解析。
    这种方法的缺陷在于:无法复制函数;丢失原型链(对象就丢失所属的类)。JSON转串的方式,对于多维数组也有效:
  4. jQuery方式。$.extend([deep], target, object1 [, objectN ]) 该方法可以运用于数组,也可以运用于对象。
  5. 递归方法。使用递归函数实现多维数组 or 对象的深度拷贝。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // 定义一个深拷贝函数  接收目标target参数
    function deepClone(target) {
    // 定义一个变量
    let result;
    // 如果当前需要深拷贝的是一个对象的话
    if (typeof target === 'object') {
    // 如果是一个数组的话
    if (Array.isArray(target)) {
    result = []; // 将result赋值为一个数组,并且执行遍历
    for (let i in target) {
    // 递归克隆数组中的每一项
    result.push(deepClone(target[i]))
    }
    // 判断如果当前的值是null的话;直接赋值为null
    } else if(target===null) {
    result = null;
    // 判断如果当前的值是一个RegExp对象的话,直接赋值
    } else if(target.constructor===RegExp){
    result = target;
    }else {
    // 否则是普通对象,直接for in循环,递归赋值对象的所有值
    result = {};
    for (let i in target) {
    result[i] = deepClone(target[i]);
    }
    }
    // 如果不是对象的话,就是基本数据类型,那么直接赋值
    } else {
    result = target;
    }
    // 返回最终结果
    return result;
    }
  6. Object.assign (也是只能一层,多层无效,这里还有object.keys()和object.values())

new操作符都干了什么

如下代码,通过构造函数创建实例对象:

1
2
3
function Func(){
}
let func= new Func();

new 共经过了4个阶段:

  1. 创建一个空对象 let obj = new Object();
  2. 链接到原型。把 obj 的proto 指向构造函数Func的原型对象 prototype,此时便建立了 obj 对象的原型链:
    obj->Func.prototype->Object.prototype->null。

    1
    obj.__proto__ = Func.prototype;
  3. 绑定this值(让Func中的this指向obj,并执行Func的函数体。) let result = Func.call(obj);

  4. 返回新对象。 (判断Func的返回值类型:
    如果无返回值 或者 返回一个非对象值,则将 obj 作为新对象返回;否则会将 result 作为新对象返回。
    1
    2
    3
    4
    5
    6
    if (typeof(result) == "object"){
    func=result;
    }
    else{
    func=obj;
    }

浏览器缓存

强缓存和协商缓存

总结:

  1. 看看是否命中强缓存,如果命中,就直接使用缓存了。
  2. 如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存。
  3. 如果命中协商缓存,服务器会返回 304 告诉浏览器使用本地缓存。
  4. 否则,返回最新的资源。

优先级:

  1. 先在内存中查找,如果有,直接加载。
  2. 如果内存中不存在,则在硬盘中查找,如果有直接加载。
  3. 如果硬盘中也没有,那么就进行网络请求。
  4. 请求获取的资源缓存到硬盘和内存。

浏览器再向服务器请求资源时,首先判断是否命中强缓存,再判断是否命中协商缓存!

浏览器缓存的优点

  1. 减少了冗余的数据传输
  2. 减少了服务器的负担,大大提升了网站的性能
  3. 加快了客户端加载网页的速度

强缓存

浏览器在加载资源时,会先根据本地缓存资源的 header 中的信息判断是否命中强缓存,如果命中则直接使用缓存中的资源不会再向服务器发送请求。

这里的 header 中的信息指的是 expires 和 cahe-control.

Expires

该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。

Cache-Control

Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600,代表着资源的有效期是 3600 秒。cache-control 除了该字段外,还有下面几个比较常用的设置值:

  • no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。
  • no-store:禁止使用缓存,每一次都要重新请求数据。
  • public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。
  • private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
  • Cache-Control 与 Expires 可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高

协商缓存

当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存。

这里的 header 中的信息指的是 Last-Modify/If-Modify-Since 和 ETag/If-None-Match.

Last-Modify/If-Modify-Since

浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

如果命中缓存,则返回 304,并且不会返回资源内容,并且不会返回 Last-Modify。

缺点:

短时间内资源发生了改变,Last-Modified 并不会发生变化。

周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。

ETag/If-None-Match

与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上送的 If-None-Match 值来判断是否命中缓存。

与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

垃圾回收机制

JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存

标记清除(mark and sweep)、引用计数(reference counting)。

  1. 标记清除(mark and sweep)
    大部分浏览器以此方式进行垃圾回收,当变量进入执行环境(函数中声明变量)的时候,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”,在离开环境之后还有的变量则是需要被删除的变量。标记方式不定,可以是某个特殊位的反转或维护一个列表等。

垃圾收集器给内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记。在此之后再被加上的标记的变量即为需要回收的变量,因为环境中的变量已经无法访问到这些变量。

  1. 引用计数(reference counting)
    这种方式常常会引起内存泄漏,低版本的IE使用这种方式。机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,当这个变量指向其他一个时该值的引用次数便减一。当该值引用次数为0时就会被回收

数组去重,数组(字符串)找出现最多次数的字符及个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   Array.prototype.removal=function(){
var arr=[];
for(var i=0;i<this.length;i++){
if(arr.indexOf(this[i]) == -1){
arr.push(this[i]);
}
}
return arr;
}
function arrStrNum(str){
var arr;
if(typeof str === 'string'){
arr = str.split('');
}else{
arr = str;
}
var json = {};
for(var i = 0; i< arr.length;i++){
if(!json[arr[i]]){
json[arr[i]] = 1;
}else{
json[arr[i]]++;
}
}
var iMax = 0;
var iIndex = [];
for(var k in json){
if(json[k]>iMax){
iMax = json[k];
}
}
for(var k in json){
if(json[k] == iMax){
iIndex.push(k);
}
}
return {maxNumarr:iIndex,maxNum:iMax,removalArr:arr.removal()}
// alert('出现次数最多的有:'+ iIndex.length +'个字符')
// iIndex.map(function(item,k){
// alert('出现次数最多的分别是:'+item+'出现了:'+iMax+'次')
// })
}
var str = 'asdfssaaasasasasaabbbbbbbbb';
var o = arrStrNum(str)
alert('出现次数最多的有:'+ o.maxNumarr.length +'个字符')
o.maxNumarr.map(function(item,k){
alert('出现次数最多的分别是:'+item+'出现了:'+o.maxNum+'次')
})
alert('去重后的数组为:'+o.removalArr)

es6

常用的有哪些?

  1. let const
  2. 解构赋值
1
2
3
4
5
6
7
8
9
10
11
let [a,b,c] = [1,2,3] ;

let {msg,code,data} = res;

//设置默认值:
//注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员//严格等于undefined,默认值才会生效。
let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null
  1. 对象的浅克隆和深克隆
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//只能克隆原始对象自身的值
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

//深克隆 保持继承链

function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
  1. 获取对象的键名和键值
1
2
3
4
5
6

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
Object.values(obj)
// ["bar", 42]
  1. 数组的from,of方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

let arr3 = Array.from(arrayLike,x => x + 'cmd'); // ['acmd', 'bcmd', 'ccmd']

//of

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]

如何处理高并发

  1. 减少访问api或者不访问(合并请求,尽量用静态页面)
  2. 部署到多个服务器上
  3. 对于高访问量接口采用分时请求(取100毫秒到2秒的随机数,然后发请求,这样请求就平均分到2秒时间内,一定程度上可以减少并发量)
  4. 控制大文件的下载(小于2M),实在不能控制大小就把大文件放在另一台服务器上。
  5. 用户限流,在某段时间内只允许用户提交一次
  6. 压缩合并html,css,js,图片使用精灵图或base64。
  7. 代码复用,简洁。闭包使用后赋值为null,避免垃圾回收过多(避免全局变量过多)
  8. 对于使用定时器的,离开的时候销毁定时器。
  9. 缓存技术

浏览器输入地址后的步骤

1.浏览器查看缓存,如果有缓存且新鲜,转到转码步骤。如果无缓存,发起新请求,如果有缓存但已失效,请求服务端验证。

2.浏览器解析协议,主机,端口,path, 组装一个http请求报文

https协议是对http用ssl协议(secure socket layer)加密,因为http报文是明文,有泄露的风险

3.获取主机ip地址,向目标ip地址,端口建立TCP连接,

4.TCP连接后发送HTTP请求(请求行put,post等,请求头,请求正文(如JSON数据等))

5.服务器接受请求并解析,转发到处理程序

6.检查http请求头是否包含缓存验证信息

7.处理程序读取完整请求,准备HTTP响应

8.服务器将响应报文(状态码,响应报头,响应报文(HTML,CSS,JS,图片等))通过TCP连接返回给浏览器

前端安全性

XSS全称跨站脚本攻击

主要危害
1、盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号
  2、控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力
  3、盗窃企业重要的具有商业价值的资料
  4、非法转账
  5、强制发送电子邮件
  6、网站挂马
  7、控制受害者机器向其它网站发起攻击
攻击方式

  • 反射型
    反射型XSS,也叫非持久型XSS,是指发生请求时,XSS代码出现在请求URL中,作为参数提交到服务器,服务器解析并响应。响应结果中包含XSS代码,最后浏览器解析并执行。从概念上可以看出,反射型XSS代码是首先出现在URL中的,然后需要服务端解析,最后需要浏览器解析之后XSS代码才能够攻击。
  • 存储型
    存储型XSS,也叫持久型XSS,主要是将XSS代码发送到服务器(不管是数据库、内存还是文件系统等。),然后在下次请求页面的时候就不用带上XSS代码了。最典型的就是留言板XSS。用户提交了一条包含XSS代码的留言到数据库。当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。浏览器发现有XSS代码,就当做正常的HTML和JS解析执行。XSS攻击就发生了。常用于窃取用户信息,如cookie,token,账号密码等

解决办法:
1、入参字符过滤
  在源头控制,把输入的一些不合法的东西都过滤掉,从而保证安全性。如移除用户提交的的DOM属性如onerror,移除用户上传的Style节点,

文章目录
  1. 1. 面试必备
    1. 1.1. 为什么要写这个?人生来到这里,我第一次经历到公司倒闭了!!!扯不扯?又要出去找活了,尴尬的一批
    2. 1.2. filter使用总结
  2. 2. 箭头函数和普通函数的区别
  3. 3. this的六大指向
  4. 4. node和es6的事件处理机制
  5. 5. 浅拷贝和深拷贝
    1. 5.1. new操作符都干了什么
  6. 6. 浏览器缓存
    1. 6.1. 强缓存
    2. 6.2. 协商缓存
  7. 7. 垃圾回收机制
  8. 8. 数组去重,数组(字符串)找出现最多次数的字符及个数
  9. 9. es6
    1. 9.1. 常用的有哪些?
    2. 9.2. 如何处理高并发
  10. 10. 浏览器输入地址后的步骤
  11. 11. 前端安全性
    1. 11.1. XSS全称跨站脚本攻击
|