JavaScript基础
用看得懂的话写de教程。
数据类型
JavaScript的原始数据类型包括Number、String、Boolean、Null、Undefined、Symbol(ES6新增)、BigInt(最近新增),此外有Object类型。
Number
不区分整数和浮点,注意浮点计算结果是不精确的(由于浮点数的计算方式),对浮点数不建议直接用等号判断两值相等,应当看他们的差是否小于某个值(如0.001)。Infinity(超过Number最大值)、NaN(Not a Number)也是合法的Number。
关于NaN
NaN是特殊的Number,它也不等于自己,只能通过isNaN()判断。
String
单引号‘’或双引号""包裹的字符串。
Boolean
Boolean包括'true'、'false'两种取值。比较运算符、&&、||与!都会产生布尔值。
转换结果为false的取值
NaN、null、undefined、0与空字符串转Boolean的结果都为false。
null&undefined
null表示空值,undefined表示未赋值,undefined可以用于判断函数参数是否传递。他们是两种数据类型。
null和undefined的注意事项
null是保留字,而undefined不是。
如果访问不存在的变量,会报错"var is not defined";访问已声明但未赋值的变量才会得到undefined。
typeof null的结果是object,但null也是一种基本类型而非object,这个混淆是由于typeof以内存低位判断数据类型,object和null的低3位都是0。
Object
键-值对的无序集合。键(key)只能是字符串类型,值(value)可以是任意类型。'.'可以用于表示键路径,比如obj.key或obj.obj.a。
Object是引用类型,存储的是指针,而其他基本类型存储值。
let obj = {key:'value',
obj:{
a:'a'
}}
Array
用[]或new Array()创建,数组可以包含任意类型元素并且提供了相当多的方法。Array属于Object类型。
Date
Date类型提供了丰富的与时间、日期相关的方法,Date()返回当前日期的字符串。Date也属于Object类型。
ES6
Map&SetES6新增的数据结构。
Map是一组key-value对结构,key不能重复,否则只保留最新的值。与对象只支持string与symbol相比,Map 的key支持任意类型。
let students = new Map([['Lucy',90],['Peter',80],['Bill',85]])
students.get('Lucy')//90
students.has('Peter')//true
students.delete('Peter')//true
students.get('Peter')//undefined
students.set('Bill',90)//Map { 'Lucy' => 90, 'Bill' => 90 }
students.get('Bill')//90
Set类似集合,由一组不重复的key组成,否则只保留一个。
let foods = new Set(['Chicken','Noodles','Rice'])
foods.add('fish')//Set { 'Chicken', 'Noodles', 'Rice', 'fish' }
foods.delete('Noodles')//true
foods.has('Rice')//true
Function
有趣的是,函数是Object的实例,而Object也是函数的实例。
ES6
Symbol用于产生唯一标识,除了自己等于自己,两个完全相同的symbol不相等,常用于对象属性、声明唯一常量、定义私有属性。也可以用Symbol.for()创建symbol,如果参数一致,创建的symbol相等。
let s = Symbol("")
let s1 = Symbol("")
s == s1//false
s === s//true
let s2 = Symbol.for("")
let s3 = Symbol.for("")
s2 == s3//true
你可以通过以下方式获取Symbol的description(无需记忆)。
let s2 = Symbol("love")
let obj = {[s2]:"and peace"}
obj//{ [Symbol(love)]: 'and peace' }
Object.getOwnPropertySymbols(obj)//[ Symbol(love) ]
Reflect.ownKeys(obj)//[ Symbol(love) ]
Symbol定义了对象的许多实用方法,包括[Symbol.Iterator]、[Symbol.match]、[Symbol.replace]、[Symbol.split]、[Symbol.toPrimitive]、[Symbol.toStringTag]等。toStringTag方法甚至能改变对象的toString方法。
ES6
BigInt在数字末尾加n可声明BigInt,其可操作大于Number所能表示最大数的数(2^53)。该类型尚在提案过程中,在新版Chrome与Node中得到实现。
带小数的运算会被取整。
let Num = BigInt(Math.pow(2,63))
let Num2 = 100n
typeof&instanceof
typeof返回字符串有以下结果“number”、“string”、“boolean”、“object”、“function”、“undefined”、“symbol”,null打印为“object”。而instanceof用于判断检测对象的类型,包括"Array"、"Function"、"Object"及自定义类/构造函数等。
此外Object.prototype.toString.call()可以准确打印出Null的类型。也可以通过访问".constructor"获取构造函数判断类型。
let a = []
typeof a//'object'
a instanceof Array//true
class y{}
let t = new y()
t instanceof y//true
动态类型&类型转换
作为动态语言,JS允许同一个变量在不同时间用作不同类型。
使用JavaScript函数转换
例如全局方法(构造函数)String()、Number()、Date()以及变量的toString()方法等。不同类型还会有独有的方法比如Date变量的getDate()、getDay(),Number变量的toPrecision()等。
使用JavaScript自动转换
变量类型会根据需要发生类型转换,例如:
5 + null //5 因为null=0
5 + undefined //NaN 因为undefined转为数字是NaN
"0"+ null //"0null" 因为null="null"
"5" + 1 //"51" 因为1="1"
1 + "5" //"51" 因为1="1"
"5" - 1 //4 因为"5"=5
[1,2] + 1//"1,21" 数组先转字符串,再加"1"
if("str"){
//这里的代码将会执行,因为“str”可以转为true
}
可以观察到含字符串类型会转为字符串,没有或不能转字符串的话转数字(除加号以外,结果转数字)。
自动转换有一些基础规则,比如Boolean值的转换:true等于1,false等于0,空字符串、空数组和null等于0,非纯数字字符串转为NaN等。
有趣的是,"0"可以转为Boolean的“true”,但“0”转为数字0之后再转Boolean就会变成“false”。空数组也可以转“true”,转数字之后也为0。
基本类型&基本类型包装
除了Object类型存储的是引用,所有类型都是基本类型(存储值),但除了null和undefined,他们都像对象一样拥有自己的方法。这不是因为基本类型具有方法,而是在调用基本类型的方法时,JS引擎自动包装了基本类型,调用结束后销毁对象。
因此,向基本类型添加属性是无效的,因为添加完成后临时对象即被销毁,但可以向其原型添加属性和方法。
var str = 'str'
str.toUpperCase()
/*
相当于做了这些事
var _str = new String(str)
str = _str.toUpperCase()
*/
变量声明 Declaration
var
变量用var声明,不用var则作为全局变量。var声明的变量处于全局作用域或函数作用域。
变量提升 Hoisting
用var声明的变量,可以在声明语句之前使用,但不会初始化(赋值)。因此访问他们虽然不会报错,但会得到undefined。
ES6
let&constES6中新增了let与const关键字,分别代表块级作用域中的变量与常量,同时不允许重复声明,没有变量提升。
块级作用域
由{}包裹的代码块。在for循环中,()与{}是父子块级作用域,也就是说{}用let或const声明的变量不会影响for循环计数。
块级作用域没有变量提升,可以防止在函数内使用上级变量时,后面声明的变量意外覆盖上级变量。
使用var声明变量:
var h=10;
function print(){
console.log(h)
var h;//覆盖了上级变量
}
print()//undefined
使用let声明变量:
var h=10;
function print(){
console.log(h)//暂时性死区
let h;//与当前作用域绑定,声明之前不可读取
}
print()//ReferenceError: Cannot access 'h' before initialization
同时块间的隔离有助于减少冲突和出错。此前,JS只能用函数作用域来隔离变量,常用的方式就是匿名立即执行函数(匿名IIFE)。
(function(){var hours=12}())
//等同于
{let hours=12}
暂时性死区 temporal dead zone
let和const声明的变量会与代码块绑定,在声明前不能使用同名的上级环境变量,否则会引发报错。
命名规范
变量名由26字母的大小写、数字、“$“和”_“组成,不能用数字开头。甚至支持中文,但不建议使用,避免引发麻烦。
函数声明
推荐使用函数表达式let func=()=>{}
或let func=function(){}
为变量赋值,因此函数声明也遵循以上规则。如果用function func(){}
直接声明函数,ES5中函数声明能完整地提升,ES6虽然规定了行为类似let,但实际可能会先赋值为undefined,不同环境可能有不同的处理。
运算符
比较运算符 ==与===
==表示在类型转换后相等,===表示类型和值都一样。除非需要用到==的特性,否则建议用===比较。
比较对象
对象的比较与原始值不同,比较的是引用,因此两个完全相同的数组不相等,除非他们是对同一处的引用。
'与'运算符 &&
‘与’运算符,如果左边表达式的值是false或可以转为false则返回左边表达式的值,否则返回右边表达式的值。
Boolean角度:&&只有当两边都为true,结果才为true,如果左边结果为false,右边不会判断。
'或'运算符 ||
‘或’运算符,如果左边表达式的值是true或可以转为true则返回左边表达式的值,否则返回右边表达式的值。
Boolean角度:||只有当两边都为false,结果才为false,如果左边结果为true,右边不会判断。
ES6
扩展运算符 ...ES6中的扩展运算符,用在数组或对象前表示取出所有项或属性。
用于对象
let obj={a:1,b:2}
let newObj={...obj,c:3}//{ a: 1, b: 2, c: 3 }
用于数组
赋值
生成数组的拷贝。
let arr=[0,1,2]
let newArr=[...arr,3,4]//[ 0, 1, 2, 3, 4 ]
let arr_copy=[...arr]
解构赋值
结合解构赋值,它还提供了生成数组的方法。
let [...arr_copy]=arr
let [ar1,...ar2]=[0,1,2,3]
ar1//0
ar2//[ 1, 2, 3 ]
let [...ar3,ar4]=[0,1,2,3]
//SyntaxError: Rest element must be last element
WARNING
扩展运算符只能用在最后一项。
一个分号引发的血案
let val = func()//;
[a,b]=[b,a] 或 [a[c],b[c]]=[b[c],a[c]]
如果缺少分号,JS解析会出现错误,原因是两行连在一起也符合语法规则。这种情况下
用于函数参数
除了为数组赋值,还支持作为函数参数。
let arr=[0,1,2]
function add(a,b){
return a+b
}
add(...arr)//1
TIP
任何含Iterator接口的对象都可以通过扩展运算符转为真正的数组。详情见iterable接口。
基本运算 + - * /
可以用于各种类型间的运算。
方括号 []
属性访问器。最常用的是表示数组[1,2,3]
与数组下标arr[1]
,也可以作为对象的属性名obj['key']
,支持使用变量作为属性名obj[key]
(key不仅可以是符合规则的字符串,也可以是Symbol)。
点运算符 .
属性访问器。点运算符的功能是[]的子集,当属性名为常量时可以用于设置、获取对象属性obj.key
。
关键字
new
从构造函数派生出对象,构造函数的this指向创建的对象。
delete
用于删除对象属性,不可用于删除对象。
throw
抛出异常。通常结合try...catch使用。
循环体
forEach
Array.prototype.forEach(function(currentValue, index, arr), thisValue)
由于是以传入函数的形式遍历,forEach无法使用return从外部函数体返回,由于是数组的一种方法,也不支持break跳出循环。
for…in
for(let item in obj)
for…in支持遍历各种对象,它的item是对象的key,总是string类型。这种方法不稳定,不同时候结果的顺序可能不一致。如果用于数组,还有一个问题是所有属性也包括数组元素以外的自定义属性。
ES6
for…offor(let item of obj)
首先,它没有for…in的缺点,其次,也没有forEach的缺点。for…of支持数组、字符串、Set、Map和其他有iterable接口的对象,但不支持普通对象(会提示is not iterable
)。
ES6
iterable接口对象的[Symbol.iterator]
属性指向其默认的遍历器,其不仅提供了统一的接口,还能按规定的顺序排列。在ES6中,Array、String、Set和Map、arguments等类数组对象都具有iterable接口。而解构赋值、扩展运算符、yield和任何与接受数组的场合都调用了Iterator接口。
let myIterable = {}
myIterable[Symbol.iterator] = function* (){
yield 1;
yield 2;
yield 3;
}
[...myIterable]//[ 1, 2, 3 ]
借用数组的iterator:
let fakeArray={0:'apple',1:'peach',2:'pancake',length:3,
[Symbol.iterator]:Array.prototype[Symbol.iterator]}
for(let it of fakeArray){console.log(it)}//apple peach pancake
待填坑 async写法、next()写法
内置对象
Math
Math.pow()
JSON
JSON不是JS,也用在很多其他语言中,作为一种简单的传递对象数据的格式。
JSON.parse()
将标准JSON格式的字符串转为JS对象,不符合格式会提示‘unexpected token',最常见的是'unexpected token u',也就是undefined,因此写接口一定要注意确定请求成功再转换对象。
JSON.stringify()
将JS对象转为JSON格式,结合parse可以用于对象深拷贝。
Date
RegExp
Array
String
函数简介
普通函数都是Function对象的实例,而构造函数生成的函数是Object的实例。相比普通对象,函数多了可被调用的特征。
'Function'与‘function’的不同
‘Function’是JS的内置对象,而'function'是一个声明函数的关键字。
和其他语言函数的区别
由于JS是弱类型语言,函数无法指定形参类型与返回类型,同时也无法限制传入参数的个数,因此没有重载的特性。函数内部可以通过arguments对象获取实参。
this
this指向调用当前函数的对象,如果没有对象调用,那么this==window。在箭头函数中,this指向与环境中相同。bind、call、reply方法都可以修改this。
绑定this
绑定this的4种方法,按优先级从低到高排序分别是默认绑定、隐式绑定、显式绑定、new绑定。其中apply()与call()属于显式绑定。
默认绑定
全局环境中、函数独立调用时(即使被嵌套、包括立即执行函数),this指向window。有时候被嵌套的函数想获得上层函数的this,可以使用var that = this
语句传递this值。
隐式绑定/方法调用
this的值是调用该函数的对象。如a.b()中b内部的this指向a。只有直接调用obj.func()
时才会传递this,否则this仍指向window。函数虽然可以属于一个对象,但函数不会与对象绑定this。
这些不能传递this的场景包括赋值、传参、内置函数(如setTimeout)、间接引用(对象的属性赋值时的立即执行函数,如(p.foo = o.foo)()
,this为window)等。
var val='window'
var func = function(){
console.log(this.val)
}
var obj={val:'obj',func:func};
func()//window
obj.func()//obj
//赋值会丢失this
var func1 = obj.func
func1()//window
//作为参数传递也会丢失this
var func2 = function(func){
func()
}
func2(obj.func)//window
显示绑定
即使用call、apply、bind方法绑定this到对象上。JS还新增了许多内置函数提供thisValue选项,如数组的迭代方法map、forEach、filter、some、every。
new绑定
new的作用是从构造函数返回新对象。
function constructorA(){
this.a=0
}
let obj = new constructorA()
obj.a//0
需要注意如果constructor没有返回值,那么构造的对象就是返回值。而其中的this永远指向obj,即新生成的对象,即使let newObj = new obj.constructorA()
,this也会指向newObj,而不是obj。
this与函数
this的四种绑定方法其实也对应函数的四种调用方式,包括函数调用(func)、方法调用(obj.func)、间接调用(call、apply)、构造函数调用(new)。
实现bind
Function.prototype.bind(thisArg[,arg1[,arg2[,...]]])
bind提供了两个功能,一个是传递this,另一个是传递参数(之后传参数会位于这些参数后面),它返回绑定后的函数。
首先,我们要传递this,需要通过方法调用来完成,bind的this是原函数,我们要怎么返回绑定好的函数呢?🤔
可以想到,我们先把函数绑定到那个环境上去,但这就是bind的功能啊。实际上,我们应该返回一个全新函数,而这个新函数的执行结果与原函数+thisArg一致。
那么先不考虑传递参数,只考虑this的情况。
Function.prototype.myBind = function(thisValue){
thisValue._func = this
return function(){
return thisValue._func()
}
}
这样我们就已经实现了bind最基本的功能——绑定this,但我们向thisValue添加了属性。其实我们只用保证结果正确,因此可以删除添加的属性,用临时变量替代。
Function.prototype.myBind = function(thisValue){
let func = this
let getResult = (func,thisValue)=>{
thisValue._func = func
let result = thisValue._func()
delete thisValue._func
return result
}
return function(){
return getResult(func,thisValue)
}
}
细心的朋友不难看出,getResult和call、apply有着相似的功能,即返回绑定某个this值后的执行结果。也就是说,bind其实是基于call和apply实现的。但为了方便理解整个概念,我先介绍了bind。
call和apply
明白了基本原理之后,我们来研究如何传入参数。首先,我们应该知道所有参数都可以在aruguments对象中找到,我们先看一下它的结构:
function printArguments(){return arguments}
printArguments(1,2,3)//[Arguments] { '0': 1, '1': 2, '2': 3 }
Arguments是一个特殊的对象,它不是数组,但具有数组的许多特征,这里把它当作数组。
先看function.call(thisArg,arg1,arg2,...)
,我们需要把后面的参数传入函数。
Function.prototype.myCall = function(){
let [thisValue,...parameters] = arguments
thisValue._func = this
let result = thisValue._func(...parameters)
delete thisValue._func
return result
}
再看看function.apply(thisArg,[argsArray])
,我们转换一下参数形式就行。需要注意我们的argsArray不能为空,如果为空,parameters为undefined,再使用扩展运算符就会报错is not iterable
。
Function.prototype.myApply = function(){
let [thisValue,parameters] = arguments
thisValue._func = this
let result = thisValue._func(...parameters)
delete thisValue._func
return result
}
可以完善的一些地方
如果没有传this值,我们可以让默认值为window,如果没有传argsArray,让默认值为[],这里拿apply作为例子。
Function.prototype.myApply = function(){
let [thisValue,parameters] = arguments
if(!thisValue)thisValue = window
if(!parameters)parameters = []
thisValue._func = this
let result = thisValue._func(...parameters)
delete thisValue._func
return result
}
我们的bind也可以改造成使用apply的模式。
Function.prototype.myBind = function(){
let func = this
let [thisValue,...parameters] = arguments
return function(){
return func.myApply(thisValue,parameters)
}
}
现在还可以继续考虑两个问题:如果不能使用…运算符怎么办?如果绑定的对象已经有了_func属性或者不能设置属性怎么办?
先看如何替代…运算符。如果不能使用…运算符,我们就不能方便地向函数传递任意多个参数,可以使用eval()解析生成的字符串,也可以用new Function([arg1[,arg2[,...argN]],]functionBody)
结合读取arguments数组读取任意多个参数,也是通过解析生成的字符串。
使用不重复的属性。ES6提供了symbol()用于标志唯一的事物,它可以以作为对象的属性,我们仍以apply作为例子。
Function.prototype.myApply = function(){
let [thisValue,parameters] = arguments
if(!thisValue)thisValue = window
if(!parameters)parameters = []
let _func = Symbol()
thisValue[_func] = this
let result = thisValue[_func](...parameters)
delete thisValue[_func]
return result
}
此外还可以用Math.random()生成一个不太可能重复的属性名。
作用域 Scope
作用域即变量和函数的可访问范围和生命周期。
变量作用域
可以分为全局作用域、函数内作用域(包括嵌套函数)、块级作用域。局部变量可以在局部覆盖同名全局变量。
作用域链 Scope Chain
作用域链决定了函数能访问变量的范围,组织了访问变量的顺序,在解析标识符时一级一级地按顺序查找函数和变量。需要注意的是,JS根据函数定义的位置查找,而非执行的位置。
执行环境/执行上下文 Execution Context
执行环境定义了变量与函数能访问的数据,包括全局、函数内、eval、块级作用域等。
执行环境包括至少3个重要的属性:作用域链、变量对象和this(按创建顺序排序)。这里关注前两个。
变量对象 Variable Object
每个执行环境都有与之关联的变量对象,它包括了环境中所有的变量和函数。全剧环境下的变量对象称为VO。
所有的变量和函数即函数声明、变量声明、函数形参。不包括匿名函数。
活动对象 Activation Object
当环境是函数时,活动对象就是变量对象。活动对象至少包含arguments对象(即函数参数)。有很多资料提到函数中不能直接访问VO,而以AO替代,不过反正这两个都是不能用JS代码打印出来的。
Arguments对象至少包括callee(对当前函数的引用)、length(真正传递参数的个数)、properties-indexs(函数的参数值),注意Arguments并不包含this。
作用域链
从外层到函数乃至嵌套函数内,多个执行环境形成了一个程序执行栈,同时也形成了一个指向多个环境的链表,即作用域链。
作用域链包括VO与所有上级的作用域。
数组 Array
属性
length
数组长度/元素个数。
constructor
构造函数。
prototype
通过在原型上定义方法,让所有数组都可以使用自定义的方法。
变异方法与非变异方法 mutation method and non-mutation method
有些方法改变原数组,称为变异方法;也有些方法返回一个新数组,称为非变异方法;剩下的那些方法不改变数组也不返回数组。下面用M和N标记变异与非变异方法。
N
mapArray.prototype.map(function(currentValue,index,arr),thisValue)
map的作用是按回调函数的规则从原数组映射出一个新数组(作为返回值)。
从函数原型可以看出,回调函数可以得到当前元素的值、索引、原数组,处理后的值应作为返回值,还能传入this对象。
currentValue和index以及arr是只读的,但arr是对象,currentValue也可能是对象,此时可以修改属性或执行方法。
forEach
Array.prototype.forEach(function(currentValue, index, arr), thisValue)
参数 | 描述 |
---|---|
function(currentValue, index, arr) | 必需。currentValue即当前元素(必需),index即索引值,arr即数组对象。 |
thisValue | 传入的this值,默认undefined |
无返回值,不能改变数组。如果数组成员是对象,当然可以更改其属性,因为数组只存了对象的指针。
reduce
Array.prototype.reduce(function(total, currentValue, index, arr), initialValue)
迭代器,reduce从左到右遍历数组并接受一个函数作为累积器。这个函数接受上次迭代的返回值(total,而初始值可以用initialValue指定),并最终得到一个返回值作为reduce的返回值。
使用reduce可以组织多个函数作为函数链,称为compose。
reduceRight
与reduce相似,但从右向左迭代。
N
filterArray.prototype.filter(function(currentValue, index, arr), thisValue)
过滤器,返回所有符合条件的项(回调函数中返回true)。不能改变数组。
M
push、popArray.prototype.push(arg1, arg2, ...)
Array.prototype.pop()
栈方法。进栈和出栈。进栈返回新数组长度,出栈返回出栈元素的值。
M
shift、unshiftArray.prototype.shift()
Array.prototype.unshift(arg1, arg2 , ...)
shift即出队列,删除数组第一项并将其作为返回值,unshift则是将item塞回队列(成为新数组的第0项、第1项等等)。push和shift方法结合使用则数组可以作为队列使用。
N
sliceArray.prototype.slice(start, end)
切片的意思,即返回数组的一部分。start和end指定了开始和结束的数组下标,他们都接受负数值,-n代表从末尾向前数的第n个元素。
ES6
findArray.prototype.find(function(currentValue, index, arr), thisValue)
接受函数作为条件,返回第一个函数返回true的数组项。
ES6
findIndex和find用法一致,返回第一个函数返回true的数组项的索引。如果找不到返回-1。
indexOf
Array.prototype.indexOf(item, start)
indexOf接受一个值直接与数组项进行比较,返回第一次匹配的项的索引,如果找不到返回-1。start可以指定从哪一项开始搜索。
lastIndexOf
Array.prototype.lastIndexOf(item,start)
与indexOf相似,但返回最后一个匹配项。
M
sortArray.prototype.sort([compareFunction(firstEl,secondEl)])
排序。修改原数组,返回对原数组的引用(即修改后的数组)。
比较函数是可选的,接受比较的第一个元素和第二个元素,如果返回结果小于0,a将被排在b前面,如果大于0,b将被排在a前面,如果等于0,顺序不变(遗憾的是浏览器不一定遵守)。
默认的sort将元素转为字符串并比较编码值大小。
M
reverseArray.prototype.reverse()
翻转数组。改变原数组,返回其引用。
M
spliceArray.prototype.slice(index[, howmany, item1, item2, ...])
Splice的中文意为铰接、粘接,该方法可以自由地从数组添加、删除元素。
第一个参数index用于确定位置,从哪里开始操作;第二个参数决定从下标为index的元素起,删除几个元素;后面的参数将会添加到数组中从index开始的位置上。
N
concatArray.prototype.concat([arr1, arr2, ...])
concat意为串联,即将两个或多个数组连接在一起并返回。参数为空时返回原数组拷贝,常用于复制数组。
join
Array.prototype.join([separator=","])
join返回所有数组元素转换成的一个字符串,默认用半角逗号分隔,和toString表现一致,也可以自己指定分隔符。
M ES6
fillArray.prototype.fill(value[, start=0[, end=array.length]])
以固定值填充数组。start和end指定填充区间,array[end]不会被填充。
M
copyWithinArray.prototype.copyWithin(targetIndex[, start[, end=array.length]])
targetIndex确定了要复制到的位置,而start与end决定了被复制元素的范围。这种复制不是插入,而是覆盖原有元素,并且不改变数组长度。
ES6
includesArray.prototype.includes(searchElement[, fromIndex])
第一个参数传入值,第二个参数确定从哪开始搜索,-n代表倒数第n项。如果数组包括该值则返回true,否则返回false。
ES6
fromArray.prototype.from(object[, mapFunction[, thisValue]])
object如果是拥有length属性或可迭代的对象,通过此方法能够返回一个数组。不符合要求的对象会导致from方法返回空数组。
every
Array.prototype.every(function(currentValue,index,arr),thisValue)
返回Boolean值,当且仅当所有元素传入回调函数的返回结果为true时every的结果为true。
some
和every用法一致,有一个元素传入回调的结果为true即返回true并不再检验之后的元素。
ES6
entriesArray.prototype.entries()
从数组返回一个可迭代对象(Array Iterator)。如果不明白可以先了解function generator。
ES6
keysArray.prototype.keys()
创建key的可迭代对象,而数组的key是0、1、2、3...
isArray
Array.prototype.isArray(obj)
顾名思义,判断是否数组,返回Boolean值。
toString
其实和join类似,返回字符串,不过不带参数,只能以逗号分隔。
valueOf
数组对象的默认方法,返回数组原始值。不必手动调用。
对象
可枚举属性 Enumerable Properties
Object.keys()、for...in、JSON.stringily()都只处理可枚举属性,可以用Object.propertyIsEnumerable()方法判断属性是否可枚举。
定义一个不可枚举属性:
let obj = {}
obj.defineProperty(obj,"attr",{
value:"bread",
enumerable:false
})
待填坑
如果属性存在于原型
对象拷贝
除了接下来介绍的Object.assign(),还可以用JSON.parse(JSON.stringify())深拷贝对象,对于数组可以用concat()。
Object.assign()
Object.assign(target, ...source)
(浅)拷贝数组,将所有可枚举属性从一个或多个源对象复制到目标对象,并将其作为返回值。需要注意它调用源对象的Setter和目标对象的Getter,如果合并源包括Getter或目标包括Setter,那么应该使用Object.getOwnPropertyDescriptor()与Object.defineProperty()准确复制属性定义。
原型 Prototype
JavaScript中的继承。
String方法
字符串方法均返回新值,不改变原字符串。
substring
String.prototype.substring(from[, to=array.length])
给定两个下标,截取部分字符串作为返回值,arr[to]不会被截取。
substr
String.prototype.substr(start[, length=array.length-start])
截取从arr[start]开始的length个字符作为返回值,不指定length则截取到结尾。
trim
去除字符串两边的空格作为返回值。
split
String.prototype.split([separator[, limit]])
将字符串按分隔符拆成数组,separator可以是字符串或RegExp,默认不会拆分,传入""空字符串可拆分每一个字符,limit限制返回子字符串的最大数量(达到limit个子字符串后split即返回)。
slice
String.prototype.slice(start[, end=array.length])
截取字符串片段,不包括arr[end],end可以为负(-n代表倒数第n个)。
replace
String.prototype.replace(searchValue, newValue)
接受字符串或RegExp进行匹配和替换。如果是字符串只能替换第一次匹配的子字符串,正则表达式可以替换所有的项(/str/g
)。
match
String.prototype.match(RegExp)
接受一个正则表达式,返回结果数组或null。
search
String.prototype.search(searchValue)
接受字符串或正则表达式,返回第一次匹配的子字符串起始位置的下标,找不到返回-1。
indexOf
String.prototype.indexOf(searchValue[, start])
与search相似,但只接受字符串,可以给一个开始搜索的位置。注意它不会来回找,如果在start到end区间都没有匹配项就返回-1。
lastIndexOf
String.prototype.lastIndexOf(searchValue[, start])
与indexOf的区别在于,该方法从后往前找,能找到最后一次出现的位置。
ES6
includesString.prototype.includes(searchValue[, start])
与indexOf类似,但不返回子字符串位置,只返回Boolean值。
concat
String.prototype.concat([str1[, str2[, ...]]])
连接多个字符串并作为结果返回。
toLowerCase
将大写转换成小写字母并返回。
toUpperCase
将小写转换成大写字母并返回。
ES6
repeatString.prototype.repeat(count=0)
将字符串复制指定次数合并成一个字符串返回,默认count=0即返回空字符串。
ES6
startsWithString.prototype.startsWith(value[, start=0])
用于判断字符串是否以value开头。不过start可以自定义,也就是判断字符串start处是否有字符串value。返回结果为Boolean值。
charAt
String.prototype.charAt(index=0)
接受index并返回str[index]。
charCodeAt
String.prototype.charCodeAt(index=0)
接受index并返回str[index]的Unicode编码。
fromCharCode
String.fromCharCode([code1[, code2[, ...]]])
接受一个或多个字符编码,返回创建的字符串。
HTML包装方法
包括anchor、big、blink、bold、fixed、fontcolor、fontsize、italics、link、small、strike、sub、sup。这些方法从字符串返回一个HTML标签用于网页中展示。
错误处理
try...catch
try {
//insert code here
a.b=c
}
catch(err) {
console.error("Error catched: "+err)
}
throw
抛出自定义错误。
try {
throw 'Number is too big'
}
catch(err) {
console.error(err)
}
finally
无论是否发生错误都会执行的语句。
try {
}
catch(err) {
}
finally {
}
Error对象
如果是内置错误(非throw抛出),抛出的是一个Error对象。包括name和message属性。
错误名name通常包括ReferenceError(引用尚未声明的变量)、SyntaxError(语法错误)、TypeError(类型错误,如xxx is not a function)、URIError(由URI函数抛出)、rangeError(由Number的方法抛出)。
参考
模板字符串
`我买了${a}箱苹果``
变量作用域
JS中变量的作用域可以是全局,也可以是局部(函数参数和局部变量),同名局部变量会
函数作用域
JS的函数作用域是指在函数内声明的变量始终可见(变量提升)。
作用域链
JS查找上级作用域时,根据定义的位置查找,与执行环境无关。
参考目录
this
https://www.cnblogs.com/xiaohuochai/p/5735901.html
JavaScript
https://www.liaoxuefeng.com/wiki/1022910821149312
ECMA Script 6
http://es6.ruanyifeng.com/
Execution Context
https://juejin.im/entry/58edde2761ff4b00581b93ff
Symbol
https://www.cnblogs.com/diligenceday/p/5462733.html
MDN
runoob