??拖了这么久,来整理去年秋招的JS篇了~
1. 数据类型
- 原始数据类型:Number、String、Boolean、Null、Undefined、Symbol
- 引用数据类型:Object、Array、Function
- 基本数据类型:Number,String,Boolean,Undefined,Null
2. null和undefined的区别
null == undefined;
null === undefined;
typeof null
typeof undefined
3. for in 和 for of 的区别
- for in遍历对象时,遍历顺序为:先遍历键名为数字的,按从小到大的顺序,再按照字符串出现的顺序遍历键名为字符串的;for of 不能遍历对象
- for in会遍历数组所有的可枚举属性,包括原型属性,而for of遍历的只是数组内的元素,而不包括数组的原型属性
- 在遍历数组时,for in遍历的是数组索引,而for of遍历的是数组元素值。
4. call、bind、apply的区别
- fn.call(obj,param1,param2)
严格模式下,第一个参数是谁,this就指向谁,如果不传参this就是undefined 非严格模式下,第一个参数是null/undefined,this指向window - fn.apply(obj,arr)
与call的区别在于传参方式 - fn.bind(obj,param1,param2)
- bind改变fn的this,但不会立即执行
- call改变fn的this,且会立即执行fn
5. 数组方法
- join();
- push()/pop();
- shift()/unshift();
- sort();
- reverse();
- concat();
- slice();
- splice();
- indexOf()/lastIndexOf();
- forEach();
- map();
- fliter();
- every();
- some();
6. map和foreach的区别
??forEach返回的是undefined,不可以链式调用,map返回一个新数组,原数组不会改变
7. 数组去重
- 方式一:set去重
- 方式二:双循环去重
var arr = [1, 5, 6, 0, 7, 3, 0, 5, 9,5,5];
function unique(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
for (var j = i + 1, len = arr.length; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--;
len--;
}
}
}
return arr;
}
console.log(unique(arr));
- 方式三:indexOf去重
var arr = [1, -5, -4, 0, -4, 7, 7, 3];
function unique(arr) {
var arr1 = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (arr1.indexOf(arr[i]) === -1) {
arr1.push(arr[i]);
}
}
return arr1;
}
console.log(unique(arr));
- 方式四:sort()去重
var arr = [5, 7, 1, 8, 1, 8, 3, 4, 9, 7];
function unique(arr) {
arr = arr.sort();
console.log(arr);
var arr1 = [arr[0]];
for (var i = 1, len = arr.length; i < len; i++) {
if (arr[i] !== arr[i - 1]) {
arr1.push(arr[i]);
}
}
return arr1;
}
console.log(unique(arr));
8. 深浅拷贝
- 概念
浅拷贝是地址引用,修改对象中的对象或者数组会影响原始对象。 深拷贝是内存拷贝,修改对象中的所有值不会影响原始对象。 - 代码
function clone(origin, target) {
var target = target || {};
for(var prop in origin) {
target[prop] = origin[prop];
}
return target;
}
function deepClone(origin, target) {
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]";
for(var prop in origin) {
if(origin.hasOwnProperty(prop)) {
if(origin[prop] !== "null" && typeof(origin[prop]) == 'object') {
if(toStr.call(origin[prop]) == arrStr) {
target[prop] = [];
}else {
target[prop] = {};
}
deepClone(origin[prop], target[prop]);
}else {
target[prop] = origin[prop];
}
}
}
return target;
}
9. 如何判断是一个数组
- 方式一:inatanceof运算符
??用于检验构造函数的prototype属性是否出现在对象的原型链中的任何位置,返回布尔值。 ?? prototype属性可以修改,因此并不是最初判断为true,就永远为true;当脚本拥有多个全局环境,比如说html中拥有多个iframe对象,则instanceof的验证结果和预期不符,因为iframe会产生新的全局环境,它会拥有自己的Array.prototype属性
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
const arr = new xArray();
console.log(arr instanceof xArray);
- 方式二:constructor 实例的构造函数属性constructor指向构造函数
- 方式三:object.prototype.toString.call 判断某个对象属于哪种内置类型
- 方式四:Array.isArray(arr) 用于确定传递的值是否为一个数组,返回布尔值
10. 作用域
- 作用域:负责收集并维护所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限,简单来说,作用域是代码的执行环境,其中定义了变量或函数有权访问的其他数据
- 作用域链:当一个块或函数嵌套在另一个块/函数中时,得到的嵌套结构被称为作用域链。在当前作用域中找不到某个变量的情况下,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量活着抵达最外层的作用域。
- 词法作用域:词法作用域就是定义在词法阶段的作用域,即,词法作用域是由写代码的过程中,将变量和块作用域写在哪里来决定的。
|