JavaScript面试题总结(全面)

1.js数据类型有哪些?两种类型的区别?

基本数据类型:String,Number,Boolean,Null,Undefined,Symbol

引用数据类型:Object,Array,Function,Data,Math,Map,Set,RegExp(正则表达式)

区别:两者的存放地址不同

基本数据类型存放在栈中,占用内存小,空间固定,且经常被使用。

引用数据类型存放在堆中,占用内存大,空间不固定;引用数据类型在栈中存放指针。指针指向堆

中该实体的起始地址。

2.数据类型的监测方法有哪些?

typeof(常用于判断基本数据类型,因为对象、数组和Null都返回的Object);

console.log(typeof '温情');  // string
console.log(typeof 111);  // number
console.log(typeof true);  // boolean
console.log(typeof undefined);  // undefined
console.log(typeof function () { });  // function
console.log(typeof {});  // object
console.log(typeof [1,2,3]);  // object
console.log(typeof null);  // object

instanceof;

用于判断引用数据类型,检测构造函数的prototype属性是否出现在某个实例对象的原型链上,有

则返回true,否则返回false,就是判断对象属于什么类型;

let arr = [];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
let obj = {};
console.log(obj instanceof Array); // false
console.log(obj instanceof Object); // true
let date = new Date();
console.log(date instanceof Date); // true
console.log(date instanceof Object); // true
console.log(date instanceof Array); // false

object.prototype.toString.call();

返回一个“[object XXX]”格式的字符串,XXX就是具体的数据类型

function getType(value) {
    if(typeof value !== 'object') {
        return typeof value;
    } else {
        return Object.prototype.toString.call(value).split(' ')[1].slice(0, -1);
    }
};
console.log( getType() );  // undefined
console.log( getType(null) );  // Null
console.log( getType(123) );  // number
console.log( getType('温情') );  // string
console.log( getType({}) );  // Object
console.log( getType([]) );  // Array
console.log( getType(new Date) );  // Date
console.log( getType(new RegExp) );  // RegExp
console.log( getType(new Function) );  // function

3.null和undefined的区别?

两个数据类型都是基本数据类型,并且都有一个值,null和undefined。

undefined的意思是未定义,比如说只是声明了一个变量但是为定义,那么就是undefined,

null是一个空对象。

4.如何实现深拷贝和浅拷贝?

浅拷贝:

        object.assign()的第一个参数是目标对象,后面的参数是源对象,这个方法会将目标对象

和源对象进行合并,如果目标对象和源对象中出现同一个键名的话,源对象中的值会覆盖掉目标对

象中的值。

        扩展运算符,会将多个数组进行合并,并且同样的值也不会被覆盖掉。

深拷贝:

        利用JSON.stringify():先利用JSON.stringify()将js对象转化为字符串,再利用JSON.parse()方

法将字符串还原为js对象赋值给一个新的对象,这样就完成了深拷贝。但是如果拷贝的对象当中有

函数,undefined,Symbol的话,数据就会消失。

        利用函数库lodash里的_.cloneDeep()方法进行深拷贝

5.如何判断一个对象是一个空对象?

1)利用JSON.stringify() 方法:

if(JSON.stringify(obj)=='{}') 如果为真的话就返回空对象

(2)object.keys(obj)方法:

if(object.keys(obj).length<=0) 如果为真就是空对象

6.箭头函数与普通函数的区别?

箭头函数比普通函数更加简洁。

箭头函数没有自己的this,其this指向与外层函数的this指向相同。

箭头函数不能当作构造函数使用。

箭头函数没有prototype,arguments属性。

call(),apply(),bind()方法不能改变箭头函数中this的指向。

7.数组原生的方法?

数组转换为字符串:toString(),tolocalString(),join()

末尾操作:pop()删除最后一个元素,push()在末尾增加一个元素

首位操作:shift()删除第一个元素,unshift()在守卫增加一个元素

重排序和翻转数组:resverse(),sort()

合并数组:concat()

数组截取(浅拷贝)方法:slice(),不会改变原数组

数组修改:splice(),改变了原数组

数组归并方法:reduce()

8.forEach和map的区别?

forEach方法,数组中的每一个元素都会执行提供的函数,会改变原数组,没有返回值。

map方法,会返回一个新数组,不会改变原数组,新数组里面的值是原数组中的元素执行提供函数

所返回的值

9.for与forEach区别?

        1.for循环可以使用break跳出循环,但forEach不能。

        2.for循环可以控制循环起点(i初始化的数字决定循环的起点),forEach只能默认从索引0开

        3.for循环过程中支持修改索引(修改 i),但forEach做不到(底层控制index自增,无法左右

它)

10.Promise的方法?

(1)then()方法:

可以接收两个回调函数作为参数,第一个回调函数当Promise对象的状态变为Resolved的时候调

用,第二个回调函数当Promise对象的状态变为Rejected的时候调用。第二个参数可以省略,

then()方法返回的是一个新的Promise实例,因此可以使用then()的链式调用。

(2)catch()方法:

可以接收一个回调函数作为参数,当Promise对象的状态变为rejected的时候调用,相当于then()方

法的第二个回调函数。

(3)all()方法:

可以接收一个数组作为参数,数组中的每一个元素都是一个Promise对象,只有当数组中的每一个

Promise对象的状态都变为Resolved的时候,all()的状态才会变为Resolved。只要有一个Promise

对象的状态是Rejected,all()的状态就是Rejected。

当所有的子Promise对象执行完,all()的状态为resolved的时候,返回值是一个数组,数组按顺序输

出每一个Promise对象resolve()的返回值。当有任何一个Promise失败,返回值就是第一个失败的

Promise对象的结果。

(4)race()方法:

race()方法和all()方法一样,接受的是一个数组,数组里面的元素都是Promise对象,与all()不同的

是,根据子Promise对象第一个返回的状态来决定race()方法的状态。如果第一个Promise的状态变

成了resolved,那么race()自身的转台就变成了resolved,反之则是rejected

(5)finally()方法:

不管最后的状态是什么,都要执行finally()方法。

11.对闭包的理解?

闭包就是指有权访问另一个函数作用域中变量的函数。创建闭包最常见的方式就是在一个函数中创

建另一个函数,创建的函数可以 访问当前函数中的变量。

优点:

        可以重复使用变量,并且不会造成变量污染。

缺点:

        会引起内存泄漏(解决:在退出函数之前,将不使用的局部变量全部删除)

12.对作用域和作用域链的理解?

作用域:

(1)全局作用域:

在最外面函数和最外面函数外层声明的变量可以称为全局变量。

被定义但是没有被声明的变量也被称为全局变量。

window身上的属性也被称为全局变量。

(2)局部作用域:

一般在函数内部声明的变量被称为局部变量,局部作用域是分层级的,内层的可以访问外层的,反之则不行。

(3)块级作用域:

ES6新增的let和const关键字,可以生命块级作用域,一般在一个代码块中使用。

let和const声明的变量没有变量提升,不可以被重复声明。

块级作用域一般在循环中使用,可以把循环的变量限制在循环内部。

作用域链:

在当前作用域里查找变量,如果查找不到的话就到父级作用域查找,还查找不到的话就依次向上一

级作用域查找变量,知道查找到window身上即可,这一层层的关系就叫做作用域链。

12.对象继承的方式有哪些?

(1)构造函数的继承(call/apply):call和apply可以改变某个函数的this指向,父类:Animal,子类:Cat,

在子类构造函数中Animal.call(this)

(2)原型继承:子类原型=父类实例 Cat.prototype=new Animal()

        优点:可以继承 父类的所有 (自身+原型)

        缺点:不可以 动态的给 父类 构造函数 传参数

  <script>
    // 父类
    function Father(name, sex) {
      this.name = name
      this.sex = sex
    }

    Father.prototype.say = function() {
      console.log('会说四川话了')
    }


    // 定义子类
    function Son() {}
    Son.prototype = new Father('王', '男')
    var one = new Son()
    console.log(one, one.name, one.sex)
    one.say()
  </script>

(3)类继承:extends,super(可以继承父类构造函数) class Son extends Father{}

(4)组合继承

14.ES6新特性有哪些?

(1)const/let/var

相同点:三者都可以用于声明变量

不同点:

let

特性:

        1.let 不能重复声明变量,var 可以重复声明变量;

        2.let 定义变量,可先声明,后赋值

        3.使用let定义的边量存在块级作用域,只能在{ }中使用

const

特性:

       1.const 用于定义常量 ,需要在声明的同时赋值

        2.使用let定义的边量存在块级作用域,只能在{ }中使用

var

特性:

        1.var定义的变量,在全局范围内都可以使用,但是容易造成全局变量的污染,用于全局作用

域,不推荐

        2.全局作用域的理解:在全局范围内都可以使用

        3.利用 var 所定义的变量,利用声明方式定义的函数,存在“声明提升”的现象(在 JS 引擎中

执行 JS 时的预解析过程)。在执行 JS 代码时,会先将所有使用 var 所定义的变量的声明部分提

升到对应作用域的最顶部(赋值部分仍保留在原位置)。对于函数,如果是使用声明方式定义的函

数(function 函数名(){} 这种方式),会将函数整体提升到对应作用域的最顶部,对于函数表达式

方式定义的函数,只提升声明部分,不提升函数主体。

(2)结构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值

数组的结构

        const Web = ['苹果', '华为', '小米']
        let [tool1, tool2, tool3] = Web
 
        console.log('tool1-----', tool1) // 苹果
        console.log('tool2-----', tool2) // 华为
        console.log('tool3-----', tool3) // 小米

对象的结构

     const liMing = {
            name: 'liMing',
            age: '22',
            tell: function(){
                console.log(`hello world`)
            }
        }
 
        let {name, age, tell} = liMing
 
        console.log(name) // 'liMing'
        console.log(age) // '22'
        console.log(tell) // f(){...}
        tell() // hello world

(3)模板字符串

特性:

``(反引号)内容中可以直接出现换行符

可以使用${exprision}进行变量的拼接

<html>
<body>
 
<h2>JavaScript 模板字面量</h2>
 
<p>模板字面量允许字符串中的变量:</p>
 
<p id="demo"></p>
 
<p>Internet Explorer 不支持模板字面量。</p>
 
<script>
let firstName = "Bill";
let lastName = "Gates";
 
let text = `Welcome ${firstName}, ${lastName}!`;
 
document.getElementById("demo").innerHTML = text;
</script>
 
</body>
</html>

(4)简化对象的写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法(在属性名和变量名相同

的情况下),这样的书写更加简洁

        let name = 'LiMing'
        let tell = function(){
            console.log('I am LiMing')
        }
 
        const liMing = {
            name,
            tell,
            sayHi(){
                console.log('hello')
            }
        }
        // 等效于
        // const liMing = {
        //     name: name,
        //     tell: tell,
        //     sayHi: function(){
        //         console.log('hello')
        //     }
        // }
 
 

(5)箭头函数

是普通函数的简写形式,没有自己的 this、arguments、super、new.target 等

箭头函数与普通函数的区别:

1.箭头函数没有自己的this,在普通函数中,this总是指向调用它的对象

2.箭头函数不用用于构造函数

 let Person = (name, age)=>{
            this.name = name
            this.age = age
        }
 let meInfo = new Person('xiaojian', 18) // 报错:Uncaught TypeError: Person is not a constructor

3.箭头函数不能使用arguments变量,但是可以使用....rest

let fn = ()=>{
   console.log(arguments)
}
 
fn(1, 2, 3) // 报错:Uncaught ReferenceError: arguments is not defined
        
let fn2 = (...rest)=>{
    console.log(...rest)
}
 
fn2('a','b','c') // a b c

4.箭头函数不具有prototype原型对象,不具有super,不具有new.target

5.箭头函数的简写形式

        当形参有且只有一个的时候,可以省略();

  当代码体只有一条语句的时候,可以省略{},此时return必须省略,而且语句的执行结果就是

函数的返回值;

// 当只有一个参数时,圆括号是可选的:
const abc = functiong(a){
    return a*a
}
// ==> 
const abc a => {
    return a*a
}
 
const add = function(a, b) {
    return a + b
}
// ==>
const add = (a, b) => {
    return a + b
}
// ==> 
const add = (a, b) => a + b

(6)函数参数的默认值设置

ES6允许给函数参数赋初始值

function add(a, b, c=10){ // 具有默认值的参数,一般位置要靠后
   return a + b + c
}
console.log(add(1,2,))

(7)rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments

// ES5获取实参的方式
function printStudent(){
   console.log(arguments) // arguments为一个对象
}
printStudent('xiaojian','xiaohua')
 
// ES6获取实参的方式
function printFriend(friend1, friend2, ...rest){ // rest参数必须放在形参列表最后,否则会报错
     console.log(friend1) 
     console.log(friend2) 
     console.log(rest) // 得到一个数组,可以使用数组api
}
printFriend('小猫','小狗','兔子','鸭子')
// 小猫
// 小狗
 // ['兔子','鸭子']

(8)展开运算符

...能将「数组」转为逗号分隔的「参数序列」

说明:虽然形式与rest参数类似,但是rest参数是用在函数定义时的形参位置,扩展运算符是用在

函数实际调用时的实参位置

const STUDENTS = ['小明','小芳','小红']
function printStudent(){
   console.log(arguments)
}
printStudent(STUDENTS) // 参数为一个数组,数组内包含3个元素
printStudent(...STUDENTS) // 参数为3个元素

(9)数组方法

常用数组方法如下:

1)indexOf(searchElement):查找数组中 searchElement 元素第一次出现的索引(下标),

如果不存在返回 -1 ;

2) lastIndexOf(search):查找数组中 search 元素最后一次出现的索引,如果不存在返回 -1;

3) forEach(callback) -- 遍历迭代数组 的每个元素,在遍历每个元素时,调用 callback 执行函数体

语句块。没有返回值

4) map(callback) -- 遍历迭代数组的每个元素,返回一个新数组,新数组中的元素值是 callback 函

数中的返回值

5) filter(callback) -- 过滤筛选数组元素,返回一个新数组,新数组中的元素值为满足 callback 函数

条件的对应元素值

6) some(callback) -- 判断数组中是否存在满足 callback 条件的元素,返回布尔值

7) every(callback) -- 判断数组中是否每一个元素都满足 callback 条件,返回布尔值

8) find(callback) -- 查找数组中满足 callback 条件的第一个元素,返回查找到的元素值,找不到返

回 undefined

9) findIndex(callback) -- 查找数组中满足 callback 条件的第一个元素的下标,返回下标值,找不到

返回 -1

以上几个方法的参数 callback 为函数结构:

function(currentValue, index, array) {
    // currentValue 表示当前遍历到的元素值
    // index 表示当前遍历到的元素下标
    // array 表示调用当前方法的数组
}

10) reduce(callback, init) 从前向后遍历

reduce方法主要实现归并(累计),callback 结构:

function(result, currentValue, index, array) {
    // result 中保存累计结果
    // currentValue 表示当前遍历到的元素值
    // index 表示当前遍历到的元素下标
    // array 表示调用当前方法的数组
}
 
init 参数为 callback 函数中 result 的初始值,如果不传递 init 参数,使用数组的第一个元素作为 result 的初始值。

11)includes(val):判断在数组中是否存在参数表示的元素,返回 boolean 值。如果包含则返回

true,否则返回false。

12)Array.isArray():判断参数是否为数组(面试经常提问如何判断一个表达式是否为数组)

13)数组扁平化

15.数组运用?

1)数组降序

// 降序
// 使用数组的sort方法
var numberArray = [3,6,2,4,1,5]
numberArray.sort(function(a,b){return b-a})
console.log(numberArray); // 6,5,4,3,2,1
 
// 降序
const arr= [95, 87, 62, 92, 73, 93,60, 59]
    for(let i = 0; i < arr.length - 1 ; i++) {
      for(let j = 0; j < arr.length - 1 -i; j++) {
        if(arr[j] < arr[j+1]) {
          const temp = arr[j]
          arr[j] = arr[j+1]
          arr[j+1] = temp
        }
      }
    }
console.log('排序后:', arr)
 
// 升序
// 使用数组的sort方法
var newArray = [3,6,2,4,1,5]
newArray.sort(function(a,b){return a-b})
console.log(newArray); //1,2,3,4,5,6
 

2)数组去重

// 方法一
const array = [8, 5, 2, 8, 7, 4, 3, 8, 9, 2, 4, 7, 6, 3, 5, 4, 9, 6, 2]
     const abc = []
     array.forEach(function(curr) {
       if(abc.indexOf(curr) === -1) {
         abc.push(curr)
       }
     })
console.log('去重后:', abc)
 
//方法二
const array = [8, 5, 2, 8, 7, 4, 3, 8, 9, 2, 4, 7, 6, 3, 5, 4, 9, 6, 2]
     const abc = []
     array.forEach(function(ccc) {
      //  if(abc.includes(ccc) === false) {
      //    abc.push(ccc)
      //  }
      if(!abc.includes(ccc)) {
        abc.push(ccc)
      }
     })
console.log('去重后:', abc)
 
// 方法三
  const array = [8, 5, 2, 8, 7, 4, 3, 8, 9, 2, 4, 7, 6, 3, 5, 4, 9, 6, 2]
    const abc = array.reduce(function(result, curr) {
      if(!result.includes(curr)) {
        result.push(curr)
      }
      return result
    }, [])
console.log('去重后:', abc)

3)数组扁平化

const arr = [1, [2, 3, [4, 5]]] 
 
//第一种方法:使用数组和字符串的方法先把多维数组转化为字符串,在用字符串的split以指定的付号
//转化为数组,在通过数组的map方法把元素进行类型转换形成新的数组
 function flatten(arr) {
   return arr.toString().split(',').map(function(item) {
     return Number(item)
   })
 }
 
//第二种方法:使用数组的join(',')将数组转换字符串,再用字符串的split(',')方法将字符串转化为数组
//再通过数组的map方法把元素进行遍历,通过Number把遍历的返回值转化为数字
 function flatten(arr) {
   return arr.join(',').split(',').map(function(item) {
     return Number(item)
   })
 }
 
//使用reduce + 递归 实现数组的扁平化
  function flatten(arr) {
    return arr.reduce((result, item) => {
      return result.concat(Array.isArray(item) ? flatten(item) : item )
    }, [])
  }
 
    
const flatten = (arr) => {
     let result = [];
     for (let i = 0; i < arr.length; i++) {
       if (Array.isArray(arr[i])) {
        result = result.concat(flatten(arr[i]));
       } else {
         result.push(arr[i]);
       }
     }
     return result;
   };

console.log(flatten(arr))

4)一维数组转化为转化为特定的几维数组

<script>
    var fromArr = [1,2,3,4,5,6,7,8,9,10,11];
    var mountOfLine = 5;  
    var data = fun(fromArr,mountOfLine);
    console.log('data   ',data)
    /**
     *
     * @param fromArr  需要转换的一维数组(源数组)
     * @param mountOfEachLine  目标数组内的子数组元素个数(例:若要的到这样的结构 -> [[1,2],[3,4],[5,6],[7,8],[9,10]] , 则mountOfLine = 2)
     * @returns newArr 数据结构样式 -> [[1,2],[3,4],[5,6],[7,8],[9,10]]
     */
     function fun(fromArr,mountOfEachLine) {
        //装二维数组的容器(目标数组)
        let newArr = [];
        //源数组元素个数 
        let len = fromArr.length;
        //计算出指定好的 mountOfLine 源数组能分成几个子数组
        let lineNum =  len % mountOfEachLine == 0 ? len / mountOfEachLine : Math.ceil(len / mountOfEachLine);
        //将源数组的元素拿出来,放到新数组 newArr 容器内
        for (let i = 0; i < lineNum; i++) {
            let tempElement = fromArr.slice(i*mountOfEachLine,(i+1)*mountOfEachLine);
            newArr.push(tempElement);
        }
        return newArr;
    }
</script>

16.什么是同步任务?什么是异步任务?

同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。

异步任务指的是,不进入主线程、而进入"任务队列"的任务,只有等主线程任务执行完毕,"任务队

列"的任务才会进入主线程执行。

异步任务又任务宏任务(settimeout,setInterval )和微任务(promise, async await)

执行顺序:先执行同步任务,再执行当前所有的微任务,然后执行一个宏任务,然后再执行所有的

微任务。再执行一个宏任务。再执行所有的微任务·······依次类推到执行结束。

17.JavaScript原型,原型链的理解?

原型

        原型分为隐式原型_proto_和显示原型prototype,每个对象都有他的隐式原型_proto_,指向

它构造函数的显示原型prototype.

        无论何时,只要创建一个函数,就会为这个函数添加一个prototype属性,这个属性指向原型

对象。

        构造函数的prototype指向原型对象,原型对象有一个constructor属性指向构造函数,每个构

都有一个造函数的实例_proto_属性,这个属性也指向原型对象

原型链:

        每个对象都有 __proto__ 属性,这个属性指向原型对象,当想访问对象的一个属性时,如果

这个对象本身没有这个属性就会通过__proto__属性 查找,原型对象也是对象,每个对象又有自己

的 __proto__ 属性,所以就会一直这样查找上去,直到找到这个属性,这就是原型链的概念。

        原型链就是对象沿着 __proto__ 这条链逐步向上搜索,最顶层是 Object,Object

的 __proto__ 是 null

18.http状态码的了解?

2开头表示请求成功

        200表示一切正常

3开头的便是重定向

        301表示永久重定向

        302表示临时重定向

4开头表示客户端错误

        400表示请求报文中存在语法错误

        401请求授权失败

        403表示跨域

        404表示请求资源不存在

5开头表示服务器端错误

        500表示服务器在执行请求时发生了错误

19.call apply和bind的区别

共同点:

        都是用来改变函数的this对象的指向的。

        第一个参数都是this要指向的对象。

        都可以参加后续参数传参

不同点:

        bind是返回对应函数,便于稍后调试,apply, call则是立即调用

        apply和call功能一样,只是传入的参数列表形式不同,call需要把参数按顺序传递进去,而

apply则是要把参数放在数组,伪数组里

使用示例:

apply:

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。

var name="martin";
    var obj={
      name:"lucy",
      say:function(year,place){
      console.log(this.name+" is "+year+" born from "+place);
      }
    };
    var say=obj.say;
    setTimeout(function(){
      say.apply(obj,["1996","China"])
      } ,0); 

    //lucy is 1996 born from China,this改变指向了obj
    say("1996","China") 

    //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向

call:

call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。

var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10

bind:

Function.prototype.bind=function () {
 var _this=this;
 var context=arguments[0];
 var arg=[].slice.call(arguments,1);
 return function(){
 arg=[].concat.apply(arg,arguments);
 _this.apply(context,arg);
 }
 };

20.输入url到页面打开都做了什么事情?

        输入url;

        DNS解析;

        TCP握手;

        HTTP请求;

        HTTP响应返回数据;

        浏览器解析并渲染页面

20.this指向问题?

1.任何情况下直接在script中写入的this都是window。

2.普通函数中的this 非严格模式:this指向window, 严格模式时:this指向undefined。

function fn() {
   console.log(this);   // window
 }
 fn();  //  window.fn(),此处默认省略window

3.箭头函数没有自己的this,其this指向与外层函数的this指向相同。

4.对象中的this

        对象属性的this 指向对象外上下文环境的this

        对象方法(普通函数)中的this,指向当前对象(谁执行该方法,this就指向谁)

5.回调函数的this指向

         1)setTimeout, setInterval回调函数不管是否是严格模式都会指向window

        2)  通过在含糊内执行当前回调函数  非严格模式:this指向window, 严格模式: this指向

undefined

        3)  递归函数中的this  非严格模式:this指向window, 严格模式: this指向undefined,

        4)  使用arguments执行函数时this指向arguments

        5)  事件中的回调函数, this指向事件侦听的对象的对象(e.currentTarget)

6、在ES6的类中this的指向

        构造函数中的this指向实例当前所产生的的新的实例对象

        类中实例化方法中的this指向谁执行该方法,this指向谁

        类中静态方法中this执行该类或者该类的构造函数

        类中实例化箭头方法,this仍然指向当前类实例化的实例对象

7.ES5的原型对象中this的指向

在原型的方法中,this指向实例化当前构造函数的实例化对象

三种改变this指向的方式

        函数名.call(this,...)this写谁就指谁

        函数名.apply(this, [参数1,参数2,...])this写谁就指向谁

        函数名.bind(this, 1, 2, 3)this写谁就指向谁

8.构造函数中this指向问题

// 构造函数中this指向问题
    function Person(age, name) {
         this.age = age;
         this.name = name
         console.log(this)  // 此处 this 分别指向 Person 的实例对象 p1 p2
     }
    var p1 = new Person(18, 'zs')
    var p2 = new Person(18, 'ww')

21.cookie, localStorage,sessionStorage 的区别?

cookie

        可存储的数据有限,一般为4KB左右,超出的数据会被忽略

localStorage

        数据永久保存,除非用户手动清理客户端缓存,一般为5M

seesionStorage

        数据保存当前回话,刷新页面数据不会被清理,结束会话(关闭浏览器,关闭页面,跳转页

面)数据失效,一般5M左右,个浏览器的存储空间有差异,同页面不同窗口数据不会共享

 22.函数的节流和防抖?

节流是指当一个事件触发的时候,为防止事件的连续频繁触发,设置定时器,达到一种一段事件内只触

发一次的效果,在当前事件内不会再次触发,当前事件结束以后,再次触发才有效.

function thro(cb,wait){
  let timeOut
  return function(){
    if(timeOut) return
    timeOut = setTimeout(function(){
      cb()
      clearTimeout(timeOut)
      timeOut = null
    },wait)
  }
}

防抖是指当一个事件触发的时候, 为防止频繁触发事件, 设置定时器,以达到一种 频繁触发期间不处

理, 只有当最后一次连续触发结束以后才处理

function debounce(cb,wait){
	let timer
  return function(){
    clearTimeout(timer)
    timer = setTimeout(()=>cb(),wait)
	}
}

23.设计模式有哪些?

共23种设计模式,介绍其中6种应用较为广泛的模式。

       发布订阅模式:该设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护

        单例模式:该设计模式保证一个类只有一个实例,并提供一个访问它的全局访问点

        工厂模式:该模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类,该

模式使一个类的实例化延迟到子类,而子类可以重写接口方法以便创建的时候指定自己的对象类型

        装饰者模式:该模式能够在不改变对象自身的基础上,在程序运行期间给对象动态的添加方

法或者属性,与继承相比,装饰者模式是一种更轻便灵活的做法

        中介者模式:观察者模式通过维护一堆列表来管理对象间的多对多关系,中介者模式通过统

一接口来维护一对多的关系,且通信者之间不需要知道彼此的关系,只需要约定好API即可

        代理模式:为其他对象提供一种代理以控制对这个对象的方法,代理模式使得代理对象控制

具体对象的引用,代理几乎可以是任何对象:文件,资源,内存中的对象或者是一些难以复制的东

西

24.http的理解?

HTTP 协议是超文本传输协议,是客户端浏览器或其他程序“请求”与 Web 服务器响应之间的应用

层通信协议。

 HTTPS主要是由HTTP+SSL构建的可进行加密传输、身份认证的一种安全通信通道。

25.http与https的区别?

1)https协议需要到ca申请整数,一般免费整数较少,因而需要一定的费用

2)http是超文本传输协议,信息是明文传输,而https则是具有安全性的ssl加密传输协议

3)http和https使用的是完全不同的连接方式,用的端口号也不一样,前者是80,后者是443

4)http的连接很简单,是无状态的;https协议是由ssl+http协议构建的可进行加密传输,身份认证

的网络协议,比http协议安全

26.什么是三次挥手和四次握手?

三次握手是网络客户端跟网络服务器之间建立连接,并进行通信的过程。相当于客户端和服务器之

间你来我往的3个步骤。

        第一次握手是建立连接,客户端发送连接请求报文,并传送规定的数据包;

        第二次握手是服务器表示接收到连接请求报文,并回传规定的数据包;

        第三次握手是客户端街道服务器回传的数据包后,给服务器再次发送数据包。

四次挥手表示当前这次连接请求已经结束,要断开这次连接

        第一次挥手是客户端对服务器发起断开请求;

        第二次挥手是服务器表示接收到这次断开请求;

        第三次挥手是服务器表示已经断开连接;

        第四次挥手是客户端断开连接。

猜你喜欢

转载自blog.csdn.net/xiaojian044/article/details/130210109
今日推荐