函数 | new.target属性
new.target属性是ES6中新增的函数属性,new.target用于检测函数是否使用new关键字调用
如果函数是正常调用的,new.target的值为undefined;如果是使用new关键字调用的,则new.target将引用被调用的构造函数
1 | function King() { |
new.target属性是ES6中新增的函数属性,new.target用于检测函数是否使用new关键字调用
如果函数是正常调用的,new.target的值为undefined;如果是使用new关键字调用的,则new.target将引用被调用的构造函数
1 | function King() { |
三个方法都是用来从字符串中提取子字符串的,因为是提取,三个方法都不改变原字符串
语法
1 | str.slice(startIndex, [endIndex]) |
参数
startIndex
:从该索引开始endIndex
(可选):在该索引处结束提取字符串(不含),默认为字符串长度返回值
返回提取出来的子字符串
语法
1 | str.substring(startIndex, [endIndex]) |
参数
startIndex
:从该索引开始endIndex
(可选):在该索引处结束提取字符串(不含),默认为字符串长度返回值
返回提取出来的子字符串
语法
1 | str.substr(startIndex, [length]) |
参数
startIndex
:从该索引开始length
(可选):提取的字符数返回值
返回提取出来的子字符串
三者的主要区别在于面对0参数的处理上
slice
方法会将所有负值参数都使用负值+length
的方法进行处理substr
方法会将第一个负参数值使用负值+length
的方法进行处理,第二个负参数转为0substring
方法会将所有的负参数转为0prototype
属性(指向原型对象)constructor
的属性,指回与之关联的构造函数constructor
属性,其他的所有方法都继承自Object
[[prototype]]
指针就会被赋值为构造函数的原型对象,一般我们通过__proto__
进行访问对象的原型Function
类型的实例,所有的函数都继承或间接继承Function.prototype
Function
也有属性和方法,跟其他引用类型一样这部分是最容易理解的,不再赘述,不理解的看这篇原型和原型链 | 理解原型和原型层级
__proto__
指向Object.prototype因为Function.prototype
本身是一个function
类型(用typeof
检测一下),Function.prototype
本身是没有valueof
属性的,需要从Object.prototype
中继承
__proto__
指向 Function.prototypeObject
是构造函数,在回顾中说道:**每个函数都是Function
类型的实例,所有的函数都继承或间接继承Function.prototype
**,所以Object
作为构造函数的实例,Object
的__proto__
指向Function.prototype
就容易理解了
同理,Foo的
proto指向 Function.prototype
也就不奇怪了(Foo
是构造函数)
__proto__
指向Function.prototype这里可以这样理解Function的__proto__
指向Function.prototype是为了保证原型链的完整性,让Function
能够获得Object.prototype
上的方法
HTTP状态码是非常重要的一个知识点,尤其是对于前端工作者来说,我们在发送网络请求获取资源的时候,经常返回不同的状态码,那么各种状态码都代表什么含义呢~让我们一探究竟吧!
类别 | 含义 | 描述 |
---|---|---|
1xx | Informational (信息性状态码) | 接收的请求正在处理 |
2xx | Success(成功状态码) | 请求正常处理完毕 |
3xx | Redirection(重定向状态码) | 需要进行附加操作继而完成请求 |
4xx | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5xx | Server Error(服务器错误状态码) | 服务器请求错误 |
3xx响应结果表明浏览器需要执行某些特殊的处理以正确处理请求
301 Moved Permanently(永久重定向):请求的资源已经被分配到新的URL,以后应使用资源指定的URL
302 Found(临时重定向):请求的资源被分配到新的URL,希望用户(本次)能够使用新的URL访问资源
303 See Other:由于请求对应的资源存在着另一个URL,应使用GET方法重定向获取请求资源,和302类似,但是303状态码明确表示客户端应当采用GET获取资源(消息确认页面或者上传进度页面)
304 Not Modified(浏览器缓存相关):客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况,304状态码返回时,不包含任何响应的主体部分
307 Temporary Redirect(临时重定向):和302类似
4xx响应结果表示客户端是错误所在
Method | Mean |
---|---|
GET(获取资源) | 发送一个请求获取服务器上的某一资源,返回实体主体 |
POST(传输实体主体) | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件) 数据被包含在请求体中,POST 请求可能会导致新的资源的建立和/或已有资源的修改 |
PUT(传输文件) | 从客户端向服务器传送的数据取代指定文档的内容 |
DELETE (删除文件) | 请求服务器删除指定页面 |
OPTIONS (询问支持的方法) | 查询针对请求URI指定的资源支持的方法 |
CONNECT(连接方式) | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器 |
TRACE(测试诊断) | 回显服务器收到的请求,主要用于测试或诊断 |
PATCH(局部更新) | 对已知资源的局部更新 |
forEach
方法:针对每一个元素执行提供的函数,没有返回值,直接修改原数组
1 | let arr = [1,2,3]; |
map
方法:返回一个数组,其中数组的每一项都是对原始数组中同样位置的元素运行传入函数而返回的结果,并且仅对每一项已分配值得索引调用
1 | let arr = [1,2,3]; |
map
方法适用于创建一个与原数组元素一一对应的数组,map
方法还可以进一步结合filter
,reduce
等forEach
方法适用于并不打算改变数据,而是想用数组的元素做一下操作的时候,比如打印,存入其他数组等1 | arr.reduce(callbackFn, [initalValue]); |
callbackFn:reducer函数
包含四个参数:
initalValue(可选):
注意点
实现思路
代码实现
1 | Array.prototype.myReduce = function(callbackFn, initalValue) { |
说明
#1:Object(this)
Object构造函数作为一个工厂函数,能够根据传入的值的类型返回相应原始值包装类型的实例
null
或者undefined
:将会创建并返回一个空对象#2:len = lenValue >>> 0
>>>
表示无符号右移,为了保证结果为非负整数
#3: 获取数组第一个有效元素
我觉得这里主要为了检测空值,虽然之前说了若是没有initalValue,previousValue就为array[0],但是若出现数组前面有空值或者全部为空值的情况,previous的取值是需要慎重的,所以初始化previousValue准确地说应该是数组中合法的第一个元素
#4:跳过空值(补课:空值检测以及reduce对存在空值的数组处理)
1 | let arr = [1,2,3,4,5]; |
1 | let arr = [2,4,7,3,5,8,10,9]; |
1 | let arr = [3,7,4,2,5,3,2,8]; |
1 | // .map(callback) callback = function(item, index, arr) {...} |
1 | // .filter(callback) callback(item, index, arr) {...} |
compose函数是指将函数按顺序执行,将若干个函数组合成一个函数来执行,并且每个函数执行的结果都能作为下一个函数的参数
假设有这样两个函数,一个求和函数,一个累积函数
1 | function sum(value) { |
一般情况下,会这样使用:
1 | let value = 10; |
若是有compose函数,将可以实现以下效果:
1 | const fn = compose(sum, mul); |
1 | function runPromiseInSequence(arr, input) { |
1 | // flat(depth) |
1 | function count(arr) { |
1 | function increment(input) { return input + 1;} |
举例1
之前在做算法题的时候遇到这样一个问题:我想创建一个n*m 的数组,于是我采用这样的方式
1 | const n = 10, m = 10 |
结果,grid
打印的结果为[empty × 10]
,这说明map
根本没起作用,阅读红宝书的时候发现在第四版141页数组空位的地方有说明,原话是“map()
会跳过空位置”,用专业术语说,**map
仅对每一项已分配值的索引调用**,所以要是我想实现我想要的效果,我应该写如下代码:
1 | const n = 10, m = 10 |
举例2
我们已经直到,map
方法会跳过空位置,并且红宝书第四版P140页提到”ES6
中普遍将空位当作存在的元素,值为undefined
“,下面的例子证实了这个说法
1 | let arr = [1,2,,4]; |
再看下面的代码:
1 | let arr1 = [1,2,,4]; |
咦?undefined
的位置没有被跳过,而空值显然被跳过了
于是引发了两个问题:
undefined
,但是和undefined
还是有本质的区别,究竟是怎么样的区别呢?map
是怎么判断是空值还是undefined
的呢?通过arr[index] === undefined
显然是行不通的要解答这两个问题,就要回归到上面说的**map
仅对每一项已分配值的索引调用**,undefined
数据基本数据类型,当然属于值
以下操作均会产生空位
1 | // Array构造函数传一个数值表示数组长度 |
1 | 0 in [undefined, undefined, undefined]; // true |
说明[undefined, undefined, undefined]
在索引0处有值,[,,,]
在索引0处没有值
map()
:跳过空位,但会保留这个值
forEach()
,filter()
,every()
,some()
,reduce()
:跳过空位
join()
,toString()
,Array.from
,展开运算符
:会将空位视为空字符串
fill()
:将空位视为正常值
copyWithin()
:连着空位一起拷贝
举例
1 | // map() |
红宝书第四版P113:为了方便操作原始值,ECMAScript 提供了3 种特殊的引用类型:Boolean、Number 和String
new 包装类型
的方式进行转换看下面这个例子:
1 | var s1 = 'someText'; // 后台偷偷操作了,隐式! |
分析:
s1
是一个保存字符串的变量,是一个原始值,在第二行调用了调用了substring()
方法,并把结果保存在s2
中。原始值本身不是一个对象,照理说不应该有方法,但是事实确实调用方法成功了。实际上,当第二行访问s1
时,是以读模式访问的,也就是要从内存中读取变量保存的值。在以读模式访问字符串值的任何时候,后台都会执行以下3 步:
以上3步可抽象为下列代码:
1 | var s1 = new String('someText'); // new 了, 显式! |
从上面的例子我们不难看出:
引用类型与原始值包装类型的主要区别在于对象的生命周期
具体来说:在通过new 实例化引用类型后,得到的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间,这意味着不能在运行时给原始值添加属性和方法
1 | let s1 = "some text"; |
创建原始值包装类型【装箱】的方式有:
1 | let obj = new Object("some text"); |
需要注意的是:使用new 调用原始值包装类型的构造函数,与调用同名的转型函数并不一样(注意区分转型函数和构造函数)
1 | let value = "25"; |
Boolean 是对应布尔值的引用类型
1 | let booleanObject = new Boolean(true); |
Boolean实例重写
valueOf()
方法,返回一个原始值true
或者false
,toString()
方法被调用时也会被覆盖,返回字符串''true''
或者''false''
看下面这个例子:
1 | let falseObject = new Boolean(false); // 包装了一个值为false的Boolean对象 |
1 | let falseObject = new Boolean(false); |
1 | let falseObject = new Boolean(false); |
Number 是对应数值的引用类型
1 | let numberObject = new Number(10); |
Number实例重写
valueOf()
方法,toString()
方法和toLocaleString()
方法
valueOf()
方法返回Number
对象表示的原始数值,另外两个方法返回数值字符串
toString()
方法可选地接收一个表示基数的参数,并返回相应基数形式的数值字符串
1 | let num = 10; |
toFixed()
方法返回包含指定小数点位数的数值字符串,接受一个参数表示小数位数
1 | let num = 10; |
toExponential()
,返回以科学记数法(也称为指数记数法)表示的数值字符串,接受一个参数表示小数位数
toPrecision()
方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法形式这个方法接收一个参数,表示结果中数字的总位数(不包含指数)
ES6
新增了Number.isInteger()
方法,用于辨别一个数值是否保存为整数
IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。这个数值范围从Number.MIN_SAFE_INTEGER(-2^53 + 1)到Number.MAX_SAFE_INTEGER(2^53 - 1)。对超出这个范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的数值。为了鉴别整数是否在这个范围内,可以使用Number.isSafeInteger()方法
1 | let numberObject = new Number(10); |
1 | let numberObject = new Number(10); |
String 是对应字符串的引用类型
1 | let stringObject = new String('hello world'); |
String
对象的方法可以在所有字符串原始值上调用valueOf()
、toLocaleString()
和toString()
都返回对象的原始字符串值String
对象都有一个length
属性,表示字符串中字符的数1 | let message = "abcde"; |
1 | let message = "abcde"; |
1 | // Unicode "Latin small letter A"的编码是U+0061 |
1 | let message = "ab☺de"; |
1 | console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab☺de |
1 | let stringValue = "hello "; |
这两个方法从字符串中搜索传入的字符串,并返回位置,如果没找到,则返回-1
两者的区别在于,indexOf()方法从字符串开头开始查找子字符串,而lastIndexOf()方法从字符串末尾开始查找子字符串
1 | let stringValue = "hello world"; |
这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值
区别在于,startsWith()
检查开始于索引0 的匹配项,endsWith()
检查开始于索引(string.length - substring.length)
的匹配项,而includes()
检查整个字符串
startsWith()和includes()方法接收可选的第二个参数,表示开始搜索的位置,如果传入第二个参数,则意味着这两个方法会从指定位置向着字符串末尾搜索,忽略该位置之前的所有字符
1 | let message = "foobarbaz"; |
1 | let stringValue = " hello world "; |
trimLeft()和trimRight()方法分别用于从字符串开始和末尾清理空格符
1 | let stringValue = "na "; |
这两个方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格
1 | let stringValue = "foo"; |
可选的第二个参数并不限于一个字符,如果提供了多个字符的字符串,则会将其拼接并截断以匹配指定长度
此外,如果长度小于或等于字符串长度,则会返回原始字符串
1 | let stringValue = "foo"; |
1 | let text = "cat, bat, sat, fat"; |
1 | let text = "cat, bat, sat, fat"; |
1 | let text = "cat, bat, sat, fat"; |
1 | let colorText = "red,blue,green,yellow"; |
1 | let stringValue = "yellow"; |
创建数组可以通过Array
构造函数的方式构造数组 (new 操作符可以省略)
1 | let colors = new Array('red', 'green', 'yellow'); |
特殊:当传入一个数值的时候,会创建一个指定数组的数组,用逗号创建的数组空位,值为undefined
(关于数组空位,发现一些好玩的,请看这篇博文)
1 | let arr = Array(10); // 这里省略了new操作符 |
Array.of()
创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
Array.of()
代替了之前用Array.prototype.slice.call(arguments)
转数组的笨拙写法
Array.of()
和Array
构造函数的区别在于处理单个数组的情况
1 | Array(10); // [empty × 10] |
Array.from()
创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
语法(注意:容易被忽略)
1 | Array.from(arrayLike, mapFn, thisArg); |
参数
arrayLike
:类数组或者可迭代对象(如Map,Set等)或者有一个length
属性和可索引元素的结构mapFn
(可选):用于增强数组元素的回调函数thisArg
(可选):执行回调时的this
对象举例
1 | // 第二个参数的妙用 |
Array.from()
对现有数组是浅拷贝
1 | let arr1 = [5,6,7,8]; |
1 | let colors = ['red', 'green', 'yellow']; |
Array.length()
返回或设置一个数组中的元素个数
1 | let colors = ['red', 'green', 'yellow']; |
注意:数组的length
并不只是可读的,而是可以通过修改length
属性,从数组的末尾删除或者添加元素
1 | // 删除 |
1 | Array.isArray([1,2,3]); // true |
思考:检测一个对象是否是数组的方法有?
values()
方法返回一个新的Array Iterator
对象,该对象包含数组每个索引的值
keys()
方法返回一个包含数组中每个索引键的Array Iterator
对象
entries()
方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对
1 | const a = ['foo', 'bar', 'baz', 'qux']; |
手写实现
1 | // entries() |
copyWithin()
方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度
语法
1 | arr.copyWithin(target, start, end) |
参数
target
:从这个位置开始填充start
(可选):填充的内容从这个位置开始截取end
(可选):填充的内容到这个位置截取完毕(不包含end)注意
负索引会被计算成负索引+length
copyWithin()
静默忽略超出数组边界、零长度及方向相反的索引范围
举例
1 | let arr = [0,1,2,3,4,5]; |
1 | /* |
fill()
方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素,不包括终止索引,会改变原数组
语法
1 | arr.fill(value, start, end) |
参数
value
:用于填充数组的元素start
:起始索引,默认为0end
:终止索引,默认为this.length
注意
负索引会被计算成负索引+length
fill()
静默忽略超出数组边界、零长度及方向相反的索引范围
举例
1 | let arr = [1,2,3,4,5,6,7]; |
手写实现
1 | /* |
valueOf()
返回数组本身
toString()
返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串
toLocaleString()
返回一个字符串表示数组中的元素。数组中的元素将使用各自的toLocaleString
方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开
举例
1 | let colors = ['red', 'green', 'yellow']; |
join()
返回以指定分隔符分隔数组元素的字符串
1 | let colors = ['red', 'green', 'yellow']; |
注意:如果数组中某一项是null
或者undefined
,则返回值会以空字符串表示
手写实现
1 | /* |
向数组末尾添加元素,返回修改后数组的长度
手写实现
1 | /* |
删除数组的最后一项,同时减少数组的
length
值,返回被删除的元素
手写实现
1 | /* |
删除数组的第一项,同时减少数组的
length
值,返回被删除的元素
手写实现
1 | /* |
在数组开头添加元素,返回修改后数组的长度
手写实现
1 | /* |
补课啦:常见的排序算法及JS实现
sort()
方法用原地算法(即不创建额外的空间)对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16 代码单元值序列时构建的
语法
1 | arr.sort(compareFunction) |
参数
compareFunction
(可选):用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序1 | function compareFunction(value1, value2) { |
reverse()
方法将数组中元素的位置颠倒,并返回该数组,该方法会改变原数组
手写实现
1 | /* |
concat()
方法用于合并两个或多个数组,此方法会首先创建一个当前数组的副本,然后再把参数添加到副本末尾,所以不会更改现有数组,而是返回一个新数组
语法
1 | var new_array = old_array.concat(value1[, value2[, ...[, valueN]]]) |
参数
valueN
:可以是数组或者值注意
可以使用Symbol.isConcatSpreadable
来控制传入的类数组对象是否强制打平,true
为强制打平
举例
1 | let a1 = [1,2,3]; |
手写实现
1 | /* |
slice()
方法返回一个新的数组对象,这一对象是一个由begin
和end
决定的原数组的浅拷贝(包括begin
,不包括end
),原始数组不会被改变
语法
1 | arr.slice(start, end); |
参数
start
(可选):起始索引,默认为0end
(可选):终止索引(不含),默认为this.length
注意
start
超过原数组的索引范围返回空数组end
大于原数组的长度,则截取到原数组的末尾手写实现
1 | Array.prototype.mySlice = function(start, end) { |
splice()
方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容,此方法会改变原数组
语法
1 | arr.splice(start, deletcount, item1, item2,...) |
参数
start
:起始位置deletecount
(可选):要移除数组元素的个数,0或者负数表示不移除item1 item2
(可选):要添加的元素返回值
由被删除的元素组成的一个数组
如果只删除了一个元素,则返回只包含一个元素的数组
如果没有删除元素,则返回空数组
方法
手写实现
1 | /* |
indexOf()
方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1
lastIndexOf()
方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1,从数组的后面向前查找,从fromIndex
处开始
includes()
方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true
,否则返回false
注意
fromIndex
,即从哪一项开始寻找===
比较手写实现
1 | /* |
find()
方法返回数组中满足提供的测试函数的第一个元素的值,否则返回undefined
findIndex()
方法返回数组中满足提供的测试函数的第一个元素的索引,若没有找到对应元素则返回-1
注意
手写实现
1 | Array.prototype.myFind = function(callback) { |
every()
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值
举例
1 | let arr = [3,4,5,6,7]; |
手写实现
1 | Array.prototype.myEvery = function(callback) { |
some()
方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试,它返回一个布尔值
举例
1 | let arr = [3,4,5,6,7]; |
手写实现
1 | Array.prototype.mySome = function(callback) { |
filter()
方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素
举例
1 | let arr = [3,4,5,6,7]; |
手写实现
1 | // 迭代法 |
forEach()
方法对数组的每个元素执行一次给定的函数,没有返回值,改变原数组
举例
1 | let arr = [3,4,5,6,7]; |
手写实现
1 | /* |
map()
方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
举例
1 | let arr = [3,4,5,6,7]; |
注意
map
仅对每一项已分配值得索引调用1 | let a = [1,2,,4]; |
手写实现
1 | // 迭代法 |
reduce()
接收两个参数:归并函数和归并起点的初始值其中归并函数接收四个参数:上一个归并值、当前项、当前项的索引、数组本身。归并函数返回的任何值都会成为下一次调用同一个函数的第一个参数,即归并值,如果没有归并起点的初始值,则把第一个元素作为初始值,迭代从第二个元素开始
reduce的应用详见:强大的reduce
手写实现
1 | Array.prototype.myReduce = function(callbackFn, initalValue) { |
reduceRight()
与reduce()
唯一不同的就是遍历方向是从最后一项到第一项,其余全部相同
flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
语法
1 | arr.flat([depth]) |
参数
depth
(可选):指定要提取嵌套数组的深度,默认为11 | function myFlat(arr, depth = 1) { |