侧边栏壁纸
  • 累计撰写 22 篇文章
  • 累计收到 1 条评论

JS

admin
2022-06-14 / 0 评论 / 4 阅读 / 正在检测是否收录...

问题

  1. New操作符做了什么?
  2. 解释一下原型?
  3. 闭包、闭包函数、闭包的特点?
  4. js内置对象?
  5. 检查数据类型的方式?
  6. Js中的Object. defineProperty?
  7. Call apply bind的作用、区别、以及应用场景?
  8. Map、foreach、forin、forof?
  9. var、let、const?
  10. 数组的常见方法?
  11. Math常见方法?
  12. 数组去重的几种方式?如果数组中的数据是对象呢?
  13. 数组的最大最小值的几种方法?
  14. 函数节流与防抖的概念?
  15. ES6新特性?
  16. ES6对象新增的方法?
  17. 函数、方法、类以及如何添加属性和方法?
  18. ES5与ES6继承的区别?
  19. 类和函数Class和function的区别?
  20. promise?
  21. async,await?
  22. Set,map,weakset,weakmap区别?
  23. 装箱和拆箱?
  24. 内存泄漏的几种情况?
  25. Json和xml?
  26. 浅拷贝深拷贝?
  27. Js操作dom的方法?
  28. Js中的变量(主要解释var和let定义变量的区别)?
  29. Js中display和visibility?

答案:
New操作符做了什么
1 创建一个空的简单的js对象
2 设置原型,将对象的__proto__设置为函数的prototype对象
3 让函数中的this指向这个对象(function.call),执行构造函数的代码(为这个新对象添加属性)
4 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,返回这个引用的对象(普通数据类型和复杂数据类型)

原型
每个对象都有他的原型对象,他可以使用原型对象身上的方法和属性
拿到原型对象可以通过对象的--proto--或者构造函数的prototype拿到
(构造函数中的this指向new创建的对象 this.name = name)

闭包
声明在一个函数中的函数就是闭包闭包函数,闭包是指内部函数可以访问其所在的外部函数中声明的参数和变量
闭包特点
保护私有变量,可以访问函数内部私有变量,局部变量常驻内存,
更加的安全还能够保持代码的封装性,访问也比较方便
缺点:一直在内存中,浪费资源,内存占用过多就会溢出导致内存泄漏
作用域是指代码的执行环境,作用域链就是嵌套函数一层一层往上查找

Js的内置对象有哪些
Math,Date,Array,String

检查数据类型
Typeof(判断函数是function,对象和数组和null都是object,nan是num,未定义就是未定义) 简单数据类型 boolean,number,string,undefinend,null
引用类型 Object(包括对象数组date等)
Object.prototype.toString.call(x) Object.prototype.toString方法可以判断数据类型,通过call函数改变this的指向,让this指向x,从而判断X的数据类型。之所以不通过x.toString去找原型对象的toString方法去判断,是因为在继承obj的时候重写了tostring方法
Instanceof 判断对象属性 (一般不用,因为该方法设计初衷是为了判断构造函数的prototype属性是否出现在某个实例对象的原型链上)

Js中的Object. defineProperty
给对象身上定义新的或者修改现有的一个属性,默认定义的属性无法删除和改变
Object. defineProperty(obj,’name’,{
Value: 属性的默认值
get:function(){ name = ‘xxx’} function可以省略
set: function(){ return ‘xxx’}
Configurable:默认是false,为true是属性可以被删除
Writable:默认是false,为true是属性可以被修改
Enumerable:默认false,为true就可以枚举属性})

Call apply bind
Call和apply都会调用函数并且改变函数内部this指向。
Call的参数是单个单个的,apply是数组形式的,bind返回一个函数,不会输出东西,其他两个会直接执行。
Bind不会调用函数,但会改变this指向。
Call:
判断数据类型:Object.prototype.toString.call(x)
类数组转数组:类数组是对象,但是内容和数组一样有序号有长度,Array.prototyte.slice.call(xxx)
Apply:
对给定数组求最大最小值,Math.max.apply(null,array) == Math.max(1,2,3,4,5)

Map 遍历数组,会返回一个新的数组,三个参数arr.map(function(value,index,arr){xxx})
For each 遍历数组,不会返回新数组 同上
For in 遍历数组和对象,遍历的数组是字符串形式,遍历的对象属性包括原型对象身上的,输出的是属性名,如果需要输出属性值的话需要arr[i]
For(let i in arr){ }
For of 遍历对象,只能遍历迭代器对象,array,set,map,遍历的数组输出的是num格式

Var 变量,函数提升
Let 不存在变量函数提升,let定义的变量只在块中有用
Const 严格的let,并且声明的时候必须赋值,且值的地址不能改(简单数据类型值不能改,复杂数据类型地址不能改,但是值可以改)
如果直接定义一个变量而不用任何声明,默认该变量是window的,哪里都能用
Var定义的变量是定义在了window上一个成员属性身上
Let声明的变量不是真正的全局变量,而是保存在类似函数作用域的脚本作用域对象中,类似于局部变量,所以window上找不到

数组常见方法
Array = [1,2,3,4,5]
1 array.indexOf(2) 检查数组中有没有2这个元素,有的返回下标,没有返回-1
3 Array.sort((a,b) =>{return a - b}) a-b是从小到大排序,b-a从大到小,返回一个数组
也可以直接array.sort() 默认是从小到大的(10个数以内)
5 array.push(1) 给array添加一个1,返回值是数组的长度,会直接改变原数组
6 array.pop() 删除并返回数组的最后一个元素,改变原数组
7 array.unshift() 给数组开头添加元素,改变原数组
8 array.shift() 删除数组第一项,改变原数组
9 array.reverse() 反转数组
11 array.splice(index,howmuch,arr...)从索引index开始删除howmuch个项,然后把arr添加进去

以上都会改变原数组

以下都不改变原数组
2 Const res = array.filter((item,index) =>{ }) item是数组中的每个元素,会返回一个数组
4 Const res = Array.reduce(function(prev,current,currentIndex,sourceArray){
//Prev 上一个数字,current当前数字,currentIndex当前数字索引,
Return Prev +current 求和
})
10 array.slice(start,end) 获取从start到end索引的数组,不包括end项
12 array.join()把数组中的所有元素放入一个字符串,默认以逗号分割,或者填进去分割的东西,将数组转换成字符串
13 array.concat(arr) 把arr中的元素都加到array后面,返回新数组
14 Array.map(function(currentValue,index,arr)) map会依次处理数组中的每一个元素,并返回一个新的数组,对原来数组不影响,也不会检查空数组

Math
Math.min(1,2,3) math.max(1,2,3) math.ceil() 进1 math.floor() 舍 math.round()四舍五入
Math.random 返回一个0-1的数字 不包括0和1
Math.floor(math.random()*总数 + 第一个值)
Math.floor(math.random()*10 + 1) 随机产生1-10

Str.split(“X”) 把字符串以X为分隔符分割并返回一个数组,不填写X则一个一个分开
Array.from(arr) 可以直接把字符串转为数组

数组去重
1.filter和indexOf
2.相邻元素排序--先利用sort排序,然后循环比较i+1和i项,不等的话就加入到新数组中
3.set 解构赋值 return [...new Set(array)]
4.const result = new Set(array) 此时已经排好序的,但是类型是set类型,所以需要array.from将类数组对象变成数组 array.from(new Set(array))

数组中各项是对象的去重
临时对象缓存数组项key值 --- 遍历比较

求数组中的最大最小值
1 Math.max(...array) 因为max里要传一个一个的参数,所以...array
Math.max.apply(null,array)
2 利用reduce循环比较
3 sort函数排序后直接选

函数节流
单位时间内只执行一次 -- 返回值是一个函数,开启定时器,定时器如果存在直接返回,清空定时器,并且把timmer置为null,能设置一个立即执行

函数防抖
事件被触发n秒后在执行回调,如果还没到时候就又被触发就重新计时,能设置一个立即执行

ES6
箭头函数和普通函数区别
1 箭头函数的this指向父级作用域的this,普通函数的this是调用这个函数
2 call,apply,bind无法改变箭头函数的this指向
3 箭头函数不可以被当作构造函数
4 箭头函数不可以使用arguments对象,如果使用的话需要在传参的时候表明接受的参数(...args)
普通函数:sayName(){const args = arguments log(args)} ----sayName(a,b)
args里面就变成了传进去的参数的数组 也就是arguments是接受传入的参数的函数
5 箭头函数不支持new.target(用来判断一个构造函数是否用new关键字调用)

ES6新增了rest参数
效果等同于arguments,不过arguments是一个类数组是一个对象,rest则是数组,且要求形参中必须有…rest,而且需要放到变量的最后

类数组转数组方法
Array.prototype.slice.call()(或者apply) Array.from new Array()

Es6的扩展运算符…
…和…rest的不同在于 … 一般是在实参位置,…rest是在形参位置
作用:
数组合并:arr = […arr1,…arr2] 能把两个数组中的参数都拿出来,只写一个数组的话就是克隆,浅拷贝

Symbol
不能进行运算
不能用for in遍历,但是可以用reflect.ownkeys获取键名
str = Symbol(‘xx’) != str1 = Symbol(‘xx’)
str = Symbol.for(‘xx’) == str1 = Symbol.for(‘xx’)

Es6对象新增的方法
Object.is(a,b) 比较两个变量是否相同 能判断普通和复杂数据类型也能够判断NaN ==NaN
Object.assign(target,...sources) 两个或者多个对象进行合并,覆盖target,返回一个合并后的结果,后面的会覆盖前面的
Object.key(obj) 返回目标对象所有可遍历的属性的键名
Object.value(obj) 返回目标对象所有可遍历的属性的键值
Object.entries(obj) 返回目标对象所有可遍历的属性的键值对数组

函数、方法、类
函数是可以执行的js代码,通过名字直接调用的,函数中的数据是显示传递。
方法是定义在对象的内部,不能直接调用,是特殊的函数,方法中的数据是隐式传递。
类是ES6新增的定义,用来创建对象用的。

在函数内部添加的属性会添加到使用该函数作为构造函数创建的对象身上。
而在函数外部直接添加的属性,则只会作为构造函数的属性,而构造函数的实例对象拿不到这个属性,如果需要添加的话必须添加到构造函数原型身上。
给函数添加方法和属性,如果直接添加的话,打印对象打印不出来,但是构造函数可以调用,实例函数不可以调用,所以必须通过原型。
Person.prototype.name = ‘hello’ p1.name = ‘hello’

ES5与ES6继承
ES6使用语法 class B extends A继承,ES6类继承是ES5函数继承的语法糖,把ES6的继承通过Babel转义成ES5之后,发现它是通过object.create方法实现了(1)B.proto = A。表示子类B继承父类A的静态属性。通过Object.setPropertypeOf()方法实现(2)B.prototype.proto = A.prototype 。这与组合继承相同。 (一) ES6继承同时存在两条继承链。ES5是没有第一条原型链的。
(二) ES6的子类必须在constructor方法中调用super()方法,super()代表调用父类的构造函数,因为子类没有自己的this对象,所以子类要先继承父类的this。但ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。
(三) ES6 可以自定义原生数据结构(比如Array、String等)的子类,这是 ES5 无法做到的。
l4dw4p5u.png
ES6的构造函数通过原型链连接起来了,构造函数之间有直接的引用关系;
ES5实际上是使用call或者apply借用父类构造函数实现的实例化,构造函数之间没有直接的引用关系
ES5的实例化对象是由子类构造函数先创建的,然后父类构造函数是使用call或者apply修改这个对象
ES6的实例化对象是由父类构造函数先创建的(这就是为什么要先调用super),然后子类构造函数修改这个对象

Class和function的区别
相同:都可以用构造函数,class的构造函数里面是一个constructor
不同:class不可以使用call,bind,apply改变他的this指向

Promise--异步编程解决方案,需要new
三个状态:pending,fufilled,rejected 当一件任务交给promise时状态时pending,任务完成就是fufilled任务失败就是rejected。
两个过程:分别是pending- fufilled和pending- rejected 状态一旦改变就不能在变了
缺点:无法取消promise,一旦新建就会立即执行无法中途取消。 如果不设置回调,promise内部的错误不会抛出,不会反应到外部。
then方法--拿到resolve或者reject的值,可以链式调用,接受两个参数,分别是成功 和失败回调
Catch方法--捕获错误的
Finally方法---执行到最后一定执行的
Promise.all()---接受一组异步任务,全部完成后执行回调。将多个promise实例包装成一个新的promise实例 并发的
Promise.race()---接受一组异步任务,第一个异步任务完成后后执行回调。将多个promise实例包装成一个新的promise实例 继发的
Promise封装的话就是把内容封装到一个promise对象中,new Promse((resolve,reject)=>{})

Async-await
先执行async函数,返回一个promise对象
Await相当于promise的then
Try…catch可以捕获异常,代替了promise的catch

Set,map,weakset,weakmap区别?
强引用与弱引用---在js中强引用是指变量通过指针指向一个地址。强引用不会被垃圾回收,弱引用虽然也是引用,但是当所有的强引用不在引用一个地址的时候,即使弱引用仍在引用,那么那个地址的数据仍然会被销毁。
Set---成员不能重复,类似数组;可以遍历;方法有add,delete,has
Weakset---成员都是对象;成员都是弱引用,随时会消失(当其他对象都不引用该对象垃圾回收机制就会将其回收),不可以遍历
Map---键值对的集合,可以遍历
Weakmap--只接受对象为键名,不接受其他类型为键名;键名指向的对象不计入垃圾回收;不能遍历,方法同get,set,has,delete,不可以枚举不可以清空

装箱:基本数据类型变成引用类型 拆箱:相反

内存泄漏的几种情况?
1 意外的全局变量 2 闭包 3 未被清空的定时器 4 未被销毁的事件监听 5 dom引用、

Json和xml
Xml大,占带宽,不容易解析处理,但是对数据描述性好,一般用于配置文件,json一般用于数据交互

浅拷贝深拷贝
浅拷贝只复制指针,仍然共享,深拷贝创造一模一样的新的对象。
浅拷贝:Object.assign() for in 深拷贝:递归拷贝所有属性 使用json转换 lodash里的cloneDeep

Js操作dom的方法
通过document.getElmentsByid byname classname qureySelector querySelectoryAll 等
可以修改标签内容 innerHTML 设置样式style.xxx
添加事件 onclick onmouseover onmouserover onfocus onblur
添加事件之后最后一个生效,添加多个事件用addEventListener

Js中display和visibility? Visibility不破坏页面布局但会有空白

0

评论 (0)

取消