JavaScript基础知识(一)

1. 数据类型&判断

1.1. 数据类型

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

1.2. 类型判断

  • typeof

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    typeof 123 //number
    typeof true //boolean
    typeof "abc" //string
    typeof undefined //undefined
    typeof null //object
    typeof 123n //bigint
    typeof Symbol(a) //symbol
    typeof [] //object
    typeof {} //object
    typeof function () {} //function
    typeof NaN //number
    typeof new Date() //object
    typeof RegExp() //object
  • instanceof

    1
    2
    3
    4
    function Person() {}
    const p = new Person()
    console.log(p instanceof Person) //true
    console.log(p instanceof Object) //true
  • constructor

    1
    2
    3
    function Person() {}
    const p = new Person()
    console.log(p.constructor === Person) //true
  • Array

    1
    Array.isArray([]) //true
  • NaN

    1
    2
    3
    isNaN(NaN) //true
    isNaN(123) //false
    isNaN("abc") //true
  • prototype

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Object.prototype.toString.call(123) //[object Number]
    Object.prototype.toString.call("abc") //[object String]
    Object.prototype.toString.call(true) //[object Boolean]
    Object.prototype.toString.call(undefined) //[object Undefined]
    Object.prototype.toString.call(null) //[object Null]
    Object.prototype.toString.call(Symbol()) //[object Symbol]
    Object.prototype.toString.call(123n) //[object BigInt]
    Object.prototype.toString.call([]) //[object Array]
    Object.prototype.toString.call({}) //[object Object]
    Object.prototype.toString.call(function () {}) //[object Function]
    Object.prototype.toString.call(new Date()) //[object Date]
    Object.prototype.toString.call(RegExp()) //[object RegExp]

1.3. 判断是否相等

  • 全等

    1
    2
    3
    4
    5
    null == undefined //true
    null === undefined //false
    NaN == NaN //false
    +0 === 0 //true
    +0 === -0 //true
  • Object.is

    1
    2
    3
    4
    5
    Object.is(null, undefined) //false
    Object.is(NaN, NaN) //true
    Object.is(+0, 0) //true
    Object.is(-0, 0) //false
    Object.is(+0, -0) //false

1.4. 判断是否为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//判断是否为null
value === null
!value && typeof value != "undefined" && value != 0

//判断是否为空
!value //判断null undefine NaN 0 false ""
value.length === 0 //判断[]

//Object.getOwnPropertyNames 判断{}
var value = {}
var arr = Object.getOwnPropertyNames(value)
console.log(arr.length == 0) // true

//Object.getOwnPropertySymbols 判断Symbol()
var value = {}
var arr = Object.getOwnPropertySymbols(value)
console.log(arr.length == 0) // false

2. 构造函数&原型&实例&类

2.1. 关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//1.构造函数
function Person(name, age) {
this.name = name
this.age = age
this.sayName = function () {
console.log(this.name)
}
}
const p = new Person("Jim Green", 12)

//2. 构造函数的原型
Person.prototype.job = "student"

//3. 关系
p instanceof Person //true
p.__proto__ === Person.prototype //true
Person.prototype.constructor === Person // true
Person.prototype.isPrototypeOf(p) //true

2.2. 继承

2.2.1. 原型继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function SuperType(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name)
}
}

function SubType(){

}

SubType.prototype = new SuperType()

const sub = new SubType();

console.log(sub instanceof SubType); //true
console.log(sub instanceof SuperType); //true
2.2.2. 经典继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name)
}
}

function SubType(name, age){
SuperType.call(this, name, age)
}

const sub = new SubType('Jim Green',12);
console.log(sub.name); //Jim Green
sub.sayName(); //Jim Green
console.log(sub instanceof SubType); //true
console.log(sub instanceof SuperType); //false
2.2.3. 组合继承
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
function SuperType(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name)
}
}
SuperType.prototype.sayAge = function(){
console.log(this.age)
}

function SubType(name, age, job){
SuperType.call(this, name, age)
this.job = job
}

SubType.prototype = new SuperType();
SubType.prototype.sayJob = function(){
console.log(this.job)
}
const sub = new SubType('Jim Green',12,'student');
console.log(sub.name); //Jim Green
sub.sayName(); //Jim Green
sub.sayAge(); //12
sub.sayJob(); //student
console.log(sub instanceof SubType); //true
console.log(sub instanceof SuperType); //true
2.2.4. 原型式继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function object(o){
function F(){}
F.prototype = o
return new F()
}

let person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
let anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
let yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends);// ['Shelby', 'Court', 'Van', 'Rob', 'Barbie']
2.2.5. 寄生式组合继承
1
2
3
4
5
6
7
8
9
10
11
function object(o){
function F(){}
F.prototype = o
return new F()
}

function inheritPrototype(subType,superType){
let prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}

2.3. 类

2.3.1. 类的构成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Foo{
constructor(name,age){
this.name = name ;
this.age = age;
}
sayName(){
console.log(this.name)
}
static baseF(){
console.log(this)
}
}

const f = new Foo('Jim Green',12)
console.log(f.name); // Jim Green
f.sayName(); // Jim Green
Foo.baseF(); // class Foo{...}
typeof Foo ; // funciton
2.3.2. 类继承
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
class Super{
constructor(name,age){
this.name = name ;
this.age = age;
}
sayName(){
console.log(this.name)
}
static baseF(){
console.log(this)
}
}
class Sub extends Super{
constructor(name,age,job){
super(name,age);
this.job = job;
console.log(this.name)
}
}

const s = new Sub('Jim Green',12, 'student');//Jim Green
console.log(s.age); //12
console.log(s.job); //student
s.sayName(); //Jim Green
Sub.baseF(); //class Sub{...}

3. 数组遍历

  • for循环
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let i = 0, len = arr.length ; i < len ; i++ ){
    console.log(arr[i]);
    }
  • forEach
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    arr.forEach(function(item,index,arr){
    console.log(item)
    })
  • for…in
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let index in arr){
    console.log(arr[index]);
    }
  • for…of
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let item of arr){
    console.log(item);
    }
  • Object.entries
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let [index,item] of arr.entries()){
    console.log(index,item);
    }
  • Object.keys()
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let index of arr.keys()){
    console.log(index);
    }
  • Object.values()
    1
    2
    3
    4
    let arr = [2,3,5,7,11,13,17,19];
    for(let item of arr.values()){
    console.log(item);
    }

4. 对象遍历

  • for-in 循环——只遍历可枚举属性,包含实例属性和原型属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const obj = {
    a:123,
    b:'abc',
    c:function(){
    console.log()
    }
    }
    for( let key in obj){
    console.log(obj[key])
    }
  • Object.keys()——只遍历可枚举属性,只包含实例属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    }
    }
    const res = Object.keys(obj)
    console.log(res)
  • Object.values()——只遍历可枚举属性,只包含实例属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    }
    }
    const res = Object.values(obj)
    console.log(res)
  • Object.entries()——只遍历可枚举属性,只包含实例属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    }
    }
    const res = Object.entries(obj)
    console.log(res)
  • Object.getOwnPropertyNames——遍历所有属性,除了Symbol属性,包含可枚举和不可枚举,包含实例属性和原型属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    },
    [Symbol()]:111
    }
    const res = Object.getOwnPropertyNames(obj)
    console.log(res)
  • Object.getOwnPropertySymbols——只遍历Symbol属性,包含可枚举和不可枚举,包含实例属性和原型属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    },
    [Symbol()]:111
    }
    const res = Object.getOwnPropertySymbols(obj)
    console.log(res)
  • Reflect.ownKeys——遍历所有属性,包含可枚举和不可枚举,包含实例属性和原型属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const obj = {
    a: 123,
    b: "abc",
    c: function () {
    console.log()
    },
    [Symbol()]:111
    }
    const res = Reflect.ownKeys(obj)
    console.log(res)

5. 对象解构

1
2
3
4
5
6
7
8
9
10
const obj = {
a: 123,
b: "abc",
c: function () {
console.log()
},
[Symbol()]:111
}
const {b,c,a} = obj
console.log(b,c,a)

6. 展开运算符

6.1. 展开数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//数组转换
const arr = [1,2,3,4,5]
console.log(...arr) // 1 2 3 4 5

//数组浅拷贝
let a = [1, 2, 3, { m: 123 }]
let b = [...a]
console.log(b)
b[0] = 5
b[3].m = 456
console.log(a)
console.log(b)

//拼接数组
let a = [1, 2, 3]
let b = [-1, 0, ...a, 4, 5]
console.log(b)

6.2. 展开函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function f(...args) {
console.log(args)
}
f(1, 2, 3) //[1, 2, 3]

function f(a, ...args) {
console.log(args)
}
f(1, 2, 3) //[2, 3]

function f(a, ...args, b) {
console.log(args)
}
f(1, 2, 3) //SyntaxError: Rest parameter must be last formal parameter

6.3. 展开对象

  • 对象浅拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //对象浅拷贝
    let obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    },
    [Symbol()]: 1
    }

    let obj2 = { ...obj1 }
    console.log(obj2) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 123 }, [Symbol()]: 1 }

    obj2.a = 2
    console.log(obj1) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 123 }, [Symbol()]: 1 }
    console.log(obj2) //{ a: 2, b: 'xyz', c: [Function: c], d: { m: 123 }, [Symbol()]: 1 }

    obj2.d.m = 456
    console.log(obj1) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 456 }, [Symbol()]: 1 }
    console.log(obj2) //{ a: 2, b: 'xyz', c: [Function: c], d: { m: 456 }, [Symbol()]: 1 }
  • 对象合并

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //合并对象
    let obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    },
    [Symbol()]: 1
    }

    let obj2 = { ...obj1, e: 111 }
    console.log(obj2) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 123 }, e: 111, [Symbol()]: 1 }
  • 对象解构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    },
    [Symbol()]: 1
    }

    let { a, b, ...obj2 } = obj1
    console.log(obj2) //{ c: [Function: c], d: { m: 123 }, [Symbol()]: 1 }

7. Object 方法

  • Object.assign

    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
    //浅拷贝
    const obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    }
    }

    const obj2 = Object.assign({},obj1)
    console.log(obj2) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 123 } }

    obj2.d.m = 456
    console.log(obj1) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 456 } }
    console.log(obj2) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 456 } }

    //合并
    const obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    }
    }
    const obj2 = {
    a: 2,
    b: "abc"
    }
    const obj3 = Object.assign(obj1, obj2)
    console.log(obj3) //{ a: 2, b: 'abc', c: [Function: c], d: { m: 123 } }
  • Object.create

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //创建新对象,源对象是新对象的原型
    const obj1 = {
    a: 1,
    b: "xyz",
    c: function () {},
    d: {
    m: 123
    }
    }
    const obj2 = Object.create(obj1)
    console.log(obj2.a) //1

    obj2.d.m = 456
    console.log(obj1) //{ a: 1, b: 'xyz', c: [Function: c], d: { m: 456 } }
  • Object.defineProperty

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //对象添加属性
    const obj = {}
    Object.defineProperty(obj, "a", {
    configurable: true,
    enumerable: true,
    writable: true,
    value: 123
    })
    obj.a = 456
    console.log(obj) //{a:456}
  • Object.defineProperties

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //对象多个属性
    const obj = {}
    Object.defineProperties(obj, {
    a: {
    configurable: true,
    enumerable: true,
    writable: true,
    value: 123
    },
    b: {
    configurable: true,
    enumerable: true,
    writable: true,
    value: {
    m: 10
    }
    }
    })
    console.log(obj) //{ a: 123, b: { m: 10 } }
  • Object.entries

    1
    2
    3
    4
    //返回对象可枚举属性的键值对数组
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.entries(obj)
    console.log(res) //[ [ 'a', 123 ], [ 'b', { m: 10 } ] ]
  • Object.fromEntries

    1
    2
    3
    4
    //键值对列表转换为一个对象
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.entries(obj)
    console.log(res) //{ a: 123, b: { m: 10 } }
  • Object.getOwnPropertyDescriptor

    1
    2
    3
    4
    //返回对象的某个元素的描述符
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.getOwnPropertyDescriptor(obj, "a")
    console.log(res) //{ value: 123, writable: true, enumerable: true, configurable: true }
  • Object.getOwnPropertyDescriptors()

    1
    2
    3
    4
    //返回对象的所有自身属性的描述符
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.getOwnPropertyDescriptors(obj)
    console.log(res) //
  • Object.getOwnPropertyNames

    1
    2
    3
    4
    //对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.getOwnPropertyNames(obj)
    console.log(res) //[ 'a', 'b' ]
  • Object.getOwnPropertySymbols

    1
    2
    3
    4
    //对象的所有自身属性的属性名(只包括 Symbol 值作为名称的属性)组成的数组
    const obj = { a: 123, b: { m: 10 }, [Symbol()]: 1 }
    const res = Object.getOwnPropertySymbols(obj)
    console.log(res) //[ Symbol() ]
  • Object.freeze

    1
    2
    3
    4
    5
    //冻结一个对象,不能被修改
    const obj = { a: 123, b: { m: 10 } }
    Object.freeze(obj)
    obj.a = 456
    console.log(obj) //{ a: 123, b: { m: 10 } }
  • Object.getPrototypeOf

    1
    2
    3
    4
    //对象的原型
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.getOwnPropertyNames(obj)
    console.log(res) //[Object: null prototype] {}
  • Object.prototype.hasOwnProperty()

    1
    2
    3
    4
    //对象的是否有指定属性,不包含原型属性
    const obj = { a: 123, b: { m: 10 } }
    const res = obj.hasOwnProperty('a')
    console.log(res) //true
  • Object.prototype.isPrototypeOf

    1
    2
    3
    4
    //对象是否存在于另一个对象的原型链上
    const obj = { a: 123, b: { m: 10 } }
    const res = obj.isPrototypeOf(Object)
    console.log(res) //false
  • Object.is

    1
    2
    3
    4
    5
    6
    //判断两个值是否为同一个值
    Object.is(null, undefined) //false
    Object.is(NaN, NaN) //true
    Object.is(+0, 0) //true
    Object.is(-0, 0) //false
    Object.is(+0, -0) //false
  • Object.keys

    1
    2
    3
    4
    //返回对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.keys(obj)
    console.log(res) //[ 'a', 'b' ]
  • Object.values

    1
    2
    3
    4
    //返回对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同
    const obj = { a: 123, b: { m: 10 } }
    const res = Object.keys(obj)
    console.log(res) //[ 123, { m: 10 } ]

8. Array 方法

  • Array.isArray —— 判断是否为数组
  • Array.of ——参数变数组
    1
    Array.of(1,2,3) ;//[1, 2, 3]
  • Array.from ——类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Array.from('foo') // ['f','o','o']
    Array.from([1, 2, 3], x => x + x) //[2, 4, 6]

    const set = new Set(['foo', 'bar', 'baz', 'foo'])
    Array.from(set) //['foo', 'bar', 'baz']

    const map = new Map([[1, 2], [2, 4], [4, 8]])
    Array.from(map) //[[1, 2], [2, 4], [4, 8]]

    const mapper = new Map([['1', 'a'], ['2', 'b']])
    Array.from(mapper.values()) //['a', 'b']
    Array.from(mapper.keys()) //['1', '2']

    Array.from([1, 2, 3], x => x + x) //[2, 4, 6]

    Array.from({ length: 3 }, (_, i) => i) // [0,1,2] 序列生成器
  • concat ——合并两个或多个数组,不改变当前数组,返回新数组
  • pop ——从数组中删除最后一个元素,并返回该元素的值。改变数组的长度
  • push ——将一个或多个元素添加到数组的末尾,并返回该数组的新长度。改变数组的长度
  • shift ——从数组中删除第一个元素,并返回该元素的值。改变数组的长度
  • unshift ——将一个或多个元素添加到数组的开头,并返回该数组的新长度。改变数组的长度
  • splice ——删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
  • slice ——返回一个新的数组对象,由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。不改变当前数组
  • every ——数组内的所有元素是否都能通过某个指定函数的测试。返回一个布尔值
  • some ——数组内的至少有 1 个元素通过了被提供的函数测试。返回一个布尔值
  • map ——创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
  • filter ——创建一个新数组,其包含通过所提供函数实现的测试的所有元素
  • reduce ——迭代归并
  • join ——一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串,可传参数
  • sort ——元素进行排序。默认排序是将元素转换为字符串,比较它们的 UTF-16 代码,可传入自定义比较函数。改变原数组
  • reverse ——元素的位置倒叙,改变原数组
  • find ——返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
  • findIndex ——返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1
  • indexOf ——返回在数组中可以找到一个给定元素的第一个索引。否则返回-1
  • lastIndexOf ——返回在数组中可以找到一个给定元素的最后一个索引。否则返回-1
  • includes ——判断一个数组是否包含一个指定的值,返回布尔值
  • entries ——返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对
  • values ——返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值
  • keys ——返回一个包含数组中每个索引键的Array Iterator对象
  • forEach ——对数组的每个元素执行一次给定的函数
  • copyWithin ——浅复制数组的一部分到同一数组中的另一个位置,并返回它。不改变原数组
  • toStrng —— 返回一个字符串,表示指定的数组及其元素
  • fill ——用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引
  • flat ——按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
    1
    2
    3
    4
    5
    6
    7
    const arr1 = [0, 1, 2, [3, 4]];
    console.log(arr1.flat());
    // expected output: [0, 1, 2, 3, 4]

    const arr2 = [0, 1, 2, [[[3, 4]]]];
    console.log(arr2.flat(2));
    // expected output: [0, 1, 2, [3, 4]]

9. 数组去重

  • 遍历循环判断
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function norepeat(arr) {
    for (let i = 0, len = arr.length; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
    if (arr[i] === arr[j] || Object.is(arr[i], arr[j])) {
    arr.splice(j, 1)
    }
    }
    }
    return arr
    }
    //无法去除[] {} function(){}
  • Set
    1
    [...new Set(arr)]
  • indexOf
    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
    function norepeat(arr) {
    const newarr = []
    arr.forEach(function (item) {
    if (newarr.indexOf(item) === -1) {
    newarr.push(item)
    }
    })
    return newarr
    }

    function norepeat(arr) {
    const newarr = []
    arr.forEach(function (item,index) {
    if (arr.indexOf(item) === index) {
    newarr.push(item)
    }
    })
    return newarr
    }

    function norepeat(arr) {
    return arr.filter(function (item,index) {
    return arr.indexOf(item) === index
    })
    }

    //不能判断NaN
  • includes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function norepeat(arr) {
    const newarr = []
    arr.forEach(function (item, index) {
    if (!newarr.includes(item)) {
    newarr.push(item)
    }
    })
    return newarr
    }
  • Map
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function norepeat(arr) {
    const newarr = []
    const map = new Map()
    arr.forEach(function (item) {
    if (!map.has(item)) {
    newarr.push(item)
    map.set(item, true)
    }
    })
    return newarr
    }
  • object
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function norepeat(arr) {
    const newarr = []
    const obj = {}
    arr.forEach(function (item) {
    if (!obj[item]) {
    newarr.push(item)
    obj[item] = true
    }
    })
    return newarr
    }

10. 多维数组遍历

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
function flatten(sourceArr, flattenedArr = []) {
for (const item of sourceArr) {
if (Array.isArray(item)) {
flatten(item, flattenedArr)
} else {
flattenedArr.push(item)
}
}
return flattenedArr
}

const arr = [1, [2, 3], [[4, 5], 6], [[[[3, 4, 5, 6]]]]]
console.log(flatten(arr)) //[1, 2, 3, 4, 5, 6, 3, 4, 5, 6]

//指定展开级别
function flattenDepth(sourceArr, depth, flattenedArr = []) {
for (const item of sourceArr) {
if (Array.isArray(item) && depth > 0) {
flattenDepth(item, depth - 1, flattenedArr)
} else {
flattenedArr.push(item)
}
}
return flattenedArr
}

const arr = [1, [2, 3], [[4, 5], 6], [[3, 4, 5, 6]]]
console.log(flattenDepth(arr, 1)) //[ 1, 2, 3, [ 4, 5 ], 6, [ 3, 4, 5, 6 ] ]

11. 浅拷贝&深拷贝

11.1. 数组浅拷贝

  • 展开运算符
    1
    2
    3
    4
    5
    6
    7
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = [...a1]

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • Array.from
    1
    2
    3
    4
    5
    6
    7
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = Array.from(a1)

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • slice
    1
    2
    3
    4
    5
    6
    7
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = a1.slice()

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • concat
    1
    2
    3
    4
    5
    6
    7
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = a1.concat([])

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • filer
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = a1.filter(function (item) {
    return true
    })

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • map
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = a1.map(function (item) {
    return item
    })

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 8 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]

11.2. 数组深拷贝

  • JSON 转换
    1
    2
    3
    4
    5
    6
    7
    const a1 = [1, 2, 3, [6, 7]]
    const a2 = JSON.parse(JSON.stringify(a1))

    a2[2] = 5
    a2[3][1] = 8
    console.log(a1) //[ 1, 2, 3, [ 6, 7 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]
  • 自定义函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function deepcloneObj(obj) {
    const deepclonedobj = Array.isArray(obj) ? [] : {}
    if (obj && typeof obj === "object") {
    for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
    if (obj[key] && typeof obj[key] === "object") {
    deepclonedobj[key] = deepcloneObj(obj[key])
    } else {
    deepclonedobj[key] = obj[key]
    }
    }
    }
    }
    return deepclonedobj
    }

    const a1 = [1, 2, 3, [6, 7]]
    const a2 = deepcloneObj(a1)

    a2[2] = 5
    a2[3][1] = 8

    console.log(a1) //[ 1, 2, 3, [ 6, 7 ] ]
    console.log(a2) //[ 1, 2, 5, [ 6, 8 ] ]

11.2. 浅拷贝

  • 展开运算符
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const obj1 = {
    x: 123,
    y: "abc",
    z: {
    a: 111
    }
    }
    const obj2 = { ...obj1 }
    obj2.x = 456
    obj2.z.a = 222
    console.log(obj1) //{ x: 123, y: 'abc', z: { a: 222 } }
  • Object.assign
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const obj1 = {
    x: 123,
    y: "abc",
    z: {
    a: 111
    }
    }
    const obj2 = Object.assign({}, obj1)
    obj2.x = 456
    obj2.z.a = 222
    console.log(obj1) //{ x: 123, y: 'abc', z: { a: 222 } }
  • 自定义函数
    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
      //简单深拷贝
    function deepcloneObj1(obj) {
    const deepclonedobj = Array.isArray(obj) ? [] : {}
    if (obj && typeof obj === "object") {
    for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
    if (obj[key] && typeof obj[key] === "object") {
    deepclonedobj[key] = deepcloneObj(obj[key])
    } else {
    deepclonedobj[key] = obj[key]
    }
    }
    }
    }
    return deepclonedobj
    }
    const obj1 = {
    x: 123,
    y: "abc",
    z: {
    m: 111
    }
    }

    const obj2 = deepcloneObj1(obj1)
    obj2.z.m = 222
    console.log(obj1) //{ x: 123, y: 'abc', z: { m: 111 } }
    console.log(obj2) //{ x: 123, y: 'abc', z: { m: 222 } }

    //进阶深拷贝
    //.....
    • jQuery extends
    • lodash _deepclone

12. 手写 Promise

13. fetch、 ajax

14. 防抖和节流

  • 防抖 ——持续触发事件时,一定时间内没有去触发事件,事件才会执行一次;一定时间内触发事件,需要重新计时,直到满足指定时间再执行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function debounce(fn,wait){
    let timer = null
    return function(){
    const that = this
    const args = arguments
    if(timer){
    clearTimeout(timer)
    }
    timer = setTimeout(function(){
    fn.apply(that,args)
    }, wait)
    }

    }
  • 节流 ——持续触发事件时,在一定时间内只执行一次
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function throttle(fn,wait){
    let timer = null
    const pre_time = new Date()
    return function(){
    const that = this
    const args = arguments
    const now_time = new Date()
    if(now_time - pre_time >=wait){
    fn.apply(that, args)
    }
    else {
    if(!timer){
    timer = setTimeout(function(){
    fn.apply(that, args)
    clearTimeout(timer)
    },now_time - pre_time)
    }
    }
    }
    }

15. async 、await

15.1. 介绍

  • async是函数声名的关键字
  • await用在async函数内部
  • async函数返回的是一个promise
  • 优化处理promise
  • 使用try…catch进行错误处理

15.2. 优点

  • 代码清晰简洁
  • 减少回调

16. apply、call、bind

  • 相同点:
    • 改变this指向,修改作用域
  • 不同点:
    • apply的第二个参数是数组,call是一个个的单独参数
    • apply、call是立即执行函数,bind只是返回一个函数

17. 代理

18. Map、Set

18.1. 概念

  • Map:键值对的数据映射集合
  • Set:有序的数据集合列表,元素相互独立且唯一非重复

18.2. 用法

  • Map

    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
    //新建
    const map = new Map()
    //或者
    const map = new Map(['key1','value1'],['key2','value2'])
    //或者
    const map = new Map().set('key1','value1').set('key2','value2')

    //长度
    map.size

    //增加元素
    map.set('keya','valuea')

    //获取
    const val = map.get('keya')

    //判断是否含有某元素
    const res = map.has('keya')

    //删除某元素
    map.delete('keya')

    //清空
    map.clear()

    //迭代
    for(let m of map){
    //按照之前插入map的顺序迭代
    }

    for(let m of map.entries()){

    }

    for(let m of map.keys()){

    }

    for(let m of map.values()){

    }

    for(let m of map[Symbol.iterator]()){

    }

    [...map]

    map.forEach((value,key)=>{})
  • Set

    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
    //新建
    const set = new Set()
    //或者
    const set = new Set(['value1','value2'])
    //或者
    const set = new Set().add('value1').add('value2')
    //长度
    set.size

    //增加元素
    set.add('valuea')

    //判断是否含有某元素
    const res = set.has('valuea')

    //删除某元素
    set.delete('keya')

    //清空
    set.clear()

    //迭代
    for(let s of set){
    //按照之前插入set的顺序迭代
    }

    for(let s of set.entries()){

    }

    for(let s of set.keys()){

    }

    for(let s of set.values()){

    }

    for(let s of set[Symbol.iterator]()){

    }

    [...set]

    set.forEach((value,key)=>{})

18.3. WeakMap、WeakSet

  • WeakMap ——弱映射,Map的健只能是Object或者继承于Object,不可迭代,不可clear
  • WeakSet ——弱集合,元素只能是Object或者继承于Object,不可迭代,不可clear

19. 事件循环Event Loop

19.1. JS语言的特点

  • 概念:单线程、非阻塞的脚本语言

20. this

  • 确定过程:创建执行上下文时,创建变量对象、确定作用域链、确定this指向
  • this指向是在函数被调用时确定的
  • 全局this,一般指向window
  • 函数中的this由调用者提供,指向由调用方式决定
  • 如果调用者函数被某一对象所拥有,函数调用时,this指向该对象
  • 如果函数独立,函数内部的this指向undefined,非严格模式下,this指向undefined时,会自动指向window
  • call和aplly改变this的指向
  • 构造函数中的this,指向新的实例对象
  • 箭头函数没有this,到上级作用域找this,上级作用域没有this则继续往上找;箭头函数绑定apply、call、bind只传递参数,不绑定this

21. 作用域、作用域链、执行上下文、闭包

  • 执行上下文 ——代码的执行环境
    • 执行环境:全局环境、函数环境、eval
    • 全局执行上下文在js代码开始运行时创建
    • 函数的执行上下文在函数被调用时创建
  • 作用域 ——变量和函数可以访问的范围
  • 作用域链 ——变量的可访问作用域对象的集和
  • 闭包 ——可访问另一个函数作用域的变量的函数,继续使用函数声名时的作用域,保护函数内部变量,回调函数

22. var 、let、const

  • var、let ——定义变量
  • const ——声名常量
  • const必须初始化
  • const不可修改,除了对象中的元素
  • const、let不可重复定义
  • const、let不是全局对象的属性
  • 变量提升 ——let、const需要先声名再使用
  • 块级作用域 ——if、while、for循环、switch、大括号、函数等