js学习总结(待补充)

1.JS中有哪些数据类型?

答:基本数据类型(String、Number、Boolean、Undefined、Null、Symbol)、引用数据类型(Object)

2.对象(数组)的深克隆和浅克隆

let obj = {
       a:100,
       b:[10,20,30],
       c:{
          x:10
       },
       d:/^\d+$/
};

let arr = [10,[100,200],{
      x:10,
      y:20
}];

 深克隆方案:

function deepClone(params={}){
     if(typeof params !== 'object'){
          return params
     }
      if(params == null){
          return null
     }
     if(params instanceof RegExp){
          return new RegExp(params)
     }
      if(params instanceof Date){
          return new Date(params)
     }
      let result = new params.constructor
      for(key in params){
          if(params.hasOwnProperty(key)){
                result[key] = deepClone(params[key])
          }
      }
       return result  
}    

 

3.堆栈内存和闭包作用域面试题

堆:存储引用类型值的空间

栈:存储基本类型值和指定代码的环境

let a={},b='0',c=0
a[b] = '水'
a[c] = '火'
console.log(a[b])

答:火,对象的属性名中数字和字符串等效

let a ={},b=Symbol('1'),c=Symbol('1')
a[b]='水'
a[c] = '火'
console.log(a[b])

答:水,Symbol的特点,都是唯一的

let a={},b={n:'1'},c={m:'2'}
    a[b]='水'
    a[c] = '火'
    console.log(a[b])

答:火,key会转化成字符串[Obejct object],Object.prototype.toString / valueOf

var test = (function(i){
      return function(){
        alert(i*=2)
      }
    })(2)
    test(5)

答:‘4’     这题涉及了闭包和立即执行函数(IIFE)以及执行上下文,alert弹出的结果都要转化为字符串

var a = 0,
        b = 0
    function A(a){
      A = function(b){
        alert(a + b++)
      }
      alert(a++)
    }
    A(1)
    A(2)

答:‘1’,‘4’  解析:a++表示先展示a,再自增,全局的ab和函数里的ab没关系

4.谈谈你对闭包的理解?

答:当一个嵌套的内部(子)函数访问了嵌套的外部(父)函数的变量(函数)时,就产生了闭包,延长了局部变量的生命周期,又不会造成全局污染,但是占用内存较多,不易被释放。在防抖和节流中会用到闭包。

5.什么是执行上下文和执行上下文栈?

答:全局执行上下文和全局执行上下文栈(在执行全局代码前将window确定为全局执行上下文对象,对全局数据进行预处理,添加为window的属性和方法,给this赋值,然后将window对象压入栈中,代码执行完毕后出栈,回收执行上下文),函数执行上下文和函数执行上下文栈(在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象,对局部数据进行预处理,压入对应的栈中,函数执行完毕后放出对象,回收执行上下文)

6.什么是作用域和作用域链?

答:作用域:是一段代码所在的区域,控制着变量和函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期,分为全局作用域和函数作用域以及ES6的块作用域。

作用域链:多个上下级关系的作用域形成的链,它的方向是从下到上的(从内到外),查找变量时就是沿着作用域来查找的。

7.作用域和执行上下文有什么区别?

答:和执行上下文不同,作用域在函数定义时就确定了,且作用域是静态的,只要函数定义好了就一直存在,且不会再变化。而执行上下文环境是动态的,调用函数时创建,函数调用结束时执行上下文环境就会自动释放。

8.深拷贝和浅拷贝的实现原理,以及为什么要深拷贝?

答:深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型来说的,浅拷贝只是复制指向某个对象的指针,新旧对象还是共享同一块内存,而深拷贝会在栈中开辟一个新内存,创造出一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。同一个Array或者Object赋值给两个不同变量时,变量指向的是同一个内存地址,是浅拷贝,而大多数实际项目中,我们想要的结果是两个变量(初始值相同)互不影响,所以就要使用到深拷贝。

9.typeof和instanceof的区别?

答:typeof用于判断数据类型,返回值为6个字符串,分别为stringBooleannumberfunctionobjectundefined。但是typeof在判断nullarrayobject及函数实例时,得到的都是object。这使得在判断这些数据类型的时候,得不到真是的数据类型,由此引出instanceof,instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值。

10.如何区别Object和Array?

数组表示有序数据的集合,对象表示无序数据的集合。通过instanceof、isArray方法来区分Object和Array。

 11.一道面向对象面试题?

function Foo(){
      getName = function(){
        console.log(1)
      }
      return this
    }
    Foo.getName = function(){
      console.log(2)
    }
    Foo.prototype.getName= function(){
      console.log(3)
    }
    var getName = function(){
      console.log(4);
    }
    function getName() {
      console.log(5);
    }
    Foo.getName()
    getName()
    Foo().getName()
    getName()
    new Foo.getName()
    new Foo().getName()
    new new Foo().getName()

答:2,4,1,1,2,3,      涉及变量、函数提升,执行上下文,原型和原型链,运算符优先级,this,new方法

12.谈谈你对原型和原型链的理解?

答:每个构造函数一旦创建都有prototype指针指向它的原型对象(构造函数.prototype)。而原型对象(构造函数.prototype)会默认生成一个constructor指针又指向构造函数。在创建该构造函数的实例时,实例有一个内部属性__proto__指向该原型对象。原型对象内创建的所有方法属性会被所有实例共享。而构造函数的原型对象作为一个对象实例,它的__proto__指针就指向Object的原型对象,这样就形成了一个原型链,当实例对象查找一个属性或者方法时,自身如果没有就会通过__proto__在原型链上一级一级的查找,找到了就返回,如果没有找到就返回undefined。

13.谈谈对this的理解?

答:解析器在调用函数时,每次都会向函数内部传递进一个隐含的参数,这个参数就是this,this指向的是一个对象,我们称之为函数执行的上下文对象,根据函数调用方式的不同,this会指向不同的对象,以函数的形式调用时,this永远都是window,以方法的形式调用时,this就是调用方法的那个对象,箭头函数是没有this,箭头函数里的this指向的是外面的第一个不是箭头函数的函数的this,如果没有,就是window。可以利用call,apply,bind改变this。

14.用js实现new方法?

function Person(name,age){
      this.name = name
      this.age = age
    }
    Person.prototype.sayName = function(){
      console.log(this.name)
    }
    function New(func){
      return function(){
        var o = {__proto__:func.prototype}
        func.apply(o,arguments)
        return o
      }
    }
    const child = New(Person)('大雄',15)
    child.sayName()

15.一道面试题让你彻底掌握JS中的EventLoop

    async function async1(){
      console.log('async1 start');
      await async2()
      console.log('async1 end');
    }
    async function async2(){
      console.log('async2');
    }
    console.log('script start');
    setTimeout(() => {
      console.log('setTimeout');
    }, 0);
    async1()
    new Promise(function(resolve){
      console.log('promise1');
      resolve()
    }).then(function(){
      console.log('promise2');
    })
    console.log('script end');
    // script start
    // async1 start
    // async2
    // promise1
    // script end
    // async1 end
    // promise2
    // setTimeout

涉及知识点:同步异步、微队列宏队列、async和await、Promise

16.面试题

setTimeout(() => {
      console.log(1);
    }, 20);
    console.log(2);
    setTimeout(() => {
      console.log(3);
    }, 10);
    console.log(4);
    console.time('AA');
    /* for (let i = 0; i < 90000000; i++) {
      
    }
    console.timeEnd('AA'); */
    console.log(5);
    setTimeout(() => {
      console.log(6);
    }, 8);
    console.log(7);
    setTimeout(() => {
      console.log(8);
    }, 15);
    console.log(9);
    //2 4 5 7 9 3 1 6 8 有循环
    //2 4 5 7 9 6 3 8 1 无循环

关键点:多个setTimeout进入宏队列后,出来的顺序是由延迟时间来决定的

var x = 2
    var y = {
      x:3,
      z:(function(x){
        this.x*=x
        x+=2
        return function(n){
          this.x*=n
          x+=3
          console.log(x);
        }
      })(x)
    }
    
    var m = y.z
    m(4) //7
    y.z(5)//10
    console.log(x,y.x);//16,15

关键点:在函数内部this.x表示全局变量x,x表示局部变量,x+=3先在函数内部找x,函数内部没找到就沿着作用域找,一直到全局作用域,找到后返回,得到的值会成为局部变量x的值。

17.JS中DOM节点的插入操作有哪些?

appendChild、insertBefore(a,b)

18.如何解决跨域?

答:jsonp跨域(利用了标签发送GET请求“天然跨域”,不受同源策略的限制,但是只能解决GET请求跨域问题)

  cors跨域(在后台的每个ajax路由中加入response.set('Access-Control-Allow-Origin','http://127.0.0.1:8848'))

  nginx跨域

  proxy跨域(利用http-proxy-middleware中间件设置代理浏览器实现跨域)

19.防抖(debounce)与节流(throttle)区别与实现?

答:防抖(触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间)

    const debounce = (fn,time) =>{
      let timeout = null
      return function(){
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          fn.apply(this,arguments)
        }, time);
      }
    }

节流(高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。)

const throttle = (fn, time) => {
  let flag = true;
  return function() {
    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      flag = true;
    }, time);
  }
}

20.冒泡和捕获?

答:

冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点

捕获:和冒泡恰恰相反,事件捕获流的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件

DOM2级事件流包含三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段

阻止事件冒泡(e.stopPropagation()和IE的e.cancelBubble = true)

阻止默认行为(e.preventDefault()以及IE使用e.returnValue = false)

21.用js实现一个promise?

function MyPromise(excutor){
    this.status = 'pending'
    this.data = undefined
    this.calbacks = []
    let resolve = (value) =>{
      if(this.status !== 'pending'){
          return
      }
       this.data = value
       this.status = 'resolved'
       if(this.calbacks.length>0){
          setTimeout(()=>{
              this.calbacks.forEach(calbacksObj =>{
                  calbacksObj.onResolved(value)
               })
          })
       }
    }
    let reject = (reason) =>{
        if(this.status === 'pending'){
            return
        }
        this.data = reason
        this.status = 'rejected'
        if(this.calbacks.length>0){
            setTimeout(()=>{
              this.calbacks.forEach(calbacksObj=>{
                  calbacksObj.onRejected(reason)
               })
            })
        }
    }
    try{
       excutor(resolve,reject)
    }catch(error){
       reject(error)
    }
}
Promise.prototype.then = function(onResolved,onRejected){
  const self = this
  onResolved = typeof onResolved === 'function' ? onResolved : value=>value
  onRejected = typeof onRejected === 'function' ? onRejected : reason => 
  {throw reason}
  function handle(calback){
    try{
      const result = calback(self.data)
      if(result instanseof Promise){
          result.then(resolve,reject)
      }else{
          resolve(result)
      }
    }catch(err){
        reject(err)
    }
  }
  return new Promise((resolve,reject)=>{
    if(this.status === 'pending'){
        this.calbacks.push({
          onResolved(value){
              handle(onResolved)
          },
          onRejected(reason){
              handle(onRejected)
          }
        })
    }else if(this.status === 'resolved'){
        setTimeout(()=>{
            handle(onResolved)
        })
    }else{
        setTimeout(()=>{
           handle(onRejected)
        })
    }
  })
}
Promise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}
Promise.resolve = function(value){
  return new Promise((resolve,reject)=>{
      if(value instanceof Promise){
        value.then(resolve,reject)
      }else{
        resolve(value)
      }
  })
}
Promise.reject = function(reason){
  return new Promise((resolve,reject)=>{
    reject(reason)
  })
}
Promise.all = function(promises){
     const values = new Array(promises.length) //用来保存所有成功value的数组
     let resolveCount =0
     return new Promise((resolve,reject)=>{
         //遍历promises获取每个promise的结果
         promises.forEach((p,index)=>{
             Promise.resolve(p).then(
                value =>{
                    resolveCount++
                    values[index] = value
                    
                    //如果全部成功了,将return的promise改为成功
                    if (resolveCount === promises.length) {
                        resolve(values)
                    }
                },
                reason =>{//只要一个失败,return的promise就失败
                    reject(reason)
                }
             )
         })
     })
 }
Promise.race = function(promises){
     //返回一个promise
     return new Promise((resolve,reject)=>{
         //遍历promises获取每个promise的结果
         promises.forEach((p,index)=>{
             Promise.resolve(p).then(
                value =>{//一旦有成功的,将return变为成功
                    resolve()
                },
                reason =>{//一旦有失败的,将return变为失败
                    
                }
             )
         })         
     })
 }

22.post请求和get请求的区别?

答:1.GET把参数包含在URL中,POST通过request body传递参数

2.Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制

23.localStorage、sessionStorage和cookie的区别?

答:1、cookie数据始终在同源的http请求中携带,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。

2、cookie存储数据不会超过4k,而sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。

3、sessionStorage只在当前浏览器窗口关闭之前存在,localStorage始终有效,窗口或浏览器关闭也一直保存,cookie只在设置的cookie过期时间之前有效。

24.简述ajax的过程?

答:实例化一个xhr对象,连接服务器,准备数据(xhr.open),发送请求(xhr.send),监听状态变化,接收服务器返回。

25.宏任务和微任务?

答:宏任务(整体script,setTimeout,setInterval)微任务(Promise,process.nextTick)

当主线程的同步任务执行完毕后,先执行宏任务,将宏任务放入宏任务的eventqueue,然后执行所有微任务,将微任务放入到微任务的eventqueue。但是当往外拿回调函数时是先拿微任务的,其次是宏任务的。

26.数组的常用方法?

答:

改变原数组的方法:splice(添加/删除)、pop(删除数组的最后一个元素)、push(向数组末尾添加元素)、shift(删除数组的第一个元素)、unshift(向数组开头添加元素)、reverse(颠倒数组中元素位置)、sort(数组排序)

不改变原数组的方法:slice(浅拷贝数组的元素,选取一个或多个元素)、join(将数组转换为有一个字符串)、concat(合并数组)、indexOf(查找数组中是否存在某个元素)、lastIndexOf(查找元素在数组中的最后一位)、findIndex(查找数组中给定值的索引,没有就返回-1)、every(如果数组中的每个元素都符合条件,则返回true,否则为false)、some(和every正好相反,只要有一个符合就返回true)、includes(类似some,但是不是用回调,直接给一个参数值比较就可以了)

数组的遍历方法:forEach(遍历数组并不改变原数组)、map(数组中元素为对象时使用,返回每个元素中的某个属性形成新数组)、filter(遍历数组,返回符合条件的元素形成新数组)、reduce(通过初始值遍历数组,累加得到最终值)、for of

 27.怎么实现数组去重?

const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];

双重for循环+splice

const unique1 = arr => {
  let len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1);
        // 每删除一个树,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能
        len--;
        j--;
      }
    }
  }
  return arr;
}

ndexOf方法去重(for)

const unique2 = arr => {
  const res = [arr[0]];
  for (let i = 1; i < arr.length; i++) {
    if (res.indexOf(arr[i]) === -1) res.push(arr[i]);
  }
  return res;
}

indexOf方法去重(Array.prototype.filter.call

    const uniq = arr => {
      return Array.prototype.filter.call(arr,function(item,index){
        return arr.indexOf(item) === index
      })
    }
    
    console.log(uniq(arr));

set与解构赋值去重(利用ES6中set数据不重复的特性,Set函数可以接收一个数组参数进行初始化进行去重,然后通过结构赋值得到一个数组)

console.log([...new Set(arr)]);

Array.from与set去重(Array.from方法可以将Set结构转换为数组结果)

      const uniq = arr => {
        return Array.from(new Set(arr))
      }
      console.log(uniq(arr));        

相邻元素去重(sort排序和for循环)

    const uniq = arr => {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return;
        }
        arr = arr.sort()
        var arrry= [arr[0]];
        for (var i = 1; i < arr.length; i++) {
            if (arr[i] !== arr[i-1]) {
                arrry.push(arr[i]);
            }
        }
        return arrry;
    }
    console.log(uniq(arr));

利用includes

function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    var array =[];
    for(var i = 0; i < arr.length; i++) {
            if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
                    array.push(arr[i]);
              }
    }
    return array
}
console.log(unique(arr))

 28.数据扁平化?

const arr = [1, [2, [3, [4, 5]]], 6];

使用flat()

const res1 = arr.flat(Infinity);

利用正则

const res2 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');

使用reduce+递归

const flatten = arr => {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
  }, [])
}
const res4 = flatten(arr);

函数递归

const res5 = [];
const fn = arr => {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      fn(arr[i]);
    } else {
      res5.push(arr[i]);
    }
  }
}
fn(arr);
console.log(res5)

 29.类数组转化为数组?

答:Array.from(类数组)

Array.prototype.slice.call(类数组)

[...类数组]

Array.prototype.concat.apply([],类数组)

30.打印出当前网页使用了多少种HTML元素?

    const req = ()=>{
      return [...new 
      Set([...document.querySelectorAll('*')].map(el=>el.tagName))].length
    }
    console.log(req());

31.对象的遍历方法?

答:for in循环

for(let property in obj){
    console.log(property)
}
//在使用之前,需要加入obj.hasOwnProperty(property)检查是否是对象的自有属性

32.es6合并对象的方法?

Object.assign

let obj1 = {name:'a',age:18};

let obj2 = {name:'b',gender:'man'};

let obj3 = {};

Object.assign(obj3,obj1,obj2);

console.log(obj3);//{name: "b", age: 18, gender: "man"}

三点运算符

let obj1 = {name:'a',age:18};

let obj2 = {name:'b',gender:'man'};

let obj3 = {...obj1,...obj2};

console.log(obj3);//{name: "b", age: 18, gender: "man"}

33.常用的数组排序方法?

冒泡排序法:将数组中的相邻元素进行比较(第一次比较次数为数组length-1,依次递减),较大值通过两两比较移动到数组最末尾,然后循环比较。

    let arr = [3,1,2,4,5,7,6]
    let len = arr.length
    for (let i = len-1; i >0; i--) {
      for (let j = 0; j < i; j++) {
        if (arr[j]>arr[j+1]) {
          let temp = arr[j]
          arr[j] = arr[j+1]
          arr[j+1] = temp
        }
      }
    }
    console.log(arr);

选择排序法:从第一个元素开始,依次和后面的元素进行对比,筛选出最小值,然后将最小值和选中元素位置互换。然后结束循环,开始下一次循环。

    let arr = [3,1,2,4,5,7,6]
    let len = arr.length
    for (let i = 0; i < len-1; i++) {
      let min = i
      for (let j = min+1; j < len; j++) {
        if (arr[min]>arr[j]) {
          min = j
        }
      }
      let temp = arr[min]
      arr[min] = arr[i]
      arr[i] = temp
      
    }
    console.log(arr);

插入排序法:从第二个数组元素开始,依次和前面的元素进行对比,如比选中元素大,和选中元素互换位置,如比选中元素小,结束这次循环,开始下一次循环。

    let arr = [3,1,2,4,5,7,6]
    let len = arr.length
    for (let i = 1; i < len; i++) {
      let temp = arr[i]
      let j = i
      while (arr[j-1]>temp && j>0) {
        arr[j] = arr[j-1]
        j--
      }
      arr[j] = temp
    }
    console.log(arr);

快速排序法:选择数组首尾中三个元素从小到大排序,然后大于中间元素的元素分为一组,小于中间元素的分为一组,这两组继续上述操作,最后用concat连接

    let arr = [3,1,2,4,5,7,6]
    //变换位置
    let swap = function(arr,m,n){
      let temp = arr[m]
      arr[m] = arr[n]
      arr[n] = temp
    }
    //返回center
    let median = function(arr){
      let center = Math.floor(arr.length/2)
      let right = arr.length - 1
      let left = 0
      if (arr[left]>arr[center]) {
        swap(arr,left,center)
      }
      if (arr[center]>arr[right]) {
        swap(arr,center,right)
      }
      if (arr[left]>arr[center]) {
        swap(arr,left,center)
      }
      return center
    }
    let QuickSort = function(arr){
      if (arr.length === 0) {
        return []
      }
      let center = median(arr)
      let c = arr.splice(center,1)
      let l = []
      let r = []
      for (let i = 0; i < arr.length; i++) {
        if (arr[i]<c) {
          l.push(arr[i])
        }else{
          r.push(arr[i])
        }
      }
      return QuickSort(l).concat(c,QuickSort(r))
    }
    console.log(QuickSort(arr));

34.http和https的区别?

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

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

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

35.es6新特性?

const和let(const和let不能变量提前声明,块级作用域,let在同一块级作用域中只能重新赋值不能重新声明,const则是既不能重新赋值也不能重新声明)

模板字面量(`  `)

解构赋值

for...of循环(可以循环任何可迭代类型的数据(String、Array、Map、Let),不包括Object数据类型,默认情况下对象不能迭代)

三点运算符(如果你需要结合多个数组,在有展开运算符之前,必须使用Array的concat()方法。)

箭头函数

Promise

class

36.箭头函数和普通函数的区别?

1、箭头函数是匿名函数,不能作为构造函数,不能使用new

2、箭头函数不能绑定arguments,取而代之用rest参数

3、箭头函数没有原型属性

4、箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

37.call,apply,bind的区别?

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

38.es5和es6作用域区别?

es5只有全局作用域和函数作用域,而es6新增了块级作用域(就是{}包含的代码块),块级作用域里的变量不能在其他作用域里使用,而全局作用域的变量可以在函数作用域中使用。

39.什么是暂时性死区?

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。

40.ajax和websocket区别?

Ajax,即异步JavaScript和XML,是一种创建交互式网页应用的网页开发技术;

WebSocket是HTML5一种新的协议。

websocket建立的是长连接,在一个会话中一直保持连接;而ajax是短连接,数据发送和接受完成后就会断开连接。

websocket一般用于前后端实时数据交互,而ajax前后端非实时数据交互。

Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以相互推送信息。

41.js处理异步的方式有哪些?

1、回调函数

2、事件监听

3、Promise

4、async/await

5、setTimeout

42.如何判断当前脚本运行在浏览器还是node环境中?

通过判断Global对象是否为window,如果不是window,则当前脚本没有运行在浏览器中。

43.请解释一下JS的同源策略?

同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性。

44.class类如何创建实例?通过什么实现继承?如何调用父类的构造方法?通过什么定义构造方法?

通过new来创建类的实例

通过extends来实现类的继承

通过super调用父类的构造方法

通过constructor定义构造方法
45.说一说原型链继承和借用构造函数继承?
原型链继承:定义父类型构造函数,给父类型的原型添加方法,定义子类型的构造函数,创建父类型的对象赋值给子类型的原型,将子类型原型的constructor设置为子类型,给子类型原型添加方法,创建子类型的对象:可以调用父类型的方法。
借用构造函数继承:定义父类型构造函数,定义子类型构造函数,在子类型构造函数中通过call()调用父类型构造函数。
46.组合继承?
原型链+借用构造函数的组合继承
1.利用原型链实现对父类型对象的方法继承
2.利用call()借用父类型构造函数初始化相同属性
47.什么是Promise,我们用它来做什么?promise是用来解决什么问题的?
Promise 是异步编程的一种解决方案:它可以获取异步操作的消息,并在过一段时间会给你一个结果。
回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象。
promise.all可以支持多个并发的请求,获取并发请求中的数据
48.如果不使用promise.all应该如何解决并发问题?
创建一个变量,初始赋值为0,创建三个promise实例进行异步操作,成功则变量+1,最后判断是否为3,是就是成功,不是就是失败。

49.讲下DOM对象的三种查询方式?

getElementById()根据元素id来查找 ,getElementsByTagName(tag):根据元素的tag名字来查找

getElementsByName(name) 根据元素名字来查找

50.怎么样创建元素节点和文本节点,怎么样删除节点?

createElement("div")创建元素节点,createTextNode()创建一个文本节点,removeChild()可以用来删除节点

51.用那个属性可以快速的给一个节点加一段html内容?

innerHTML
posted @ 2020-09-22 19:11  sykeswh  阅读(61)  评论(0编辑  收藏  举报