js 编程常用语法 笔试、面试参考

这是一篇合作博文,感谢在原来文档的基础上添加了一些不是特别重要的内容@X·Y·C-NiFox同学。

一、基本数据操作

1、数值取整

Math.ceil(v);    //向上整除 4/3=2;
Math.floor(v);   //向下整除 4/3=1;
Math.round(v);   //四舍五入     
Math.abs(v);     //绝对值
num.toFixed(2);  //四舍五入2位

2、整数、浮点数数值转换

parseInt(v);         //丢弃小数部分,保留整数部分
parseFloat("2.333"); //得到一个字符串的浮点数形式

3、常量——最大值、最小值

//最大值
Number.MAX_VALUE;        //1.7976931348623157e+308
Number.MAX_SAFE_INTEGER; //9007199254740991
Infinity;                //Infinity

//最小值
Number.MIN_VALUE;        //5e-324
Number.MIN_SAFE_INTEGER; //-9007199254740991

4、大数操作(BigInt)

将数据类型转化为BigInt,可以进行大数加减乘除,除一元加号(+)运算符外,所有算术运算符都可用于BigInt,在输出的时候需要去除最后的'n'。

var a = BigInt(1);
for(var i = BigInt(1); i < 1000; i++){
    a = a*i;
}

二、数组

2.1 增删改查

2.2.1 增

  • push——尾增(返回新数组长度)
  • unshift——首增(返回新数组长度)
  • splice(返回空数组)
  • concat(用于合并两个或多个数组,返回新构建的数组,不影响原数组)
// 增-splice(开始位置, 要增加的元素数量, 要插入的元素) 返回空数组
let colors = ["red", "green", "blue"];
let removed = colors.splice(1, 0, "yellow", "orange")
console.log(colors) // [ 'red', 'yellow', 'orange', 'green', 'blue' ]
console.log(removed) // []

// 增-concat 返回新构建的数组
let colors1 = ['red', 'green', 'blue'];
let colors2 = colors1.concat('yellow', ['black', 'brown']);
console.log(colors1); // [ 'red', 'green', 'blue' ]
console.log(colors2); // [ 'red', 'green', 'blue', 'yellow', 'black', 'brown' ]

2.2.2 删

  • pop——尾删(返回被删除项)
  • shift——首删(返回被删除项)
  • splice(返回被删除元素的数组)
  • slice(返回新切片构建的数组,但不影响原数组)
// 删-splice(开始位置,要删除元素的数量) 返回删除元素的数组
let colors = ["red", "green", "blue"];
let removed = colors.splice(0,1); // 删除第一项
console.log(colors); // [ 'green', 'blue' ]
console.log(removed); // [ 'red' ]


// 删-slice(新构建数组的开始元素位置, 新构建数组的结束元素位置边界) 不包括结束元素
let colors1 = ["red", "green", "blue", "yellow", "purple"];
let colors2 = colors1.slice(1);
let colors3 = colors1.slice(1, 4);
console.log(colors1); // ['red', 'green', 'blue', 'yellow', 'purple']
console.log(colors2); // ['green', 'blue', 'yellow', 'purple']
console.log(colors3); // ['green', 'blue', 'yellow' ]

2.2.3 改

  • 改:splice(删除部分元素,同时插入元素,影响原数组)
// 改-splice(开始位置, 要删除的元素数量, 要插入的元素) 返回删除元素的数组
let colors = ['red', 'green', 'blue'];
let removed = colors.splice(1, 1, 'purple'); // 删除一个元素,插入一个元素
console.log(colors); // [ 'red', 'purple', 'blue' ]
console.log(removed); // [ 'green' ],只有一个元素的数组

2.2.4 查

  • indexOf
  • includes
  • find(传入逻辑函数,返回使得逻辑函数为真的第一个元素)
  • filter(传入逻辑函数,返回所有使得逻辑函数为真的数组)
let numbers = [1, 2, 3, 4, 5, 4];
console.log(numbers.indexOf(4)); // 3
console.log(numbers.includes(4)); // true
console.log(numbers.find((d, index) => d >= 5)); //5
console.log(numbers.filter((d, index) => d >= 5)); //[5];

以下函数接收一个函数作为参数,(element, index, array)=>{},均不会改变原数组,除非手动对数组进行修改(比如调用原数组或使用array参数修改)

  • some:对数组每一项都运行函数,如果至少有1个元素返回 true ,则这个方法返回 true
  • every:对数组每一项都运行函数,如果所有元素都返回 true ,则这个方法返回 true
  • forEach:对数组每一项都运行传入的函数,没有返回值
  • filter:对数组每一项都运行传入的函数,返回函数结果为 true 的项构成的数组
  • map:对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组
let numbers = [1, 2, 3, 4, 5];
console.log(numbers.some((d, index, array) => d > 2)); // true
console.log(numbers.every((d, index, array) => d > 2)); // false
console.log(numbers.filter((d, index, array) => d > 2)); // [ 3, 4, 5 ]
console.log(numbers.map((d, index, array) => d ** 2)); // [ 1, 4, 9, 16, 25]

2.2 初始化和拷贝

> 判断一个数组是否为数组

Array.isArray(arr);

2.2.1 初始化

1. 一维数组的初始化

var arr = new Array(len).fill(0);
var arr = [];

2. 二维数组的初始化(很容易产生浅拷贝的问题),要生成一个二维数组:[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

//易犯错的浅拷贝:改一个值,每一行这个值都会变,这个bug让了一个小时
var arr = new Array(matrix.length).fill(new Array(matrix.length[0]).fill(0));错误
//正确写法:
var arr = Array.from({length:matrix.length}, x=>Array.from({length:matrix[0].length}, y=>0));
var arr = new Array(matrix.length).fill(0).map(() => new Array(matrix[0].length).fill(0));

2.2.2 拷贝

1. 单层(一维)数组拷贝

arr = [1, 2, 3];
arrCopy = [...arr];
numbersCopy = arr.map((x) => x);

2. 多层(多维)数组拷贝,很容易出现浅拷贝的问题,拷贝的是引用而不是赋值。

nestedNumbers = [[1], [2]];
numbersCopy = JSON.parse( JSON.stringify(nestedNumbers));

2.3 遍历

1. ES5——forEach()

const arr = ['a', 'b', 'c'];
arr.prop = 'property value';

arr.forEach((elem, index) => {
  console.log(elem, index);
});
// Output:
// 'a', 0
// 'b', 1
// 'c', 2

2. ES6——for...of :for-of 不仅可以遍历数组,还可以遍历可迭代对象,例如遍历 Map

const arr = ['a', 'b', 'c'];
arr.prop = 'property value';

for (const elem of arr) {
  console.log(elem);
}

//map
for (const [key, value] of myMap) {
  console.log(key, value);
}
//数组方法.entries() 返回一个可迭代的[index,value]对
//keys()、values()类同
for (const [index, elem] of arr.entries()) {
  console.log(index, elem);
}

2.4 排序

  • reverse:反转
  • sort:接受一个比较函数,用于判断哪个元素在前面(比如 a, b 比较,如果比较函数返回 -1 则表示a在b前面,返回1表示b在a前面,返回0表示不改变顺序)
arr.sort((x, y) => x-y);//升序排序
arr.sort((x, y) => y-x);//降序排序
//自定义排序
function cmp(x, y){
    if(x < y) return -1;
    eles if(x == y) return 0;
    else if(x > y) return 1;
}
arr.sort(cmp)

2.5 返回数组里某个特定的值

2.5.1 返回数组的最小值和最大值

var min = Math.min(...arr);
var max = Math.max(...arr);
//因为Math.min()只接受两个参数,而这里的...为扩展运算符
//相当于依次把arr中的数值作为参数传入到Math.min()函数中

引申:返回数组对象中某个属性的最大值和最小值

Math.min.apply(Math, this.list.map(d => { return d.id }))
Math.max.apply(Math, this.list.map(d => { return d.id }))

2.5.2 返回数组的和

var sum = eval(arr.join('+'));
//eval()函数的作用:将普通字符串当做js代码解释执行
var sum = arr.reduce((a,b)=>(a+b));
//reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

2.6 数组高级操作

2.6.1 reduce

reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,回调函数接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。

arr.reduce(callback, [initialValue])

如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。

三、字符串

3.1 增删改查

js字符串一旦创建则不能改变,因此关于字符串操作方法,都是创建一个新的副本再操作。

3.1.1 增

  • +操作符
  • ${}模板操作符
  • concat
const stringValue = ' hello world ';
console.log(stringValue + '2'); // ' hello world 2'
console.log(`${stringValue} 456`); // ' hello world  456'
console.log(stringValue.concat('456')); // ' hello world  456'

3.1.2 删

  • slice(切片开始位置, [切片结束位置])、substr(切片开始位置,[切片结果字符串的长度])、substring(切片开始位置, [切片结束位置])
    • slice和substring区别是:slice遇到负索引将从末尾开始切片,而substring遇到负索引将会将其转化为0然后再判断位置大小正向切片
    • substr在es5中不推荐使用
var str = 'hello world';
console.log(str.slice(-3)); // rld
console.log(str.substring(-3));// hello world //substring(-3) => substring(0)
console.log(str.substr(-3));// rld

console.log(str.slice(3, -4)); // lo w
console.log(str.substring(3, -4)); // hel 
//substring(3, -4) => substring(3, 0) =>substring(0, 3)
console.log(str.substr(3, -4));// ""(空字符串)
//substr(3, -4) => substr(3, 0)

3.1.3 改

  • trim、trimLeft、trimRight:返回去除空格符后的字符串
  • repeat:将原始字符串重复拼接然后返回新的字符串
  • padStart、padEnd:对字符串进行填充直至符合指定长度
const stringValue = ' hello world ';
console.log(stringValue.trim());// 'hello world'
console.log('123'.repeat(2)); // '123123'
console.log('123'.padStart(10, '-')); // '-------123'
console.log('123'.padEnd(10, '-')); // '123-------'

3.1.3.1 ASCII(大小写)

//将字母转为ASCII码
"A".charCodeAt();      // 65
//将ASCII码转为对应字母
String.fromCharCode(97);  // 'a'

str = str.toUpperCase();  //大写
str = str.toLowerCase();  //小写

3.1.4 查

  • charAt、indexOf、startWith、endWith、includes
const stringValue = ' hello world ';
console.log(stringValue.trim());// 'hello world'
console.log('123'.repeat(2)); // '123123'
console.log('123'.padStart(10, '-')); // '-------123'
console.log('123'.padEnd(10, '-')); // '123-------'

3.1 字符串与数组的互相转换

1. 字符串转数组

var arr=s.split('');

2. 将数组以字符串的形式输出,默认使用","隔开。

//toString()方法不仅适用于数组,而且还可以用于其他类型的对象,它用于将对象的值转换为字符串。
var str = arr.toString(); 
var str = arr.join();  

3.3 正则表达式

3.3.1 匹配方法

  • match:接收字符串、正则表达式字符串或RegExp对象,返回匹配到的第一个元素构成的正则结果数组
  • search:接收字符串、正则表达式字符串或RegExp对象,返回匹配到的第一个元素索引
  • replace:接收两个参数,第一个为匹配的内容(可为字符串或正则表达式),第二个要替换的内容(可以使用函数),返回替换后的字符串 ,但该方法一次只能替换第一个匹配的,如果需要替换所有则需要使用全局模式的正则表达式
const text = 'cat, bat, sat, fat';
console.log(text.match(/.at/)); // [ 'cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined ]
console.log(text.search(/.at/)); // 0
console.log(text.replace(/.at/, '-')); // "-, bat, sat, fat"
console.log(text.replace(/.at/g, '-')); // "-, -, -, -"

3.3.2 匹配符

  • / /:用来包含一个正则表达式
  • 特殊字符要用\转义
  • .表示除了换行符之外的任何字符
  • *用来表示匹配0个字符或无数个字符
  • ^字符串开头
  • $字符串结尾

1. 判断字符串是不是只包括大小写字母和数字

var a = "123abcA";
var re = /^[0-9a-zA-Z]*$/
console.log(re.test(a))

正则表达式不要背 - 掘金

四、JS数据结构

4.1 Map

1. 大小:map.size;

2. 方法:

  • set(key, val): 向Map中添加新元素
  • get(key): 通过键值查找特定的数值并返回
  • has(key): 判断Map对象中是否有Key所对应的值,有返回true,否则返回false
  • delete(key): 通过键值从Map中移除对应的数据
  • clear(): 将这个Map中的所有元素删除

3. 遍历方法:

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
const map = new Map([['a', 1], ['b',  2]])

for (let key of map.keys()) {
  console.log(key)
}// "a" // "b"
for (let value of map.values()) {
  console.log(value)
}// 1 // 2
for (let item of map.entries()) {
  console.log(item)
}// ["a", 1] // ["b", 2]

for (let [key, value] of map.entries()) {
  console.log(key, value)
}// "a" 1 // "b" 2

// for...of...遍历map等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value)
}// "a" 1 // "b" 2

4. Map转化为二维数组后排序

var arr = Array.from(map); 
arr.sort((a, b) => { return a[0]-b[0]; }) //对key进行从小到大排序

4.2 Set

1. 大小:map.size;

2. 方法:

  • add(value):添加某个值,返回 Set 结构本身(可以链式调用)。
  • delete(value):删除某个值,删除成功返回true,否则返回false。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。

3. 遍历方法:

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回键值对的遍历器。
  • forEach():使用回调函数遍历每个成员。
const set = new Set(['a', 'b', 'c'])

for (let item of set.keys()) {
  console.log(item)
}// a // b // c

for (let item of set.values()) {
  console.log(item)
}// a // b // c

for (let item of set.entries()) {
  console.log(item)
} // ["a", "a"] // ["b", "b"] // ["c", "c"]

// 直接遍历set实例,等同于遍历set实例的values方法
for (let i of set) {
  console.log(i)
} // a // b // c

set.forEach((value, key) => console.log(key + ' : ' + value))
// a: a // b: b // c: c

五、JS底层函数(像算法一样复杂的JS)

5.1 手写call(), apply(), bind()

5.2 手写repeat(), setInterval()

function repeat(func, times, wait){
    return function(){
        var arg = arguments;
        var handle = function(i){
            setTimeout(function(){
                func.apply(this, arg);
            }, wait*i);
        }
        for(let i = 0; i < times; i++){
            handle(i);
        }
    }
}
var repeatFunc = repeat(console.log, 4, 3000);
repeatFunc("hellworld");

function mySetInterval(func, time){
    function f(){
        func();
        setTimeout(function(){
            func();
        }, time)
    }
    setTimeout(f, time);
}
mySetInterval(() => {
    console.log(new Date())
  }, 1000)

六、无聊的小技巧

6.1 实时打印JS数据内容

由于I/O异步化,浏览器可能会认为需要把控制台的I/O延迟到后台,在这种情况下,等到浏览器控制台输出对象内容时,已经执行了其他内容,造成console.log()的内容不准确。

如果想要实时打印内容,最好将其内容作为字符串保留下来,通常使用JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串,但JSON.stringify()方法无法处理对象中自己引用自己的问题,比如说data = { 'myself':data }; 通过下面这个方法可以解决这个问题。

function cleanStringfy(object) {
    if (object && typeof object === 'object') {
        object = copyWithoutCircularReferences([object], object);
    }
    return JSON.stringify(object);


    function copyWithoutCircularReferences(references, object) {
        var cleanObject = {};
        Object.keys(object).forEach(function(key) {
            var value = object[key];
            if (value && typeof value === 'object') {
                if (references.indexOf(value) < 0) {
                    references.push(value);
                    cleanObject[key] = copyWithoutCircularReferences(references, value);
                    references.pop();
                } else {
                    cleanObject[key] = '###_Circular_###';
                }
            } else if (typeof value !== 'function') {
                cleanObject[key] = value;
            }
        });
        return cleanObject;
    }
}

6.2 不使用额外的空间交换两个数

//不利用中间变量交换两个值的方法
function swap1(x, y) {
    x = x + y;
    y = x - y; //将上一步的x+y代入x
    x = x - y;
    return [x, y];
}

function swap2(x, y) {
    x = x ^ y;
    y = x ^ y;
    x = x ^ y; //在异或中相同为0,不同为1;原理就是a^b^a在各种情况下均=b 
    return [x, y];
}

function swap3(x, y){
    x = x * y;
    y = x / y;
    x = x / y;
    return [x, y];
}

七、ES6

7.1 Let和Const

varletconst三者区别可以 围绕下面五点展开:

  • 变量提升var变量存在变量提升,即变量可以在声明之前调用,值为undefined;而letconst不存在变量 提升,即它们所声明的变量一定要在声明后使用,否则报错。
  • 暂时性死区var不存在暂时性死区,letconst存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
  • 块级作用域var不存在块级作用域;letconst存在块级作用域
  • 重复声明var允许重复声明变量;letconst 在同一作用域不允许重复声明变量
  • 修改声明的变量varlet可以;而 const声明一个只读的常量,值不能改变 
  • 使用:能用const的情况尽量使用const,其他情况 下大多数使用let,避免使用var

7.2 数组新增拓展

  • 扩展运算符
  • 构造函数新增的方法
  • 实例对象新增的方法
  • 数组的空位:ES6明确将空位转为undefined
  • 排序稳定性:ES6将自定义排序设置为稳定排序

7.3 对象新增拓展

  • 属性的简写:ES6中,当对象键名与对应值名相等的时候,可以进行简写
  • 属性名表达式:ES6允许字面量定义对象时,将表达式放在括号内
  • super:this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象
  • 扩展运算符的应用:在解构赋值中,未被读取的可遍历的属性,分配到指定的对象上面
  • 属性的遍历
  • 对象新增的方法:
    • Object.assign()方法用于对象的合并,将源对象source的所有可枚举属性,复制到目标对象target;Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象
    • Object.setPrototypeOf方法用来设置一个对象的原型对象
    • Object.getPrototypeOf用于读取一个对象的原型对象

7.4 函数新增扩展

  • 参数:ES6允许为函数的参数设置默认值
  • 属性:函数的length属性将返回没有指定默认值的参数个数;函数name属性将返回函数名
  • 作用域:一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域
  • 严格模式:只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错
  • 箭头函数:
    • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
    • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误
    • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可用 rest 参数代替
    • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数

7.5 Promise

八、面试考点

8.1 数组扁平化(字节)

方法一:递归,用res保存结果

function flatten(a){
    var len = a.length;
    for (let i = 0; i < len; i++){
        if (Array.isArray(a[i])){
            flatten(a[i]);
        }else{
            res.push(a[i]);
        }
    }
}

方法二:使用reduce一直累加数组

​ function flatten(arr) {  
    return arr.reduce((result, item)=> {
        return result.concat(Array.isArray(item) ? flatten(item) : item);
    }, []);
}

8.2 数据去重

方法一:set

var a = [1, 2, 3, 4, 5, 3];
var set = new Set();
a.forEach(key=>{set.add(key)});
console.log(set);
//简化版
[...new Set(arr)] 

方法二reduce+includes

var a = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
var res = a.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值