注意点:
对象的键名为字符串,若命名为数值,则会自动转为字符串;如果键名不符合标识名的条件,则必须加上引号。
数值键名在用于对象的属性获取时,只能使用 [ ] 方式获取,不能使用 . 运算符获取
//基本数据类型
typeof(Number) ======> 'number'
typeof(String) ======> 'string'
typeof(Boolean) ======> 'boolean'
//特殊数据类型
typeof(null) ======> 'object'
typeof(undefined) ======> 'undefined'
//合成数据类型
typeof(函数) ======> 'function'
typeof(狭义上的对象) ======> 'object'
typeof(数组) ======> 'object'
//因此区分数组与对象数据时,一般采用 instanceof 方法
Object.prototype.toString.call(2) // "[object Number]"
Object.prototype.toString.call('') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(Math) // "[object Math]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
- 会将数据先转换为字符串再转换为数值,最后转为数值时是一个个字符依次转换。若第一个字符就不能转换为数字,则返回 NaN,因此转化空字符、null、undefined 时都返回为 NaN。
- 方法含有两个参数,分别为被转换的值、被转换的值的进制。
- 由于 parseFloat 方法的特性使它和 Number 转换方法的结果会不同。
- 若参数不是字符串,或字符串首位不能转化为浮点数,则返回 NaN(如空字符串)。
- 转换空字符传返回0,转换 null 返回0,转换 undefined 返回 NaN。
- Number 转换字符串与 parseInt 的区别是只要有一个字符无法转换成数值,就返回 NaN。
- Number 转换对象时先调用对象的 valueOf 方法,返回值为原始类型值后,就直接使用 Number方法;若返回值还是对象,则调用它的 toString 方法,返回值为原始类型值后,直接使用 Number 方法;若还是对象,就报错。
- String 方法转换对象时和 Number 类似,只不过把 toString 方法和 valueOf 方法的执行顺序互换。先调用对象的 toString 方法,返回值为原始类型值后,就直接使用 String 方法;若返回值还是对象,则调用它的 valueOf 方法,返回值为原始类型值后,直接使用String 方法;若还是对象,就报错。
- 其他数据类型转为布尔值时,undefined、null、false、0、NaN、空字符串6中数据为false;其余数据皆为true,包括空数组[ ]与空对象{ }
性能上: for > forEach > map,但是考虑到代码的语义化,因此不是特别强调性能的情况下,根据不同情况使用不同方法。
for : 基本循环语法
forEach : 数组的遍历方法,不返回值,无法中断执行
map: 数组的遍历方法,将每次的执行结果组成一个新数组返回
for … in … : 遍历对象的属性,包括对象所继承的属性
Object.keys() : 遍历对象的属性,返回一个对象自身属性名组成的数组,只返回可枚举属性
Object.getOwnPropertyNames() : 遍历对象的属性,返回一个对象自身属性名组成的数组,包括不可枚举的属性名
手动终端程序执行,抛出一个错误,参数可以是任意值
throw 123;
//Uncaught 123
捕获抛出的错误并进行处理,try 代码块里抛出错误, catch 代码块进行捕获处理,finally 代码块表示是否出现错误,最后都要运行的语句,finally 代码块可以省略。
当 try 代码块或 catch 代码块中存在 return 语句时,会先执行 finally 代码块再进行 return。
function test(){
try {
console.log(0);
throw 'bug';
} catch(e) {
console.log(1);
return true;
console.log(2);
} finally {
console.log(3);
return false;
console.log(4);
}
console.log(5);
}
let result = test();
console.log(result);
//结果依次为:
//0
//1
//3
//false
Object 本身可以作为工具函数使用,也可以作为构造函数使用
- Object() 作为工具方法使用时,会将任意值转为对象。
若参数为空/ undefined / null 则返回一个空对象;
若参数为原始类型的值,Object 会将其转为相应的包装对象的实例;
若参数是一个对象,则返回该对象,不做转换。
因此可以通过这一点,可以写一个判断对象是否为对象的函数。
function isObject( value ){
return value === Object(value);
}
Object 作为构造函数使用时,和工具函数类似。当参数为对象时,直接返回该对象;参数为原始类型的值时,返回其相应的包装对象。他们的区别是语义不同,工具函数是将一个值转为对象,而构造函数表示是新生成一个对象。
Object 对象的原生方法:
即 Object.prototype.hasOwnProperty() 接受一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否有该属性。
当与数值、字符串、布尔值相对应的 Number、String、Boolean, 作为构造函数使用时,他们会把原始类型的值转为对象。
let test = 'abc'; typeof String(test); //string typeof new String(test); //object
在有些情况下原始类型的值也会自动当作包装对象使用,并在使用后立即销毁。原始类型值的相关方法和属性就相当于使用时自动当作包装对象使用。
//此时'a'是一个字符串,但是它可以使用对象的属性 'a'.length;
由于 Array 作为构造函数时,不同的参数会有不同的行为,因此不建议使用它来生成新数组。
slice() 方法
提取目标数组的一部分,返回一个新数组,不改变原数组。
splice() 方法
删除原数组的部分成员,并可以在删除位置添加新成员,返回被删除的元素,会改变原数组。
sort() 方法
对数组成员进行排序,改变原数组。默认是按照字典顺序排,不是大小。
自定义排序时,sort() 传一个函数作为参数,函数的参数为进行比较的两个数组成员,若函数返回值大于0,表示第一个成员排在第二个后面;其余情况都是第二个排在后面。
join() 方法
指定参数作为分隔符,将所有成员连接为一个字符串返回,默认使用逗号。
数组的空位相关:
类数组对象:
具有 length 属性的对象,即可认为该对象是类数组对象
类数组对象转换为数组可以使用数组的 slice 方法:
Array.prototype.slice.call(类数组对象)
如果类数组对象想要使用数组的方法,可以通过 call() 把数组的方法放到类数组对象上,但是这种方式使用数组某些方法时性能会降低,所以推荐先将类数组对象转化为数组,在使用数组的方法
//类数组对象使用数组的 forEach 方法
Array.prototype.forEach.call(类数组对象,function(item,index){
console.log(`${index}:${item}`);
});
slice() 方法
提取目标字符串的一部分,返回一个新字符串,不改变原字符串。两个参数分别为开始位置和结束位置(不包含该位置)。
substring() 方法
提取目标字符串的一部分,返回一个新字符串,不改变原字符串。与slice() 作用类似,不过由于它对不合理参数的自动转换违反直觉,所以不建议使用。
substr() 方法
提取目标字符串的一部分,返回一个新字符串,不改变原字符串。与slice() 作用类似,不过两个参数分别为开始位置和截取长度。第二个参数为负数自动转为0。
trim() 方法
去除字符串两端空格,返回新字符串,不改变原字符串。
match() 方法
确定原字符串是否匹配某个子字符串,返回一个数组,成员为匹配的字符串,没有匹配到则返回 null。
返回的数组含有 index 和 input 属性,分别表示匹配字符串开始的位置,原字符串。
search() 方法
用法基本等同于 match(),不过返回的是匹配的第一个位置,没有匹配则返回-1。
replace() 方法
用于替换匹配的子字符串,一般情况下只替换第一个匹配子字符串,若是使用含 g 修饰符正则表达式则替换全部匹配的子字符串。
split() 方法
按照规格分割字符串,返回由子字符串组成的数组。
可以使用第二个参数,限定返沪数组的最大成员数量。
RegExp.prototype.ignoreCase
返回一个布尔值,表示是否设置了 i 修饰符。
RegExp.prototype.global
返回一个布尔值,表示是否设置了 g 修饰符。
RegExp.prototype.multiline
返回一个布尔值,表示是否设置了 m 修饰符。
RegExp.prototype.flags
返回一个字符串,包含已经设置的所有修饰符。
RegExp.prototype.lastIndex
返回一个整数,表示下一次搜索开始的位置,该属性可读写,只有在连续搜索时有意义。
RegExp.prototype.source
返回正则表达式的字符串形式,属性只读。
test() 方法
返回一个布尔值,表示当前模式是否能够匹配参数字符串。
注意:当正则表达式带有 g 修饰符时,test() 会从上一次结束的位置开始向后匹配,正则表达式内容会记录上一次的 lastIndex 属性,此时不应该更换所要匹配的字符串,结果会不准确。
exec() 方法
返回匹配结果。若发现匹配,返回一个数组,成员是匹配成功的子字符串,否则返回 null 。
注意: 若正则表达式带有 g 修饰符时,多次执行,下次搜索的位置从上一次匹配成功结束的位置开始。
执行的三步骤:
语法分析是先通篇扫描找出语法错误,不执行;之后进行预编译,最后解释执行。
其中预编译的主要流程大概是:
然后在AO对象的基础上解释一行执行一行,就解释执行。
详细过程参考
所有对象都有自己的原型对象,因为原型对象也是对象,所以原型对象也有自己的原型对象,就形成了原型链。
如果向上找,所有对象的原型都会指向 Object.prototye
,即 Object
构造函数的 prototype
属性,而Object.prototye
的原型是 null
, 因此原型链的尽头是 null
。
this
指向的call
、apply
、bind
方法call、apply的作用都是改变 this 指向,然后调用该函数。
call 的第一个参数当为空、null、undefined 时,this 指向全局对象,多余的参数表示函数的入参。
apply 的第一个参数为 null、undefined 时,this 指向全局对象,第二个参数则为数组,表示函数的入参。
function test (a, b){
console.log(a+b);
}
test.call(null,1,2);
test.apply(null,[1,2]);
bind 方法将函数体内的 this 绑定在某个对象上,并返回一个新函数。若第一个参数为 null、undefined 时等于将 this 绑定在全局对象上。
注意:根据 bind
方法的特性 bind()
方法每运行一次返回的就是一个新函数。
对象的深拷贝主要需要实现:
Object.create()
的第一个参数是要继承的原型,第二个参数是属性描述对象,用来添加新属性到创建的对象上。
//使用ES2017写法
function copyObj(orig){
return Object.create(Object.getPrototypeOf(orig),Object.getOwnPropertyDescriptors(orig));
}
//其他写法
function copyObj(orig){
let copy = Object.create(Object.getPrototypeOf(orig));
copyOwnPropertiesFrom(copy, orig);
return copy;
}
function copyOwnPropertiesFrom(target, source) {
Object.getOwnPropertyNames(source).forEach(function (propKey) {
let desc = Object.getOwnPropertyDescriptor(source, propKey);
Object.defineProperty(target, propKey, desc);
});
return target;
}