一、数据类型
-
基本数据类型:String,Boolean,Number,Undefined, Null(返回的一个空对象)Symbol(ES6新增)
-
引用数据类型:Object(Array,Function,Date)
-
区别:基本类型数据的变量值直接存在栈中,而引用数据类型的变量,其值存在堆中,需要通过存储在栈中的地址访问堆中数值(js没有堆栈的概念,但是为了更好理解代码的一些执行方式,所有才有的)
2. 数据类型检测的方式有哪些
(1)typeof
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
其中数组、对象、null都会被判断为object
(2)instanceof
instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
复制代码
(3) constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
constructor有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了:
function Fn(){};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor===Fn); // false
console.log(f.constructor===Array); // true
3. 判断数组的方式有哪些
- 通过instanceof做判断
obj instanceof Array
- 通过ES6的Array.isArray()做判断
Array.isArrray([1,3]) // true;
4. null和undefined区别
Undefined 和 Null 都是基本数据类型 undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
5.为什么0.1+0.2 ! == 0.3
6. intanceof 操作符的实现原理及实现
instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
7. isNaN 和 Number.isNaN 函数的区别?
- 函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。
- 函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。
8. == 操作符的强制类型转换规则?
对于 == 来说,如果对比双方的类型不一样,就会进行类型转换
就会进行如下判断流程:
- 首先会判断两者类型是否**相同,**相同的话就比较两者的大小;
- 类型不相同的话,就会进行类型转换;
- 会先判断是否在对比
null和undefined,是的话就会返回true - 判断两者类型是否为
string和number,是的话就会将字符串转换为number - 判断其中一方是否为
boolean,是的话就会把boolean转为number再进行判断
9.字符串的转换
1.toSting() // num.toString()
2.隐式转换(加号拼接字符串)
10.数字型的转换
1.parseInt(String)函数 parserFloat(string)函数 2.Number()强制转换成函数
11.布尔型的转换
Boolean()函数
代表空、否定的值转换为false,如'',0,NaN,null,undefined
console.log(Boolean(NaN)) // false
12.NaN undefined
如果一个变量声明未赋值 就是 undefined 未定义数据类型
undefined 和数字相加 最后的结果是 NaN
13.短路运算&& ||
- 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数的值,如果为 false 就返回第二个操作数的值。
- && 则相反,如果条件判断结果为 true 就返回第二个操作数的值,如果为 false 就返回第一个操作数的值。
二、ES6
(1)块级作用域: 块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES5中的两个问题:
- 内层变量可能覆盖外层变量
- 用来计数的循环变量泄露为全局变量
(2)变量提升: var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。
(3)给全局添加属性: 浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。
(4)重复声明: var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量。const和let不允许重复声明变量。
(5)暂时性死区: 在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。
(6)初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
2. const对象的属性可以修改吗
const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。
但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。
3. 如果new一个箭头函数的会怎么样
箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数。
new操作符的实现步骤如下:
- 创建一个对象
- 将构造函数的作用域赋给新对象(也就是将对象的__proto__属性指向构造函数的prototype属性)
- 指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象添加属性和方法)
- 返回新的对象
所以,上面的第二、三步,箭头函数都是没有办法执行的。
4. 箭头函数与普通函数的区别
(1)箭头函数比普通函数更加简洁
- 如果没有参数,就直接写一个空括号即可
- 如果只有一个参数,可以省去参数的括号
- 如果有多个参数,用逗号分割
- 如果函数体的返回值只有一句,可以省略大括号 (2)箭头函数没有自己的this
(3)箭头函数没有自己的arguments
(4)箭头函数没有prototype
5. 箭头函数的this指向哪⾥?
箭头函数不绑定this 箭头函数没有自己的this关键字
- 如果在箭头函数中使用this
- 总是指向最近的外层作用域中的this所指对象
function fn() {
console.log(this); // obj
return () => {
console.log(this); // 最外层作用域fn fn指向obj 即this指向obj
}
}
const obj = { name: 'zhangsan' };
const resFn = fn.call(obj);
resFn();
6. 对rest参数的理解
// 剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
const sum = (...args) => { // args形参 数组
let total = 0;
args.forEach(item => total += item);
return total;
};
console.log(sum(10, 20)); // 30
// 剩余参数和解构配合使用
let ary1 = ['张三', '李四', '王五'];
let [s1, ...s2] = ary1;
console.log(s1); // '张三'
console.log(s2); // ['李四', '王五']
7. 扩展运算符
- 扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。
对象的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。
(2)数组扩展运算符 数组的扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每次只能展开一层数组。
console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
// 1 [2, 3, 4] 5
- 将数组转换为参数序列
let ary = ["a", "b", "c"];
// ...ary // "a", "b", "c"
console.log(...ary); // a b c
- 复制数组
const arr1 = [1, 2];
const arr2 = [...arr1];
要记住:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。
- 合并数组
如果想在数组内合并数组,可以这样:
let ary1 = [1, 2, 3];
let ary2 = [4, 5, 6];
// // ...ary1 // 1, 2, 3
// // ...ary1 // 4, 5, 6
let ary3 = [...ary1, ...ary2];
console.log(ary3); // [1, 2, 3, 4, 5, 6]
// 合并数组的第二种方法
let ary4 = [1, 2, 3];
let ary5 = [4, 5, 6];
ary4.push(...ary5);
console.log(ary4);
- 利用扩展运算符将伪数组转换为真正的数组
8. 对象与数组的解构的理解
- 数组解构:
// 数组解构允许我们按照一一对应的关系从数组中提取值 然后将值赋值给变量
let ary = [1, 2];
let [a, b, c] = ary;
console.log(a); // 1
console.log(b); // 2
// 如果解构不成功,变量的值为undefined
console.log(c); // undefined
- 对象解构
// 对象解构允许我们使用变量的名字匹配对象的属性 匹配成功 将对象属性的值赋值给变量
let person = { name: 'lisi', age: 30, sex: '男' };
// let { name, age, sex } = person;
// console.log(name)
// console.log(age)
// console.log(sex)
let { name: myName } = person; // myname属于别名
console.log(myName); // lisi
9. ES6中模板语法与字符串处理
// 1. ES6新增的创建字符串的方式,使用反引号定义
// 模板字符串中可以解析变量
let name = `鬼脚七`;
let sayhello = `hello,myname is ${name}`;
console.log(sayhello);
let result = {
name: '酒神',
age: 34
};
// 2. 模板字符串中可以换行
let html = `
<div>
<span>${result.name}</span>
<span>${result.age}</span>
</div>
`;
console.log(html);
// 3. 在模板字符串中可以调用函数
const fn = () => {
return '我是fn函数';
};
html = `我是模板字符串 ${fn()}`;
console.log(html);
三、JavaScript基础
1. new操作符的实现原理
new操作符的执行过程:
(1)首先创建了一个新的空对象
(2)设置原型,将对象的原型设置为函数的 prototype 对象。
(3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
(4)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
2. map和Object的区别
| Map | Object | |
|---|---|---|
| 意外的键 | Map默认情况不包含任何键,只包含显式插入的键。 | Object 有一个原型, 原型链上的键名有可能和自己在对象上的设置的键名产生冲突。 |
| 键的类型 | Map的键可以是任意值,包括函数、对象或任意基本类型。 | Object 的键必须是 String 或是Symbol。 |
| 键的顺序 | Map 中的 key 是有序的。因此,当迭代的时候, Map 对象以插入的顺序返回键值。 | Object 的键是无序的 |
| Size | Map 的键值对个数可以轻易地通过size 属性获取 | Object 的键值对个数只能手动计算 |
| 迭代 | Map 是 iterable 的,所以可以直接被迭代。 | 迭代Object需要以某种方式获取它的键然后才能迭代。 |
| 性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
3. map和weakMap的区别
-
Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
-
WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。但是 WeakMap 只接受对象作为键名( null 除外),不接受其他类型的值作为键名。而且 WeakMap 的键名所指向的对象,不计入垃圾回收机制。
5. 常用的正则表达式有哪些?
// (1)匹配 16 进制颜色值
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
// (2)匹配日期,如 yyyy-mm-dd 格式
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
// (3)匹配 qq 号
var regex = /^[1-9][0-9]{4,10}$/g;
// (4)手机号码正则
var regex = /^1[34578]\d{9}$/g;
// (5)用户名正则
var regex = /^[a-zA-Z$][a-zA-Z0-9_$]{4,16}$/;
对JSON的理解
JSON 是一种基于文本的轻量级的数据交换格式。它可以被任何的编程语言读取和作为数据格式来传递。 在 js 中提供了两个函数来实现 js 数据结构和 JSON 格式的转换处理
- JSON.stringify 函数
在前端向后端发送数据时,可以调用这个函数将数据对象转化为 JSON 格式的字符串。
- JSON.parse() 函数 当从后端接收到 JSON 格式的字符串时,可以通过这个方法来将其解析为一个 js 数据结构,以此来进行数据的访问。
7. JavaScript脚本延迟加载的方式有哪些?
-
动态创建 DOM 方式: 动态创建 DOM 标签的方式,可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本。
-
使用 setTimeout 延迟方法: 设置一个定时器来延迟加载js脚本文件
-
让 JS 最后加载: 将 js 脚本放在文档的底部,来使 js 脚本尽可能的在最后来加载执行。
-
defer 属性
8. JavaScript 类(伪)数组对象的定义?
一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法
通过 Array.from() 方法来实现转换数组
9. 数组有哪些原生方法?
- 数组和字符串的转换方法:toString()、toLocalString()、join() 其中 join() 方法可以指定转换为字符串时的分隔符。
- 数组尾部操作的方法 pop() 和 push(),push 方法可以传入多个参数。
- 数组首部操作的方法 shift() 和 unshift() 重排序的方法 reverse() 和 sort(),sort() 方法可以传入一个函数来进行比较,传入前后两个值,如果返回值为正数,则交换两个参数的位置。
- 数组连接的方法 concat() ,返回的是拼接好的数组,不影响原数组。
- 数组截取办法 slice(),用于截取数组中的一部分返回,不影响原数组。
- 数组插入方法 splice(),影响原数组查找特定项的索引的方法,indexOf() 和 lastIndexOf() 迭代方法 every()、some()、filter()、map() 和 forEach() 方法
- 数组归并方法 reduce() 和 reduceRight() 方法
12. 为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?
arguments是一个对象,它的属性是从 0 开始依次递增的数字,还有callee和length等属性,与数组相似;但是它却没有数组常见的方法属性,如forEach, reduce等,所以叫它们类数组。
使用Array.from方法将类数组转化成数组
13. 什么是 DOM 和 BOM?
- DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象主要定义了处理网页内容的方法和接口。
- BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的法和接口。BOM的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象。
17. JavaScript为什么要进行变量提升,它导致了什么问题?
- 解析和预编译过程中的声明提升可以提高性能,让函数可以在执行时预先为变量分配栈空间
- 声明提升还可以提高JS代码的容错性,使一些不规范的代码也可以正常执行
变量提升虽然有一些优点,但是他也会造成一定的问题,在ES6中提出了let、const来定义变量,它们就没有变量提升的机制。
var tmp = 'hello world';
for (var i = 0; i < tmp.length; i++) {
console.log(tmp[i]);
}
console.log(i); // 11
由于遍历时定义的i会变量提升成为一个全局变量,在函数结束之后不会被销毁,所以打印出来11。
19. ES6模块与CommonJS模块有什么异同?
ES6 Module和CommonJS模块的区别:
- CommonJS是对模块的浅拷⻉,ES6 Module是对模块的引⽤
20. 常见的DOM操作有哪些
1)DOM 节点的获取(document.querySelector)
2)DOM 节点的创建(createElement)
3)DOM 节点的添加(appendChild)
4)DOM 节点的删除(removeChild)
5)修改 DOM 元素(src,href,innerHtml)
use strict是什么意思 ? 使用它区别是什么?
-
我们的变量名必须先声明再使用
-
我们不能随意删除已经声明好的变量
-
严格模式下全局作用域中函数中的 this 是 undefined。
-
严格模式下函数里面的参数不允许有重名
-
严格模式下,如果 构造函数不加new调用, this 指向的是undefined 如果给他赋值则 会报错.
数组的遍历方法有哪些
| 方法 | 是否改变原数组 | 特点 |
|---|---|---|
| forEach() | 否 | 数组方法,不改变原数组,没有返回值 |
| map() | 否 | 数组方法,不改变原数组,有返回值,可链式调用 |
| filter() | 否 | 数组方法,过滤数组,返回包含符合条件的元素的数组,可链式调用 |
29. forEach和map方法有什么区别
这方法都是用来遍历数组的,两者区别如下:
- forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;
- map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;
forEach和some区别
var arr = ['red', 'green', 'blue', 'pink'];
// 1. forEach迭代 遍历
// arr.forEach(function(value) {
// if (value == 'green') {
// console.log('找到了该元素');
// return true; // 在forEach 里面 return 不会终止迭代
// }
// console.log(11);
// })
// 如果查询数组中唯一的元素, 用some方法更合适,
arr.some(function(value) {
if (value == 'green') {
console.log('找到了该元素');
return true; // 在some 里面 遇到 return true 就是终止遍历 迭代效率更高
}
console.log(11);
});
四、原型与原型链
1. 对原型、原型链的理解
在JavaScript中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性,它的属性值是一个对象,我们也称为原型对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。
对象都会有一个属性 _ _ proto _ _ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 _ _ proto _ _ 原型的存在。
对象原型( _ _ proto _ _ )和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
2. 原型修改、重写(手动的利用constructor指回原来的构造函数)
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
// Star.prototype.sing = function() {
// console.log('我会唱歌');
// };
// Star.prototype.movie = function() {
// console.log('我会演电影');
// }
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star,
sing: function () {
console.log('我会唱歌');
},
movie: function () {
console.log('我会演电影');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(Star.prototype);
console.log(ldh.__proto__);
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
4. 原型链的终点是什么
原型链的终点是null
五、闭包/递归/深浅拷贝/作用域链/执行上下文
1. 对闭包的理解
闭包是指有权访问另一个函数作用域中变量的函数
简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量
- 闭包的作用就是:延伸了变量的作用范围
2. 对递归的了解
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己, 这个函数就是递归函数 ,递归函数的作用和循环效果一样 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return。
3. 对浅拷贝与深拷贝的理解
浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用. 深拷贝拷贝多层, 每一级别的数据都会拷贝. Object.assign(target, ...sources) es6 新增方法可以浅拷贝
- 浅拷贝改变拷贝后对象的基本数据类型值,原拷贝对象不受影响,但是如果改变拷贝后对象的更深层次,引用类型,原拷贝会受到影响。
// 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
// for (var k in obj) {
// // k 是属性名 obj[k] 属性值
// o[k] = obj[k];
// }
// console.log(o);
// o.msg.age = 20;
// console.log(obj);
Object.assign(o, obj);
console.log(o);
o.msg.age = 20;
console.log(obj); // 改变了原拷贝的age属性值了,地址发生了改变
- 深拷贝
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);
// var arr = [];
// console.log(arr instanceof Object);
o.msg.age = 20;
console.log(obj);
2. 对作用域、作用域链的理解
1)全局作用域和函数作用域
(1)全局作用域
-
最外层函数和最外层函数外面定义的变量拥有全局作用域
-
所有未定义直接赋值的变量自动声明为全局作用域
-
所有window对象的属性拥有全局作用域 2)函数作用域
-
函数作用域声明在函数内部的变零,一般只有固定的代码片段可以访问到
-
作用域是分层的,内层作用域可以访问外层作用域,反之不行
2)块级作用域
- 使用ES6中新增的let和const指令可以声明块级作用域,块级作用域可以在函数中创建也可以在一个代码块中的创建(由
{ }包裹的代码片段) - let和const声明的变量不会有变量提升,也不可以重复声明
- 在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部。 作用域链: 在当前作用域中查找所需变量,但是该作用域没有这个变量,那这个变量就是自由变量。如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到window对象就被终止,这一层层的关系就是作用域链。
3. 对执行上下文的理解
(1)全局执行上下文
任何不在函数内部的都是全局执行上下文,它首先会创建一个全局的window对象,并且设置this的值等于这个全局对象,一个程序中只有一个全局执行上下文。
(2)函数执行上下文
当一个函数被调用时,就会为该函数创建一个新的执行上下文,函数的上下文可以有任意多个。
六、this/call/apply/bind
1. 对this对象的理解
- 普通函数 this 指向window
- 对象的方法 this指向的是对象 o
- 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
- 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
- 定时器函数 this 指向的也是window
2. 对call() 和 apply() 和bind()的理解
call()
- call 第一个可以调用函数 第二个可以改变函数内的this 指向
- call 的主要作用可以实现继承 apply()
- 也是调用函数 第二个可以改变函数内部的this指向
- 但是他的参数必须是数组(伪数组)
- apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求数组最大值
bind()
- 不会调用原来的函数 可以改变原来函数内部的this 指向
- 返回的是原函数改变this之后产生的新函数
- 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
七、异步编程
1. 异步编程的实现方式?
回调函数 的方式
Promise 的方式
async 函数
2. 对Promise的理解
简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
4. Promise的基本用法
(1)创建Promise对象
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
一般情况下都会使用new Promise()来创建promise对象,