1. 闭包
- 闭包是能够读取其他函数内部变量的函数,就是在函数里面声明函数,即子函数。本质上是在函数内部和函数外部搭建起一座桥梁,使得子函数可以访问父函数中所有的局部变量,但是反之不可以,这只是闭包的作用之一。
- 另一个作用是保护变量不受外界污染,使其一直存在内存中。因为子函数被赋给了一个全局变量,所以子函数会始终在内存中,而子函数的存在依赖于父函数,所以父函数也会一直存在与内存中
- 应该少使用闭包的好,因为闭包使函数中的变量都保存在内存中,太消耗内存,会造成网页性能问题。在IE中可能导致内存泄漏。解决方法是,退出函数时,将不使用的局部变量全部删除。
2. =、==、===
- =: 赋值
- ==: 返回一个布尔值;相等返回true,不相等返回false;允许不同数据类型之间的比较;如果是不同类型的数据进行,会默认进行数据类型之间的转换; 如果是对象数据类型的比较,比较的是空间地址
- ===: 只要数据类型不一样,就返回false
3. js的原型和原型链
- 每个构造函数都有 prototype 属性,该属性指向一个对象,这个对象就是原型。
- 每个对象都有属性 proto 属性,指向该对象的原型。每个对象都从原型继承属性
- 读取实例属性时,若找不到该属性,就会去原型里面找,如果还找不到,再向上层原型中找,一直到找到或者原型为null
- 每个对象实例也有 constructor 属性,可以用来查看该实例是由哪个构造函数产生的
- 直接访问原型属性,不能修改属性的值,但可以修改属性指向的值(引用属性)。要想修改原型属性,可以通过
__proto__,但尽量不要使用。 - www.cnblogs.com/jushou233/p…



4. 作用域链
- 代码中的变量如果在当前作用域中没有被定义,该变量成为自由变量。如果想取自由变量的值,要向父级作用域(准确的说是创建它的父级作用域,而不是调用它)中寻找。如果还没有,就一级一级向上寻找。
- 作用域链的变量只能向上访问,访问到window对象终止。
- 作用域控制函数和变量的可访问范围
5. js的数据类型
- 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(ES6 引入了一种新的原始数据类型,表示独一无二的值)。
- 引用数据类型:对象(Object)(对象类型包括 数组(Array)、函数(Function)。)
- 基本数据类型直接存储在栈中,占据空间小,大小固定,属于被频繁引用的数据
- 引用数据类型在栈中存储了指针,指针指向堆中的实体。数据占据空间大,大小不固定。
6. js创建对象的几种方式
- Object构造函数创建
var Person =new Object(); Person.name = 'Jason';Person.age = 21; - 使用对象字面量表示法创建
var Person={}; //等同于var Person =new Object(); var Person={ name:"Jason", age:21 } - 使用工厂模式创建:把创建对象的方法封装在一个函数里,该函数返回一个对象。但是无法得知对象的具体类型,只能知道是Object
function createPerson(name,age,job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); }; return o; } var person1 = createPerson('Nike',29,'teacher'); var person2 = createPerson('Arvin',20,'student'); - 使用构造函数创建
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person('Nike',29,'teacher'); var person2 = new Person('Arvin',20,'student'); - 使用原型对象创建:把实例共有的属性放在里面,共有的这些属性和函数不会在每个实例创建的时候都分配空间,它们共享空间
function Person(){}
Person.prototype.name = 'Nike';
Person.prototype.age = 20;
Person.prototype.jbo = 'teacher';
Person.prototype.sayName = function(){ alert(this.name);};
var person1 = new Person();person1.sayName();
- 使用构造函数和原型结合:属性在构造函数中定义,共享的属性和方法在原型中定义
function Person(name,age,job) { this.name =name; this.age = age; this.job = job; } Person.prototype = { constructor:Person, sayName: function() { alert(this.name); }; } var person1 = new Person('Nike',20,'teacher');
7. js内置对象
- Object是所有对象的父对象
- 数据封装类对象:Object, Array, Boolean, Number, String
- 其他对象:Function, Arguments, Math, Date, RegExp, Error
8. 为什么要有同源限制
- 同源策略:协议、域名、端口相同。是一种安全协议
- 比如有一个黑客程序,利用ifrme把银行登陆页面嵌入到他的页面中方,当使用真是用户名密码登陆时,他的页面就可以通过js读取表单中的input内容,得到用户名和密码。
- 再比如如果没有同源策略,那么一个网站的API可以被其他任何来源的的ajax请求访问,那么其他网站很容通过cookies获取到该网站用户的信息
9. 事件代理
- 又叫事件委托。就是把原来需要绑定的事件委托给父元素,让父元素担当事件监听的责任。原理是DOM元素的事件冒泡。可以提高性能,减少事件注册。当新增子对象时无需再次注册
10. js如何实现继承
- 原型链继承:将父元素的实例赋值给子元素的原型,即子元素的 prototype 属性。即子类继承自父类的构造函数属性(实例属性)都在子类的原型中,父类原型中的属性都在子类的原型的原型中。但是子类实例共享了父类构造函数的引用属性,改变一个全部改变。而且子元素创建实例时不能传参
Child.prototype = new Parent() - 构造函数继承:等同于复制父类的属性给子类。但是只能继承父类构造函数中的属性和方法,不能继承原型中的。而且父类不能复用,子类的方法每次都单独创建,影响性能。实例只是子类的实例,不是父类的。
function SuperType(){ this.color=["red","green","blue"]; } function SubType(){ //继承自SuperType SuperType.call(this); } - 组合继承:原型链继承和构造函数继承的组合。通过调用父类构造,继承父类的构造函数中的属性并保留传参的优点,然后通过将父类实例作为子类原型继承所有属性,实现函数复用。缺点是父类构造函数中的属性子类中有两份,一份在子类构造函数中,一份在子类原型中,但是属性查找时,子类构造函数中的属性会覆盖子类原型中的属性,消耗内存。(子类重写原型的constructor属性,使其指向子类的构造函数)
function SuperType() { this.name = 'parent'; this.arr = [1, 2, 3]; } SuperType.prototype.say = function() { console.log('this is parent') } function SubType() { SuperType.call(this) // 第二次调用SuperType } SubType.prototype = new SuperType() // 第一次调用SuperType - 原型式继承: 利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。object()对传入其中的对象执行了一次浅复制,将构造函数F的原型直接指向传入的对象。但是父类引用属性的修改会被共享,同时子类构建实例时不能传参。
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); - 寄生式继承:使用原型式继承获得一个目标对象的浅复制,然后在函数中增加属性,返回子类实例。
function createAnother(original){ var clone=object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi" - 寄生组合式继承: 寄生式继承和组合式继承的结合。对父类原型进行浅复制,然后将子类原型替换为刚刚复制的原型,父类构造函数的属性通过构造函数继承传给子类。通过寄生方式,砍掉父类的实例属性,解决了组合继承会两次调用父类的构造函数造成资源浪费。(要重写子类constrctor属性,推荐)
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); // 创建了父类原型的浅复制 prototype.constructor = subType; // 修正原型的构造函数 subType.prototype = prototype; // 将子类的原型替换为这个原型 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } // 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费 inheritPrototype(SubType, SuperType); - 以上是ES5继承机制,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上。
- ES6继承:先创建父类的实例对象this,然后再用子类的构造函数修改this。因为子类没有自己的this对象,所以必须先调用父类的super()方法,返回子类实例。super()内部this指向子类,此时super()作为函数,只能出现在子类的构造函数中。super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。由于super指向父类的原型对象,所以定义在父类构造函数上的方法或属性,是无法通过super调用的。constructor表示构造函数,一个类中只能有一个构造函数,如果没有显式指定构造方法,则会添加默认的 constructor方法。构造函数外定义的方法在原型对象上
11. this指向问题
- 全局作用域下,this指向window
- 如果给元素的事件绑定函数,函数中的this指向当前绑定的这个元素
- 函数中的this,定义时不会指向任何值,只有在调用时才会指向调用它的对象。即指向 . 前面的对象,如果没有,就指向window
- 自调用的函数中 this 永远指向 window
- 构造函数中的 this 指向当前实例
- 箭头函数中没有this, 如果输出this,会输出箭头函数定义时所在的定义域的 this
- call, apply, bind 可以改变 this 的指向
12. 事件机制
- 事件捕获: 当用户点击或触发DOM事件时,父级元素先被触发,子级元素后被触发
- 事件冒泡: 当用户点击或触发DOM事件时,子级元素先被触发,父级元素后被触发
- DOM 0级事件:直接在元素上使用 onClick 绑定。但是不能在同一个元素上绑定两个事件(绑定两个的话,后面的会覆盖前面的)。而且不能控制元素的事件流是捕获还是冒泡。元素事件只能在冒泡阶段触发
- DOM 2级事件流存在三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。首先是事件捕获阶段,从上向下传播;然后到达点击事件目标节点;最后是冒泡阶段,从下向上传播。
- DOM2中所有的 HTML 元素上都定义了两个方法: addEventListener() 和 removeEventListener()。第三个参数定义该事件是在冒泡阶段还是捕获阶段被触发,默认false,表示在冒泡阶段被触发。若事件触发目标DOM节点为target,document 往 target节点,捕获前进,遇到注册的捕获事件立即触发执行(如果该事件绑定多个函数,按注册顺序执行);到达target节点,触发事件(对于target节点上,不管是捕获还是冒泡,先注册先执行);target节点 往 document 方向,冒泡前进,遇到注册的冒泡事件立即触发
13. new操作具体实现了什么
- 创建一个空对象,this指向该对象。同时还继承了该构造函数的原型
- 属性和方法被加入到 this 指向的对象实例中
14. ajax原理
- 在用户和服务器之间添加了一个中间层(ajax引擎),然后通过XmlHttpRequest对象向服务器发送异步请求,从服务器获取数据,然后通过 js 操作 DOM 来更新页面。使得用户操作和服务器响应异步化。
- 步骤
- 创建连接
var xhr = new XmlHttpRequest; - 连接服务器
xhr.open('get', url, true); - 监听请求数据。首先检查XMLHttpRequest的整体状态并且保证它已经完成(readyStatus=4),即数据已经发送完毕。然后根据服务器的设定询问请求状态,如果一切已经就绪(status=200)
xhr = onreadystatechange = function() { if(xhr.readystate == 4) { if(xhr.status == 200) { success(xhr.responseText) } else { fail && fail (xhr.status) } } } - 发送请求
xhr.send(null);
- 创建连接
15. XML和JSON的区别
- XML: 可扩展标记语言。用来标记文件使其具有结构性。可用来标记数据,定义数据类型。不用来表现或展示数据。格式统一,易于和其他系统进行交互。但文件大,格式复杂,传输占带宽,解析起来也耗费资源和时间
- JSON: 轻量级的数据格式,是js的一个子集,利用js中的一些模式来表示结构化数据。可在不同平台间进行数据交换。格式简单,占用带宽小。易于解析和维护
16. window.onload()和$(document).ready()的区别
- window.onload(): 等到网页中所有的内容(包括图片和iframe中的内容)全部加载完之后才会执行
- $(document).ready(): 在DOM树绘制完之后就会执行。是 DOMContentLoaded 在 jQuery中的实现
17. 几种判断数据类型的方法
- typeof: 返回一个表示数据类型的字符串。返回结果有 number、string、boolean、object、undefined、function。对于引用类型,除了function之外返回的都是object。null返回object
- instanceof: 判断左操作数对象的原型链上是否有右边这个构造函数的prototype属性,也就是说指定对象是否是某个构造函数的实例,最后返回布尔值。
- constructor: 返回所有 JavaScript 变量的构造函数,包括自定义对象,即某个实例对象是哪一个构造函数产生的。但是,constructor属性易变,不可信赖,主要体现在自定义对象上,当重写prototype后,原有的constructor会丢失。因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写。
18. js的几种设计模式
- 工厂模式: 定义一个创建对象的接口,该接口决定实例化哪一个类。相当于把方法封装起来了。解决了重复实例化的问题,但是无法检测具体的对象类型,只知道是Object。
- 单例模式: 一个对象只有一个实例,并提供一个外部函数,该函数中用一个变量标识是否创建过该对象的实例,如果没有创建过,则通过构造函数创建;如果创建过,返回原先创建的实例
- 发布订阅模式:订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心,由调度中心统一调度订阅者注册到调度中心的处理代码。发布者和订阅者不知道彼此存在
- 观察者模式:一对多。当一个对象状态发生改变时,依赖他的对象都会得到通知。实现时需要:定义观察者,观察者拥有一个缓存列表。当发布消息时,遍历缓存列表,依次触发里面存放的目标的回调函数。
- 代理模式: 当不想对一个对象直接操作时,为一个对象添加一个对象做代理,以便对原对象进行操作。
- 外观模式: 为子系统中的一组接口提供一个更高层的接口,方便调用
- 适配器模式
- 装饰器模式
- 迭代器模式
- 状态模式
19. 改变 this 指向
- call(): 第一个参数指定this的指向,指定的对象的this指向就是函数运行的作用域。后续参数就是传入这个函数的实参
- apply(): 只有两个参数。第一个参数和call()相同,第二个参数必须是数组,数组元素就是传入函数的参数
- bind(): 前面两种方法会直接执行函数。bind()会创建一个函数的实例,其this值会z指向传给bind()的对象的作用域。需要调用bind()实现函数的执行
20. var let const
- var: 用 var 定义的变量是全局作用域。可以定义名字相同的变量。如果定义变量前没有关键字声明,默认是全局作用域。存在变量提升。可是先试用后定义。
- let: 定义块级作用域变量。没有变量的提升,必须先声明后使用。同个作用域下,不允许有任何关键字声明的重名变量。
- const: 定义只读变量。const声明变量的同时必须赋值,一旦初始化完毕就不允许修改。const声明变量也是一个块级作用域变量。没有变量提升,必须先声明后使用。同个作用域下,不允许有任何关键字声明的重名变量。
21. ES6 新特性
- 有块级作用域。let定义块级作用域变量,没有变量的提升,必须先声明后使用 let声明的变量,不能与前面的let,var,conset声明的变量重名
- const 定义只读变量。const声明变量的同时必须赋值,一旦初始化完毕就不允许修改。const声明变量也是一个块级作用域变量。const声明的变量没有“变量的提升”,必须先声明后使用。const声明的变量不能与前面的let, var , const声明的变量重名。 const定义的对象/数组中的属性值可以修改,基础数据类型不可以
- 可以给形参函数设置默认值
- 展开运算符(...)。可以在函数调用时通过展开运算符传参。或者用来合并数组。还可以用来解构赋值,但是此时展开运算符只能用在最后。(对象不能用)
- 解构赋值。按照一定模式,从数组和对象中提取值,对变量进行赋值。类似于模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量赋值为 undefined。也可以不完全解构,即左边只匹配一部分右边
- 箭头函数。相当于匿名函数,不能作为构造函数的。箭头函数没有自己的this。他的this是继承当前上下文中的this。箭头函数没有函数原型。不能使用call、apply、bind改变箭头函数中this指向
22. 数组的方法
- 改变原数组的方法
- splice():向/从数组中添加/删除项目,然后返回被删除的项目。若没有删除或只是添加,则返回 空数组
array.splice(index,howmany,item1,.....,itemX)
index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置;
howmany:可选。要删除的项目数量。如果设置为 0,则不会删除项目;
item1, ..., itemX: 可选。向数组添加的新项目。 - sort():对数组元素进行排序,并返回这个数组。
不传参时,默认按字母升序,如果不是元素不是字符串的话,会调用toString()方法将元素转化为字符串的Unicode(万国码)位点,然后再比较字符。
默认参数要在函数中接收 - pop() :删除一个数组中的最后的一个元素,并且返回这个元素。
- shift():删除数组的第一个元素,并返回这个元素。
- push() :向数组的末尾添加一个或多个元素,并返回新的长度。
- reverse():颠倒数组中元素的顺序。
- ES6:fill() : 使用给定值,填充一个数组。
第一个元素(必须): 要填充数组的值
第二个元素(可选): 填充的开始位置,默认值为0
第三个元素(可选):填充的结束位置,默认是为this.length
- splice():向/从数组中添加/删除项目,然后返回被删除的项目。若没有删除或只是添加,则返回 空数组
- 不改变原数组的方法
- slice(): 返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象,且原数组不会被修改。(字符串也有一个slice() 方法是用来提取字符串的)
- indexOf(): 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
- cancat(): 合并两个或多个数组,返回一个新数组。
- 遍历数组的方法
- map(): 参数是一个函数,map()创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
- ES6: find()& findIndex() :
find()定义:用于找出第一个符合条件的数组成员,并返回该成员,如果没有符合条件的成员,则返回undefined。
findIndex()定义:返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
23. Promise 对象
- Promise 有三种状态
- pending: 初始状态。进行中
- fulfilled: 已成功
- rejected:已失败
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。new Promise的时候,会把传递的函数立即执行
- resolve函数的作用是,将Promise对象的状态从 pending 变为resolved,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
- reject函数的作用是,将Promise对象的状态从 pending 变为rejecte, 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
- .then() 方法接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。
- then方法返回的是一个新的Promise实例。 因此可以采用链式写法。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
- .catch() 方法用于指定发生错误时的回调函数。它与.then() 第二个参数不同的是,可以捕获回调函数中的错误。
- catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。
- resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例。如果传入的实例的状态是pending,那么原来实例的回调函数就会等待传入实例的状态改变;如果传入实例的状态已经是resolved或者rejected,那么原来实例的回调函数将会立刻执行。
- Promise 在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise的状态一旦改变,就永久保持该状态,不会再变了。
- Promise.resolve():将现有对象转为 Promise 对象
- 如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
- 参数是一个thenable对象(具有then方法的对象),会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。
- 如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。所以then后面的回调函数会立即执行
- 不带参数,直接返回一个resolved状态的 Promise 对象
24. <script>中defer和async的区别
- 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,不等待后续载入的文档元素,读到就加载并执行。
- 有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。加载完就执行
- 有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

25. js异步加载的方式
- defer
- async
- 动态创建DOM
- 按需异步载入js
26. use strict
- 严格模式。规范js代码,减少怪异行为
- 规则
- 变量必须声明后才能使用
- 函数的参数不能有同名属性,否则报错
- 不能使用 with 语句
27. attribute 和 property 区别
- attribute 是 DOM 元素在文档中作为html标签拥有的属性。始终保持html中的初始值。
- property 是 DOM 元素在js中作为对象具有的属性。可以通过js动态改变。
- property能够从attribute中得到同步;attribute不会同步property上的值
28. 浏览器事件循环机制(event loop)
- js是单线程。但浏览器是事件驱动的,很多行为是异步的。一个浏览器至少有三个常驻线程:js引擎线程、GUI渲染线程、事件触发线程
- js引擎线程:主要有堆和栈构成。堆中分配内存资源。函数的调用会形成一个个栈帧放入栈中
- 执行栈:每个函数执行的时候,都会生成新的执行上下文。执行上下文包含当前函数的参数、局部变量之类的信息。它会被压入栈中。正在执行的上下文会始终处于栈的顶部。函数执行完毕后,会从栈中弹出
- 程序中一般有两个线程,一个是主线程,负责程序本身。另一个负责主线程和其他进程之间的通信,被称为Event Loop线程(消息线程)。
- 事件循环:
- 函数入栈,当执行到异步任务时,把异步任务交给webapis,然后继续执行同步任务,直到栈空
- 在此期间,webapis执行异步任务,并把回调函数放入回调序列中等待
- 当执行栈为空时,把回调序列中的任务放到执行栈中,然后回到第一步
- 执行栈中放同步的代码,异步操作放入事件队列中。事件队列又分为宏任务和微任务
- 主线程开始执行执行栈中的代码。执行完毕后,先去微任务队列中执行完所有微任务,直到微任务队列空。然后去宏任务队列执行宏任务。宏任务一次只能取一条,如果宏任务中还有微任务,那么执行完这一条宏任务之后,要去执行微任务队列中的所有微任务,再执行下一条宏任务。即执行一条宏任务之前微任务队列中一定已经全部执行完
- 宏任务:
- setTimeout (根据时间执行,不根据顺序)
- setInterval
- I/O
- script代码块
- 微任务:
- nextTick
- callback
- Promise
- process.nextTick
- Object.observe
- MutationObserver
- 如果俩个微任务的优先级相同那么任务队列自上而下执行,(promise的优先级高于async)
29. Generator函数
- 函数名之前要加星号.
- Generator 函数就是一个封装的异步任务,异步操作需要暂停的地方,都用 yield 语句注明。
- 调用 Generator 函数,会返回一个内部指针(即遍历器 )。调用指针的 next 方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的 yield 语句,依次向后
- 每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。
- value 属性是 yield 语句后面表达式的值,表示当前阶段的值
- done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
30. async函数、await
- async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await
- 对Generator的改进体现在:
- async函数的执行,与普通函数一模一样调用即可。但Generator 函数的执行必须靠执行器(.next())
- async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
- async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
- 如果一个Promise被传递给一个await 操作符,await将等待Promise正常处理完成后并返回其处理结果。此处的
await Promise.resolve( )就类似于Promise.resolve(undefined).then(undefined) => { }
31. 浅拷贝和深拷贝
- 浅拷贝: 只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用。即只复制了内存地址。如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
- 深拷贝: 创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
32.类数组对象
- 具有length属性,其他属性是非负整数。没有数组的方法
- 一般Arguments对象和DOM对象列表即使用getElementsByTag等获取的对象都是类数组对象
- 类数组对象转环为数组的方法: Array.from()可以将类数组对象和可遍历对象转环为真正的数组;Array.prototype.slice.call(likeArray);或者使用展开运算符[...likeArray]
33.判断一个对象是不是数组
- Array.isArray直接判断
- 通过class:每个对象的内部属性,记录创建对象时使用的类型名
34.遍历数组
- map:不改变原数组,有return
- forEarch: 不改变原数组,没有return
- for key in value: key是索引
- some: 有一个符合条件的,就返回true
- every: 全部符合条件,才返回true
- filter: 返回符合筛选条件的数组元素
- find: 返回符合筛选条件的第一个元素
- findIndex: 返回符合筛选条件的第一个元素的索引
- reduce: 接受一个函数,函数有四个参数,分别是:上一次的值,当前值,当前值的索引,数组
35.为什么js是单线程
js是浏览器的脚本语言,主要用于用户和浏览器的交互,还有操作dom。这决定了js只能是单线程。如果有多个线程,同时操作同一个dom,就会产生问题
HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
36.模版字符串
``xxxxxx ${变量} xxxxxx`
模板占位符可以是表达式,函数调用,运算符等。还可以嵌套
如果变量不是字符串,会自动转换成字符串
特殊字符的表示需要用到转义字符
空格,换行等会原样输出
37.块中定义函数,要用函数表达式定义。但是严格模式下会报错
38.Math.round()
返回数字四舍五入后最接近的整数
小数部分大于0.5,舍入到相邻绝对值更大的整数;小于0.5,舍入到更小的
等于0.5,舍入到相邻的正无穷方向的整数
39.判断数据类型
- typeof: 能判断出number, string, boolean, undefined, symbol, function, object 即对于原始类型,除null都可以判断。对对象来说,除了function,其他都判断为object
- instanceof: 主要用于对象类型判断,判断左边操作数的原型链上是否有右边构造函数的原型
- constructor: 返回所有JavaScript变量的构造函数,包括自定义对象,即某个实例对象是哪一个构造函数产生的。但不可信,可以改。
40.表单公有属性 disabled(禁用)readOnly(只读)
41.setAttribute():新增或修改元素属性。用getAttribute取属性值
42.变量比较 不同类型 类型转换
类型转换只有三种情况:转换为boolean, number, string
转为boolean: 条件判断时,除null, undefined, '', 0, -0, false, NaN 其他都为true \
43.阻止事件冒泡,阻止默认事件
- 阻止冒泡:w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
- 阻止默认:w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false
44.defineProperty, enumerable, for...in
- Object.defineProperty(object1, 'property1', {descriptor}): 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
- descriptor包括:configurable(是否可以删除目标属性或是否可以再次修改属性的特性), enumerable(true时,可被枚举,for...in可以遍历到该属性值), value, writable(能够被改变)
- 通过defineProperty添加属性时这些以上描述符的属性值默认都为false。通过字面量添加时,均为true
45.map对于空元素,返回undefined;对空数组不进行检测
46.NaN与任何值都不相等,包括本身
47.字符串的方法
- cancat
- toLowerCase, toUpperCase: 转大小写
- slice: 截取字符串,接受一或两个参数(开始位置和结束位置),接受负值时会将负值与字符串长度相加
- substring: 截取字符串,接受一或两个参数(开始位置和结束位置,会将较小的参数作为起始位置),接受负值时会将负的参数转换为零
- substr: 截取字符串,接受一或两个参数(开始位置和截取的字符个数),接受负值时会将第一个负的参数加上字符串长度,将第二个负的参数转换为0
- indexOf
- lastIndexOf: 从末尾开始查找
- trim: 删除前置或后缀的空格,生成副本,原字符串不变
- split: 用某个字符分割字符串,返回一个数组
- search: 接受一个正则,返回第一个匹配到的字符的索引,没有返回-1
- a.localeCompare(b): a>b返回正数,a<b返回负数,a=b返回0
- replace: 用第二个参数替换第一个。如果第一个是字符串,只能替换第一次出现的。若想全局替换,第一个字符串要提供正则 g。第二个参数可以是字符串活着函数
- match: 在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
48.数组去重
- ES6 set: Array.from(new Set(arr))
Set对象储存值唯一的任何值。from()用来将类数组对象转换成数组。该对象必须有length属性且属性名必须是number或string型的数组 - for嵌套 splice :如果第i个等于第j个 splice(j, 1)
- indexOf: 准备空数组,便利原数组,若indexOf返回-1,将元素加入空数组
49.node节点及document类型
- node节点基本类型:元素 Element, 属性 Attr, 文本 Text, 注释 Comment, 文档 Document
- Document 和 Element 类型都是继承于 Node 类型的节点
- JavaScript 通过 Document 类型表示整个文档,在浏览器中有一个 HTMLDocument 类型,其继承于 Document 类型。在浏览器中存在一个 document 对象,其是 HTMLDocument 类型的一个实例。
- 在 DOM 树中,一切元素(文档、元素节点、注释、文本、属性等等)都是某一个节点类型的实例,这些节点类型都继承于 Node 类型,在 HTML文档中的一切元素都是对象。
- document.title: 获取/设置页面的 Title
- document.images: 该属性是一个 HTMLCollection,包含了页面中的所有
.(类似的还有.forms, .links)
- document.write(): 向页面写入内容。如果在文档(DOM)加载完成之后使用会覆盖该文档。
50.原生js获取dom
- 通过id: getElementById
- 通过类名: getElementsByClassName
- 通过标签名: getElementsByTagName
- 通过name属性: getElementsByName
- 通过选择器获取: querySelector
- 获取html标签: document.documentElement
- 获取body标签: document.body
51.不支持冒泡的事件:focus, blur, mouseenter,mouseleave, load, unload, resize
52.js全局函数
- isNaN(): 是否是数字
- Number(): 转换为数字
- String()
- escope():对字符串编码
- unescope(): 解码
- ...
53.防抖
事件被触发n秒后再执行事件,如果n秒内又被触发,重新计时
function debounce(fn, delay) {
var timer = null;
return function() {
var that = this;
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn.apply(that, arguments);
}, delay)
}
}
54.节流
在一个单位时间内,只触发一次函数。如果多次触发,只执行一次
- setTimeout实现
function throttle(fn, delay) {
var timer;
return function () {
var _this = this;
var args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null; // 在delay后执行完fn之后清空timer,此时timer为假,throttle触发可以进入计时器
}, delay)
}
}
- 时间戳实现
function throttle(fn, delay) {
var previous = 0;
// 使用闭包返回一个函数并且用到闭包函数外面的变量previous
return function() {
var _this = this;
var args = arguments;
var now = new Date();
if(now - previous > delay) {
fn.apply(_this, args);
previous = now;
}
}
}
55.如果在try语句里有return语句,finally语句还是会执行。当try和finally里都有return时,会忽略try的return,而使用finally的return;如果finally中没有return,会先把try返回的变量保存,执行完finally之后再返回刚刚保存的变量。finally不会影响这个变量、
56. 同名变量和函数的声明及赋值
变量赋值 > 函数声明 > 变量声明 blog.csdn.net/qq_38765789…