第1节 原生js面试题#
14 什么是工厂模式,有什么优缺点? *
22 原型 ,原型链,继承方式 ***
32 h5新特性 ***
35 队列和栈 *
50 手写防抖、节流、防抖、节流的区别 ***
01 map和foreach的区别#
-
定义#
- foreEach()方法: 执行每个元素提供的函数。
- map()方法: 创建一个由调用数组中的每个元素执行提供的函数获得的新数组。
-
相同点#
- 都是数组的遍历
- 无法终止或跳出forEach()循环,除非抛出异常;
-
区别#
- forEach()方法不会返回执行结果,而是undefined,允许callback更改原始数组的元素。
- 而map()方法将获得新的数组并返回。
- forEach()执行速度 < map()执行速度JS中Map和ForEach的区别 - 简书
02 解释下JavaScript中this如何工作#
或问: 谈谈this的指向 第一准则: this永远指向函数运行时的对象,而不是函数创建时的对象。
- 谁调用普通函数,this就是谁。
- 匿名函数或不在任何对象中的函数指向window 。
- 如果是call,apply,bind,指定的this谁就是谁。
- 如果不需要构造函数,new操作符而直接调用,那即this指向window。用new操作符生成对象实例后,this指向新生成的对象。
- 箭头函数的this, 因为箭头函数没有绑定this, 它将捕获其所在(即定义位置)上下文this值, 作为自己的this值
前端面试题 | JS部分(附带答案)_axgrfetia063590468的博客-CSDN博客http://docs.huruqing.cn/JavaScript/02.html#_2-谈谈this的指向
03 异步线程、轮询机制、宏任务微任务#
js异步和事件轮询 (event loop) 机制_毅江的博客-CSDN博客js 宏任务和微任务 - 栴檀 - 博客园详解JavaScript中的Event Loop(事件循环)机制 - 知乎
04 阻止冒泡 **#
w3c方法是event.stopPropagation() IE中方法是window.event.cancelBubble = true
05 防止默认事件 **#
event.preventDefault() return false; ///写在函数的最后一句
06 怎样判断array 和 object ***#
使用数组和对象typeof,结果都是"object"
- 使用instanceof进行判断,A instanceof B即对象A是否构造了构造函数B,即返回true, 不是即返回false.
-
在typeof上进行enhancement, typeof数组和对象返回都是object, 但数组长度超过0及0的整数,object的长度为undefined
-
利用Object.prototype.toString.call()该方法将变量转换为代表其类型string
-
Array.isArray()
-
利用constructor判断属性
JS如何判断是数组还是对象 - 简书
07 隐式转换数据类型 **#
做项目经常涉及到这三种转换
- 其它类型的转数: 详细举例
- 其他类型的转布尔: 详细举例
- 其它类型的转字符串: 详细举例
JS 隐式转换类型 - 简书
08 说说盒子模型#
-
定义#
- 所有HTML元素可以看作是盒子CSS中,"box model"这个术语用于设计和布局。
- CSS盒子模型本质上是一个盒子,包装周围HTML元素包括:外距(margin)、边框(border)、内边距(padding)、实际内容(content)四个属性。
-
区别#
- 标准盒模型:
- 盒子的实际内容(content)的width/height=我们设置的width/height;
- 盒子的总宽度/高度=width/height padding border margin
- IE盒子模型(怪异盒模型)
- 浏览器的 width 属性不是内容的宽度,而是内容、内边距和边框宽度的总和;
- 盒子的(content)宽度 内边距padding 边框border宽度 = 我们设置的width(height),
- 盒子的总宽度/高度 = width/height margin = 宽度/高度的内容区 padding border margin。
- 标准盒模型:
-
CSS可指定盒子模型类型#3
box-sizing: border-box; // 使用怪盒模型 box-sizing: content-box;// 默认选项, 应用标准盒模型
盒子模型(标准盒模型、怪异盒模型)和前端面试 css3指定盒子模型类型box-sizing属性_慕课手记
09 算法#
一个数组0000001111111111111这样,你怎样才能找到第一个1,最底层?js原生写法, 例如,当第一个数字与第二个数字进行比较时,当第二个大于第一个元素时,就会发现第一个1。有没有更高效的写作方法?
使用循环或递归来实现
10 对象的key是数字吗? *#
可以是数字,object对应的key没有限制,但如果是数字,取值时不能使用英文句号(.),只能用[]取值。
11 async await 和promise和generator有什么区别#
-
相同点:#
这些都可以解决异步操作的地狱回调问题
-
async await 和promise对象差异:#
- async和promise都是异步法
- 区别是async结果是promise对象,async是promise的终结版。
- await只能在async中使用,await阻塞意味着暂停。您共同调用两个接口。第一个执行后,不输出结果。您必须等待第二个接口执行后才能返回这两个结果。将异步操作转化为同步操作是一种做法
-
async await和generator:#
- async是Generator的语法糖 ,也就是说,async是对generator的实现,而generator代码更复杂。
- generator 除解决回调区域问题外,还可作为迭代器使用。generator 语法一般用于语法redux-saga redux-saga 一般在umi或dva(一个集成redux、redux-saga、react-router-redux、react-router使用框架
12 手写promise ***#
-
promise的用法#
var promiseObj = new Promise(function (resolve, reject) { let offer =false;
setTimeout(() => {
if (offer) {
resolve({
msg: '上班去',
company: 'xxxx公司'
})
} else {
reject({
msg: '继续面试'
})
}
},1000);
});
// 获取promiseObj保存的数据
promiseObj.then(function(res){
console.log('成功的信息:',res);
},function(err){
console.log('失败的信息:',err);
})
-
以下是一个简单的promise实现, 想更深一步研究, 请看末尾的链接#
<script>
function MyPromise(callback) {
// 状态
this.status = "pending";
this.successFn;
this.errorFn;
// 处理成功的信息
this.resolve = (data) => {
// 修改状态
this.status = 'fulfilled';
// 在这里把成功的数据返回给.then的第一个参数
this.successFn && this.successFn(data);
};
// 处理失败的信息
this.reject = (data) => {
// 在这里把失败的数据返回给.then第二个参数
this.status = 'rejected';
this.errorFn && this.errorFn(data);
};
/**
* @param {*} successFn 成功的回调
* @param {*} errorFn 失败的回调
*/
this.then = (successFn, errorFn) => {
// 把传过来的两个函数保存起来, 供后面成功或失败的时候调用
this.successFn = successFn;
this.errorFn = errorFn;
};
callback(this.resolve, this.reject);
}
var promiseObj = new MyPromise(function (resolve, reject) {
let offer = true;
setTimeout(() => {
if (offer) {
resolve({
msg: "上班去",
company: "xxxx公司",
});
} else {
reject({
msg: "继续面试",
});
}
}, 1000);
});
promiseObj.then(
function (res) {
console.log("res", res);
},
function (err) {
console.log("err", err);
}
);
</script>
原文地址: 手写Promise - 实现一个基础的Promise - SegmentFault 思否
13 promise.all作用 ***#
- Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或 参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject), 失败的原因是第一个失败 promise 的结果。
- 它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。
- 通俗的说法:解决promise的同步调用问题,可以将多个异步操作转为同步操作,缺点:只要有一个promise返回错误,那么后面的promise都不会再执行
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
14 什么是工厂模式,有什么优缺点 *#
-
定义#
- 工厂模式是一种设计模式,目的是为了创建对象,它通常在类或类的静态方法中实现,
- 有以下目的:当创建相似对象是执行重复操作
- 当编译时,不知道具体类型的情况下,为工厂客户提供一个创建对象的接口
-
优缺点#
: 写好了工厂方法后,只要原料足够,我们可以无限次的创建新的对象 :
- 没有使用 new , 而是直接调用方法进行创建
- 每个对象都有自己的函数(像下面的例子中, 每创建一个对象, 就会创建两个函数, 若创建10个对象,就需要创建20个函数, 而这些函数都一模一样的, 完全没必要),浪费资源
//使用工厂方式创建一个对象
function createCat(name, sex) {
//1.原料
var obj = new Object();
//2.加工 -- 对属性进行赋值
obj.name = name;
obj.sex = sex;
//3.方法
obj.showName = function () {
console.log("小猫名称:" + this.name);
};
obj.showSex = function () {
console.log("小猫性别:" + this.sex);
};
//4.加工结束,--输出返回
return obj;
}
//工厂模式的使用
var cat1 = createCat("小花", "母的");
//调用工厂里的方法
cat1.showName();
cat1.showSex();
var cat2 = createCat("罗小黑", "公的");
//调用工厂里的方法
cat2.showName();
cat2.showSex();
接触过哪些设计模式: 工厂模式 、单例模式(数据库连接)、发布-订阅模式观也叫察者模式(双向绑定原理)、mvc模式、mvvm模式
// 发布订阅模式
1. 定义了对象间的一种一对多的依赖关系,当一个对象的状态发 生改变时,所有依赖于它的对象都将得到通知
2. JS中的事件就是经典的发布-订阅模式的实现(观察者甲和乙都订阅了body的点击事件, 当事件发布(被点击)时,它们都收到了通知
// 订阅
document.body.addEventListener('click', observer1, false);
document.body.addEventListener('click', observer2, false);
function observer1() {
console.log('我是观察者甲');
}
function observer2() {
console.log('我是观察者乙');
}
// 发布
document.body.click(); // click1 click2
js常见的十五种设计模式
15 图片/文件夹上传到后台是什么类型? *#
图片上传后台有三种格式:
-
file格式 (创建formData来完成file上传)#
var formData = new FormData();
$.each($("#imgfile")[0].files, function (i, file) {
formData.set("idcard", file); //idcard 字段 根据自己后端接口定
});
//processData: false, contentType: false,多用来处理异步上传二进制文件。
that.$indicator.open();
$.ajax({
url: "http://wjtest.jecinfo.cn:9090/indentity/check",
type: "POST",
data: formData, // 上传formdata封装的数据
....
});
-
base64格式#
<input type="file" id="imgfile">
<script>
var base64Pic = "";
document.getElementById("imgfile").onchange = function () {
var fileReader = new FileReader();
fileReader.readAsDataURL(this.files[0]);
fileReader.onload = function () {
base64Pic = fileReader.result;
console.log(base64Pic); //base64 可以直接放在src上 预览
};
};
</scrip>
-
Blob流格式#
16 原生基础数据类型和引用数据类型的区别 *#
学过数据结构的同学对于栈和堆都多少有点了解吧!不了解也没关系,学习JS中的栈和堆也一样的_,下面我们来看看栈和堆到底是何方神圣......
-
栈和堆#
:
栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。基本类型:String,Number,Boolean,Null,Undefined :
动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类 型的变量,实际上保存的不是变量本身,而是指向该对象的指针。引用类型:Function,Array,Object
-
区别#
:所有在方法中定义的变量都是放在栈内存中,随着方法的执行结束,这个方法的内存栈也自然销毁。
- 优点:存取速度比堆快,仅次于直接位于CPU中的寄存器,数据可以共享;
- 缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
:
- 堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(参数传递)。
- 创建对象是为了反复利用,这个对象将被保存到运行时数据区。 JS中的栈和堆 - 简书
17 深浅拷贝:#
-
浅拷贝/深度拷贝的区别#
-
深拷贝和浅拷贝最根本的区别在于是否真正获得一个对象的复制实体,而不是引用。
-
**浅拷贝:**仅仅是指向被复制的内存地址(即只拷贝对象的引用),如果原对象发生改变,那么浅拷贝复制出来的对象也会相应的改变。
-
:在内存的堆中开辟一块新的空间用来存放复制的对象, 也就是得到了一个新的对象
-
-
浅拷贝例子#
var obj = { name:'wsscat', age:0 } var obj2 = obj; obj2['c'] = 5; console.log(obj);//Object {name: "wsscat", age: 0, c: 5} console.log(obj2);Object {name: "wsscat", age: 0, c: 5} var arr1 = [1,2,3,4]; var arr2 = arr1; arr2.push(5); console.log(arr1); // [1,2,3,4,5] console.log(arr2); // [1,2,3,4,5]
-
深拷贝(只拷贝第一层)#
深拷贝又分为第一层拷贝和完全拷贝, 只拷贝第一层的深拷贝适用于对象/数组的属性/成员都是基本数据类型
// (1)for循环拷贝对象第一层 var obj = {a:1,b:2,c:3} var obj2 = {}; for (var key in obj) { obj2[key] = obj[key]; } // (2) 扩展运算符拷贝对象第一层 var obj = {a:2,b:3:c:4}; var obj2 = [...obj]; // (3) slice数组拷贝第一层 var arr1 = ["前端","安卓","苹果"]; var arr2 = arr1.slice(0); arr2[0] = "后端"; console.log("原始值:" + arr1 );//前端,安卓,苹果 console.log("新值:" + arr2);//后端,安卓,苹果 // (4) concat数组拷贝第一层 var arr1 = ["前端","安卓","苹果"]; var arr2 = arr1.concat(); arr2[0] = "后端"; console.log("原始值:" + arr1 );//前端,安卓,苹果 console.log("新值:" + arr2);//后端,安卓,苹果
-
深拷贝(完全拷贝)#
// (1)JSON(对象和数组都适用) var obj = {a:2,b:3:c:4}; var str = JSON.stringfy(obj); var obj2 = JSON.parse(str); // (2)for循环完全拷贝 function deepClone(obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制, 递归调用(自己调用自己) objClone[key] = obj[key]; } } } } return objClone; } let arr = [1,2,{a:2}]; let arr2 = deepClone(arr); arr2[2].a=100; arr[2].a; // 2,arr和arr2是两个完全不同的数组, 相互不会受影响 let obj = { a:1, b: {x:1} } let obj2 = deepClone(obj); obj2.b.x = 100; obj.b.x; // 1 完全复制, 两个相互不受影响
JS数组的深拷贝和浅拷贝_可乐6666的博客-CSDN博客_js数组深拷贝和浅拷贝【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法 - 听风是风 - 博客园
18 弹性布局。浮动布局 table布局 *#
- 弹性布局:使用 百分比、rem 、flex 自适应布局
- 浮动布局:使用 float clear
- table布局:一般用于后台显示
- 自适应布局和响应式布局:一般需要用到media媒体查询完成,需要根据屏幕宽度的不同,写多个css样式文件
19 flex 弹性盒子#
-
的水平居中和垂直居中
水平:justify-content:center; 垂直:align-content:center;
-
flex属性
- flex:1 的值是1 1 0%,【父控件有剩余空间占1份放大,父控件空间不足按1缩小,自身的空间大小是0%】 ***
- flex属性 是 flex-grow、flex-shrink、flex-basis三个属性的缩写。 推荐使用此简写属性,而不是单独写这三个属性。
-
flex-grow:定义项目的的放大比例; 默认为0,即 即使存在剩余空间,也不会放大; 所有项目的flex-grow为1:等分剩余空间(自动放大占位); flex-grow为n的项目,占据的空间(放大的比例)是flex-grow为1的n倍。
-
flex-shrink:定义项目的缩小比例; 默认为1,即 如果空间不足,该项目将缩小; 所有项目的flex-shrink为1:当空间不足时,缩小的比例相同; flex-shrink为0:空间不足时,该项目不会缩小; flex-shrink为n的项目,空间不足时缩小的比例是flex-shrink为1的n倍。
-
flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(main size),浏览器根据此属性计算主轴是否有多余空间, 默认值为auto,即 项目原本大小; 设置后项目将占据固定空间。 所以flex属性的默认值为:0 1 auto (不放大会缩小) flex为none:0 0 auto (不放大也不缩小) flex为auto:1 1 auto (放大且缩小)
20 闭包是什么,闭包形成的原因和闭包的用途 *#
闭包定义: 闭包就是能够读取其他函数内部变量的函数。 闭包形成的原因: 当某个函数的作用域链还引用着其他函数的活动对象时,就会形成闭包。 闭包的应用场景:
- 封装私有变量
- 私有变量(私有属性)是后台语言经常用的东西, 意思是这个属性是私有的,外部是无法访问这个变量的
- 如果需要访问也必须通过指定的方法来进行获取和修改
<script>
function getCat() {
// 私有变量name,一般前面加_来表示私有
var _name = '白猫';
return {
getName: function () {
return _name;
},
setName: function (newName) {
_name = newName;
}
}
}
var cat = getCat();
let name = cat.getName(); // 白猫
console.log('name',name);
// 修改猫名
cat.setName('黑猫');
let newName = cat.getName(); // 黑猫
console.log('newName',newName);
</script>
- 模仿块级作用域 (ES5 中没有块级作用域)
<script>
// es6没出来之前,用var定义变量存在变量提升问题
for (let i = 0; i < 10; i++) {
console.info(i)
}
alert(i) // 变量提升,弹出10//为了避免i的提升可以这样做
(function () {
for (var i = 0; i < 10; i++) {
console.info(i)
}
})()
alert(i); // 会报错
// 根据以下代码,说出打印结果
for (var i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
}, i * 100);
} // 结果是打印了10个10,并不是我们希望0-9,要想实现我们期待的结果可以使用闭包实现
for (var i = 0; i < 10; i++) {
(function (j) {
setTimeout(() => {
console.log(j);
}, j * 100);
})(i);
}
/***上面的代码,循环了10次,创建了10个函数,每个函数传入的值都不一样* setTimeout里面的函数是个闭包,它的外层函数的变量j,因为闭包缘故,没有被销毁,打印的时候可以取到它的值*/
</script>
- 实现 JS 的模块
<script>
function Common(window) {
var DEBUG = "debug";
function log(args) {
console.log(args);
}
/** debug 利用闭包 */
function debug(args) {
console.log(DEBUG + args);
}
/** 编写 */
function write(args) {
document.write(args);
}
return {
log: log,
debug: debug,
write: write
};
}
//调用
var common = Common(window);
common.log("121");
common.debug(12232);
common.write("dadsa");
</script>
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。 js之闭包是如何产生的?
21 什么是内存泄漏,都什么情况容易产生内存泄漏 **#
-
内存泄漏:#
即为变量内容持续占用内存空间,不释放,垃圾回收机制也没有将该内存回收的情况
-
内容泄露的原因:#
- 死循环
- 定时器没有清除
- 绑定的事件没有解除
- 递归调用没有结束条件
-
主要存在内存泄漏的问题点:#
- BOM DOM对象泄漏
- scipt中存在对BOM DOM对象的引用
- javaScript对象泄漏
- 闭包函数导致的泄漏 主要关注的代码点
- DOM中的addEventLisner 函数及派生的事件监听, 比如Jquery 中的on 函数, vue 组件实例的 $on 函数,第三方库中的初始化函数
- BOM对象的事件监听,比如webSocket的监听事件
- 避免不必要的函数引用
- 如果是要render函数,避免在html标签中DOM BOM事件
22 原型 ,原型链,继承的方式 ***#
-
原型#
-
每一个都有一个属性prototype, 这个prototype属性指向了一个对象, 而这个对象正是用该构造函数创建出来的实例的, 而实例都会从原型继承属性, (你可以把原型理解成实例的"父亲", 括号内容不用背).
-
每一个原型都有一个属性constructor, 指向了该构造函数
-
每个实例都有一个内部指针
__proto__
指向了原型<script> // 实例讲解 function Cat(name, age) { this.name = name; this.age = age; } // 1.Cat有一个属性prototype, 是一个对象 console.log(typeof Cat.prototype); // object // 2.每一个原型都有一个一个属性constructor指向了构造函数, 可以使用dir来查看 // dir(Cat); Cat.prototype.constructor === Cat; // true // 小红的丈夫的妻子是小红, 小红的丈夫的妻子的丈夫的妻子的丈夫.... // 3.每一个实例都有一个内部指针__proto__指向了原型, 实例继承了原型的属性 var cat = new Cat('白猫',2); cat.__proto__ === Cat.prototype; Cat.prototype.from = '黑龙江'; console.log(cat); // 实例cat并没有from属性 console.log(cat.from); // from属性是继承了protype的属性 console.log(cat); </script>
-
-
原型链,背诵#
-
每个实例对象(object)都有一个私有属性(称之为
__proto__
)指向它的构造函数的原型对象() -
该原型对象也有一个自己的原型对象(
__proto__
) -
层层向上直到一个对象的原型对象为
null
根据定义,null
没有原型,并作为这个中的最后一个环节。 -
几乎所有 JavaScript 中的对象都是位于原型链顶端的Object的实例 (Object.prototype就是终极原型)
-
结论: 当我们访问一个实例的属性时, 会先查找该实例由没有这个属性, 没有的话就会到它的原型去查找, 还没有就会一层一层的往上查找, 一直找到Object的原型为止, 有就返回, 没有就返回undefined.
// 实例讲解 // 上面的第1点,第2点,第3点 let p1 = cat.__proto__; let p2 = p1.__proto__; let p3 = p2.__proto__; // null, p2是就是原型链的最后一环 // 第4点 cat.__proto__.__proto__ === Object.prototype; let arr = [1,2,3]; arr.__proto__.__proto__ === Object.prototype; let date = new Date(); date.__proto__.__proto__ === Object.prototype; let obj = {a:2}; // obj的构造函数就是Object本身,所以 obj.__proto__ === Object.prototype;
-
-
原型链继承#
让一个构造函数的prototyp等于另外一个构造函数创建的实例就实现了原型链继承
<script> Animal.prototype.say = function () { console.log('我是动物'); } function Animal() { this.type = '动物'; } // 创建动物的实例 let animal = new Animal(); // 让Cat的原型指向animal,就实现了继承,即Cat创建出来的实例也能拥有Animal及其原型的属性 Cat.prototype = animal; function Cat(name, age) { this.name = name; this.age = age; } var cat = new Cat(); // 实例cat继承了Animal的type属性 console.log(cat.type); // 实例cat继承了Animal原型上的方法 cat.say(); </script>
-
其他继承方法(了解)#
-
原型链继承
-
借用构造函数继承
-
组合式继承
-
寄生式继承
-
寄生组合式继承
-
es6 class继承(理解)
-
使用extends进行继承
-
子类使用super关键字
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
<script> class Father { constructor(name) { this.name = name; } sayName() { console.log(this.name); } } class Child extends Father { constructor(name, age) { super(name); this.age = age; } } var child = new Child('Tom', 22); child.sayName(); </script>
-
-
23 js异步轮询机制#
- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
- 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
- "任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
- 事件循环(event loop)
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
<script>
function test() {
var startTime = Date.now();
setTimeout(() => {
var endTime = Date.now();
console.log('时间过去了:', endTime - startTime, 'setTimeout开始执行');
}, 1000);
var count = 1000000000;
for (;;) {
count--;
if (count === 0) {
console.log("时间到");
break;
}
}
console.log(1);
console.log(2);
console.log(3);
}
test();
</script>
24 使用node.js 创建本地服务器 *#
25 Git常用命令 *#
- git init 初始化 *
- git clone 克隆代码库 *
- git config 配置
- git add 增加文件到暂存区 *
- git commit 提交暂存区到仓库 *
- git branch 名称 新建分支 *
- git checkout 切换分支 *
- git merge 合并分支 *
- git branch -d 删除分支 *
- git tag 打tag 包 *
- git status 查看状态 *
- git log 查看日志 *
- git diff 查看暂存区和工作区差异
- git fetch 下载远程仓库的变动 *
- git pull 取回远程仓库变化,并与本地分支合并 *
- git push 上传本地指定分支到远程仓库 *
26 跨域的解决方案 *#
-
定义#
- 知其然知其所以然,在说跨域方法之前,我们先了解下什么叫跨域,浏览器有同源策略,只有当“协议”、“域名”、“端口号”都相同时,才能称之为是同源,其中有一个不同,即是跨域。
- 那么同源策略的作用是什么呢?同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
- 那么我们又为什么需要跨域呢?一是前端和服务器分开部署,接口请求需要跨域,二是我们可能会加载其它网站的页面作为 iframe 内嵌。
-
跨域的几种方式#
- jsonp
- jsonp缺点: 只能是get方式不能是post方式
- jsonp原理:script标签的src属性可以跨域
- proxy代理, 下面这些这些都是属性使用proxy代理进行跨域的例子
- vue(实际是webpack)的devServer的proxy设置(只能是打包前使用,打包后需要后台配置跨域)
- nginx反向代理
- node使用中间件设置跨域
- 后台头部设置 Access-Control-Allow-Origin ,cors
- 其他 方式: a. document.domain + iframe (只有在主域相同的时候才能使用该方法) b. location.hash + iframe c. window.name + iframe d. postMessage(HTML5中的XMLHttpRequest Level 2中的API) e. web socket web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。
- jsonp
27 for循环定时器打印产生问题,怎么解决 **#
<script>
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
</script>
打印结果为5个6;
- 原因是:js是单线程,有任务队列,任务队列分为两种,同步任务和异步任务。
- 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
- 异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
- 任务执行顺序: 所以循环是同步任务先执行,当执行完之后,当setTimeout的异步操作准备好后,通知主线程,主线程将其从异步队列中取出来,再执行,所以当循环完成时,i的值位6,setTimeout再执行,打印5个6
28 http协议详解 http请求方式有 http响应状态码 *#
-
http 特点:#
- 支持客户/服务器模式。
- 简单快速:。
- 灵活:
- 无连接:
- 无状态:
-
http请求由三部分组成,分别是:请求行、消息报头、请求正文 请求方法(所有方法全为大写)有多种,各个方法的解释如下: GET 请求获取Request-URI所标识的资源 POST 在Request-URI所标识的资源后附加新的数据 HEAD 请求获取由Request-URI所标识的资源的响应消息报头 PUT 请求服务器存储一个资源,并用Request-URI作为其标识 DELETE 请求服务器删除Request-URI所标识的资源 TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断 CONNECT 保留将来使用 OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
-
在接收和解释请求消息后,服务器返回一个HTTP响应消息。#
HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文 3xx:重定向--要完成请求必须进行更进一步的操作 4xx:客户端错误--请求有语法错误或请求无法实现 5xx:服务器端错误--服务器未能实现合法的请求
301 永久移动,请求的资源被永久的移动到新url,返回信息会包括新的url。浏览器会自动定向到新url 302 临时移动,资源只是临时被移动,客户端赢继续使用原有url 304 未修改,所请求的资源未修改,服务器返回此状态码是=时,不会返回任何资源,客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
400 Bad Request //客户端请求有语法错误,不能被服务器所理解,解决方法:修改请求的参数及语法 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 , 解决方式:即没有启用任何认证方式,只需要在IIS Manager里面启用需要的认证方式即可。 即被Authorization Rule阻挡,则需要分析这个authorization rule是否是否必须来决定对他的更改。 403 Forbidden //服务器收到请求,但是拒绝提供服务 1. 你的IP被列入黑名单。 2、你在一定时间内过多地访问此网站(一般是用采集程序),被防火墙拒绝访问了。 3、网站域名解析到了空间,但空间未绑定此域名。 4、你的网页脚本文件在当前目录下没有执行权限。 6、以http方式访问需要ssl连接的网址。 7、浏览器不支持SSL 128时访问SSL 128的连接。 8、在身份验证的过程中输入了错误的密码。
解决方式:
1、重建dns缓存,对于一些常规的403 forbidden错误,马海祥建议大家首先要尝试的就是重建dns缓存,在运行中输入 cmd,然后输入ipconfig /flushdns即可。如果不行的话,就需要在hosts文件里把主页解析一下了。 2、修改文件夹安全属性 3、关于apache导致的403 forbidden错误,需设置Apache的配置文件。 4、关于HawkHost空间出现403 Forbidden错误需设置htaccess文件。
404 Not Found //请求资源不存在,eg:输入了错误的URL 解决办法:输入正确的url地址 405 请求方式不对 ,比如原本需要post方式请求的,你写了get方式请求
29 一个页面从发送http请求到渲染页面的全过程(http事务流程)***#
- 域名解析 --> 2.发起TCP的3次握手 --> 3.建立TCP连接后发起http请求 --> 4.服务器响应http请求,浏览器得到html代码 --> 5.浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 6.浏览器对页面进行渲染呈现给用户 从输入URL到页面加载的全过程 - 小火柴的蓝色理想 - 博客园
30.1 tcp和udp的区别 *#
TCP与UDP区别总结:
-
TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
-
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
-
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
-
每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
-
TCP首部开销20字节;UDP的首部开销小,只有8个字节6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
30.2 什么是长连接 *#
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。 当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等), 每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。 而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码: Connection:keep-alive 在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时 ,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个 时间。实现长连接需要客户端和服务端都支持长连接。
31 ajax是同步还是异步,ajax的流程 *#
ajax是异步的, 流程: (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象. (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息 (3)设置响应HTTP请求状态变化的函数. (4)发送HTTP请求 .(sned) (5)获取异步调用返回的数据.(onreadystatechange) (6)使用JavaScript和DOM实现局部刷新.
32 h5新特性 ***#
-
语义化标签#
-
Canvas绘图 ***#
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> canvas { border: 1px solid; } </style> </head> <body> <canvas id="myCanvas" width="600" height="600"></canvas> <script> var c = document.getElementById("myCanvas"); var cxt = c.getContext("2d"); //获取2d作图对象 cxt.moveTo(10, 10); //画线的的起始点 cxt.lineTo(150, 50); //画线 cxt.lineTo(10, 50); cxt.stroke(); //线 cxt.fillStyle = "#FF0000"; //填充颜色 cxt.beginPath(); //开始路径 cxt.arc(70, 18, 15, 0, Math.PI * 2, true); //画圆 cxt.closePath(); //结束路径 cxt.fill(); //填充 var img = document.createElement('img'); img.src = 'https://www.w3school.com.cn/i/eg_dragdrop_w3school.gif'; img.onload = function () { cxt.drawImage(img, 200, 200); //画布填充图片 } </script> </body> </html>
-
SVG绘图#
-
地理定位 *#
可以使用百度地图, 腾讯地图或者高德地图提交的公共api完成地图地位和地图绘制
-
拖放API *#
- draggable="true" 讲需要被拖放的数据加上此属性 - setData()保存数据 - drag ondrag 当拖动元素或选中的文本时触发。 - dragend ondragend 当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键). (见结束拖拽) - dragenter ondragenter 当拖动元素或选中的文本到一个可释放目标时触发(见 指定释放目标)。 - dragexit ondragexit 当元素变得不再是拖动操作的选中目标时触发。 - dragleave ondragleave 当拖动元素或选中的文本离开一个可释放目标时触发。 - dragover ondragover 当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。 - dragstart ondragstart 当用户开始拖动一个元素或选中的文本时触发(见开始拖动操作)。 - drop ondrop 当元素或选中的文本在可释放目标上被释放时触发(见执行释放)。
// 拖放例子 <!DOCTYPE HTML> <html> <head> <style type="text/css"> #div1 { width: 198px; height: 66px; padding: 10px; border: 1px solid #aaaaaa; } </style> </head> <body> <p>请把 W3School 的图片拖放到矩形中:</p> <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div> <br /> <img id="drag1" src="https://www.w3school.com.cn/i/eg_dragdrop_w3school.gif" draggable="true" ondragstart="drag(event)" /> <script type="text/javascript"> function allowDrop(ev) { ev.preventDefault(); } // 拖放时把元素id存起来 function drag(ev) { ev.dataTransfer.setData("Text", ev.target.id); } // 放下时, 获取元素id,并根据id获取元素,并把元素插入到目标元素 function drop(ev) { ev.preventDefault(); var data = ev.dataTransfer.getData("Text"); var $ele = document.getElementById(data); ev.target.appendChild($ele); } </script> </body> </html>
-
Web Storage * (浏览器缓存)#
*1.特性 一般由服务器生成,可设置失效时间,(设置过期时间是小于当前时间)。 如果在浏览器端生成Cookie,默认是关闭浏览器后失效;大小 4K左右 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 需要程序员自己封装,源生的Cookie接口不友好
除非被清除,否则永久保存大小 5M 仅在客户端(即浏览器)中保存,不参与和服务器的通信 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
仅在当前会话下有效,关闭页面或浏览器后被清除 大小 5M 仅在客户端(即浏览器)中保存,不参与和服务器的通信 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
-
COOKIE是如何工作的?
Cookie可用于客户端数据的存储,在没有其它存储办法时,使用这种方式是可行的,但随着现在浏览器开始支持各种各样 的存储方式而逐渐被废弃。 由于服务器指定Cookie以后浏览器的每次请求都会携带Cookie数据,这会带来额外的性能负 担(尤其是在移动环境下)。 新的浏览器API已经允许开发者直接在本地存储数据,如可以使用Web storage API (本地 存储和会话存储)和IndexedDB(索引数据库)。
- COOKIE主要用在以下三个方面: 会话状态管理(如用户登录状态、购物车) 个性化设置(如用户自定义设置) 浏览器行为跟踪(如跟踪分析用户行为)
-
COOKIE的缺陷 每个 HTTP 请求中都包含 Cookies,从而导致传输相同的数据减缓我们的 Web 应用程序。 每个 HTTP 请求中都包含 Cookies,从而导致发送未加密的数据到互联网上,可能会导致数据泄露,虽然进行过加密,但是攻击者拿到cookie后仍然可以登录,因为难以识别是否为同一个用户在登陆。 Cookies 只能存储有限的 4KB 数据,对于复杂的存储需求来说是不够用的。
-
sessionStroage有哪些应用场景? 答: 在不需要和服务器交互的场所,用来存储用户数据之类的,可以在路由页跳转的时候取出更改储存,减少调用接口的次数,减轻服务器压力。
-
用storage怎么来判断用户是否需要再登陆? 答:可以用加密的方法存储,每次用户访问的时候可以取出调用服务器接口作为参数发送进行对比,存在账号密码就直接跳过登录页。
-
localStorage是否可以在同源窗口共享? 答:同一浏览器的相同域名和端口的不同页面间可以共享相同的 localStorage,但是不同页面间无法共享sessionStorage的信息。
-
-
WebSocket#
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。(支付、客服模块可以使用这个技术)
32 css3新特性 *** 动画效果#
-
css3选择器#
CSS3选择器大全_Terry_wn的博客-CSDN博客_css3选择器
-
css新增样式属性#
border-radius border-image background-size background-origin background-clip:规定背景的绘制区域。 linear-gradient():线性渐变。 radial-gradient():径向渐变。 word-break:定义如何换行。 word-wrap:允许长的内容可以自动换行。 text-overflow:指定当文本溢出包含它的元素,应该发生什么。 text-shadow:文字阴影。 transform-style:指定嵌套元素是怎样在三维空间中呈现。 2D转换方法 rotate(angle):定义 2D 旋转,在参数中规定角度。 translate(x,y):指定元素在二维空间中的位移。X轴方向向右,Y轴方向向下。 scale(n):定义 2D 缩放转换。 matrix(a,b,c,d,e,f):定义 2D 转换,使用六个值的矩阵。 skew(x-angle,y-angle):定义沿着 X 和 Y 轴的 2D 倾斜转换。 perspective(n):为 3D 转换元素定义透视视图。 translate:指定元素在的位移。 matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n):定义 3D 转换,使用 16 个值的 4x4 矩阵。 过渡 transition:设置元素当过渡效果,四个简写属性为: * animation:为元素添加动画,是一个简写属性。 *
-
css新增的一些伪类#
1、p:first-of-type 选择器匹配属于其父元素的特定类型的首个子元素的每个元素。 2、p:last-of-type 选择器匹配属于其父元素的特定类型的最后一个子元素的每个元素。 3、p:only-of-type 选择器匹配属于其父元素的特定类型的唯一子元素的每个元素。 4、p:only-child 选择器匹配属于其父元素的唯一子元素的每个元素。 5、p:nth-child(2) 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型。n 可以是数字、关键词或公式。 6、:enabled :disabled表单控件的禁用状态。 7、:checked:checked 选择器匹配每个选中的输入元素(仅适用于单选按钮或复选框)。 Flex弹性布局 * 媒体查询 media *
33 es6新特性 *#
let const * 变量的解构赋值 *
<script>
let [a, b, c] = [1, 2, 3];
let [head, ...tail] = [1, 2, 3, 4];
let { foo, bar } = { foo: "aaa", bar: "bbb" };
</script>
字符串扩展
let text='abcdefg';
for (let i of text){
console.log(i);
}
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
repeat方法返回一个新字符串,表示将原字符串重复n次。
padStart()用于头部补全,
padEnd()用于尾部补全。
模板字符串 `aaa{$test}`
数值的扩展:
Number.isFinite()用来检查一个数值是否为有限的(finite)。
Number.isNaN()用来检查一个值是否为NaN。
Number.parseInt(),转整型
Number.parseFloat()转浮点型
Number.isInteger()用来判断一个值是否为整数
Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.sign方法用来判断一个数到底是正数、负数、还是零。
Math.cbrt方法用于计算一个数的立方根。
Math.sign()用来判断一个值的正负,但是如果参数是-0,它会返回-0。ES2016 新增了一个指数运算符(**)。
数组的扩展:
(1)Array.from方法用于将两类对象转为真正的数组:
类似数组的对象(array-like object)
可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
(2)Array.of方法用于将一组值,转换为数组。
(3)Array.prototype.copyWithin(target, start = 0, end = this.length)数组实例的copyWithin方 法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用 这个方法,会修改当前数组。
(4)数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回 调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
(5)fill方法使用给定值,填充一个数组。
(6)entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象
(详见《Iterator》一章),可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values() 是对键值的遍历,entries()是对键值对的遍历。Array.prototype.includes方法返回一个布尔值,表示某个 数组 是否包含给定的值,与字符串的includes方法类似。该方法属于ES7,但Babel转码器已经支持。
函数的扩展:
函数参数的默认值
与解构赋值默认值结合使用
函数的 length 属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真
ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
扩展运算符 ... *****
替代数组的apply方法
// ES5的写法
Math.max.apply(null, [14, 3, 77])
// ES6的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
扩展运算符的应用:合并数组 与解构赋值结合 函数的返回值 字符串 实现了Iterator接口的对象 Map和Set结构,Generator函数
/************/
严格模式 'use strict';
重点掌握,重点重点
箭头函数 ES6允许使用“箭头”(=>)定义函数。 箭头函数可以保留this的指向 *****
箭头函数注意点:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。
对象的扩展:
1. Object.is() 比较两个值是否相等
2. Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
属性的遍历
3. ES6一共有5种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举 属性)。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有Symbol属性。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚 举。
4. Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本 身。它是 ES6 正式推荐的设置原型对象的方法。该方法与Object.setPrototypeOf方法配套,用于读取一个对象的 原型对象。
5. Object.keys()引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历 (enumerable)属性的键名。
6. Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键 值。
7. Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
set 和 map 数据类型 *
set可以用于数组去重,是无序的,set中不包含重复的元素
map 的key值可以是数组对象字符串等格式
Map类似于一个对象,是键值对的集合,键值可以是字符串,各种类型,对象。
proxy ***
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
vue双向绑定原理的Object.defineProperty 更改为了 Proxy,性能有所优化
promise *
解决异步回调地狱问题
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
.then() Promise实例添加状态改变时的回调函数。
.catch() 用于指定发生错误时的回调函数。
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。
all中的内容是两个异步操作,只有等到它们的结果都返回了,才会触发pickTopRecommentations这个回调函数。
Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。
Promise.resolve()有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用。
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
.done()Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到
.finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
Generator 函数的语法 ***
迭代器或解决异步调用回调地狱
function* gen() {
yield 123 + 456;
}
redux-saga中使用了该语法
async await *
解决异步回调地域问题,一般和promise一起使用
class 语法糖 ;解决了js中没有类的概念,需要使用 function做为构造函数来使用的问题,简化了继承 *
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
模块module *
引入模块 import
输出模块 export
34 typescript *#
- 基础类型: boolean\number\string\数组\元组(元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同)\枚举(enum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字)\ Any\ viod\null\undefin