本文把平时的一些读书笔记和理解进行了整理概括,包含一些易混淆、遗漏的知识点,也会配上一些例子,可能不是很完整,还会有点杂,但也许会有你须要的(目前先整理了一部分,笔记有点多,后续会持续更新)。git
1.变量是常见的标识符,以字母、$、_开头,可是不能包含+ - *等标识符,中文也是合法的标识符,保留字不能做为标识符。github
2.函数声明和赋值会分为两个阶段,一个是编译阶段的任务,就是编译器声明变量,另外一个是执行阶段的任务,就是js引擎去查询赋值,因此声明都会在代码被执行前首先进行处理。正则表达式
3.若是在函数中使用var定义一个变量,函数调用时至关于建立了这个变量并赋值,在函数退出后就会被销毁,因此在函数外面读不到这个变量。可是若是在函数内定义变量时不使用var,至关因而全局变量,外面通常是读获得的,可是若是不运行这个函数时,至关于没有建立这个变量,外面也是读不到的:json
function test(){
message = 'hello'
}
test(); // 若是不先运行这个,则读不到message变量
alert(message);
复制代码
4.var声明的变量不能用delete删除 ,delete能够删除一个对象的属性,但不能删除继承的属性。数组
5.变量没有类型,变量的值才有类型。安全
1.提高是指声明会被视为存在于其所出现的做用域的整个范围内,就是说在哪一个做用域声明的,它就在这个做用域内(let, const并不会提高)。闭包
2.函数声明提高:app
foo(); // typeError 至关于对undefined进行函数执行,因此是类型错误
bar(); // referenceError 不存在这个函数,因此是引用错误
var foo = function bar() {} // 函数表达式不会提高
复制代码
3.函数提高的优先级大于变量提高的优先级,我的理解为函数声明在变量之下,然后会把变量覆盖,进而优先级更高函数
// 例一:
var fo;
fo = function(){
console.log(456);
}
function fo(){
console.log(123);
}
fo(); // 456 函数声明被提高到了最上面,而后被后面的函数覆盖
// 例二:
fo = function(){
console.log(456);
}
fo(); // 456 同理,函数也是被覆盖
var fo;
function fo(){
console.log(123);
}
// 例三:
var fo = function(){
console.log(456);
}
function fo(){
console.log(123);
}
fo(); // 456 同理,函数也是被覆盖
// 同时函数声明还能被后面的声明覆盖,说明越后面的函数声明排在越后面,而后把前面的函数覆盖了:
foo(); // 3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
}
function foo() {
console.log(3);
}
复制代码
4.继续例子post
console.log(foo); // 打印出函数源码
foo(); //能够执行 undefined 和 12
var foo=10;
foo(); //foo已经被赋值为一个变量,没法执行foo为函数,因此报错
console.log(foo); // 上面报错,这里执行不到
function foo(){
var a;
console.log(a);
a=12;
console.log(a);
}
console.log(foo);
//以上实际执行顺序:
var foo;
function foo(){
var a;
console.log(a);
a=12;
console.log(a);
}
console.log(foo); // 打印函数源码
foo(); // 执行函数
foo=10; // foo被赋值为10
foo(); //因为这里报错,foo已经被赋值,找不到这个函数,下面的都不会被执行
console.log(foo);
console.log(foo);
复制代码
1.做用域是一套规则(或者理解为约束范围),用于肯定在何处以及如何查找变量,其实也就是查找变量的地方。
2.每一个环境中都有一个变量对象,因此该环境下定义的变量和函数都保存在这个对象中。
3.当代码在一个环境中执行时,会产生做用域链,如函数的做用域链的第一个对象是arguments对象(arguments在全局中是不存在的),第二个对象是上一层环境,即该环境的外部环境,以此类推,全局对象是做用域链中的最后一个对象。
4.if和for中用var声明的变量都是全局变量。
5.循环变量比较:
// 例一:
for(var i = 0; i < 3; i++) {
console.log(i); // 0 1 2
}
console.log(i); // 3
// 例二:
for(var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i); // 后面再输出三次4
}, 0)
}
console.log(i); // 这个先输出,为4
// 例三:
for(let i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i); // 1 2 3 let在每次迭代中都从新声明
}, 0)
}
复制代码
6.函数参数也是属于函数局部做用域的,它们是隐式建立的。
7.块做用域:
以上方式可将变量绑定在一个块中,造成这个变量的块做用域。 块做用域还利于垃圾回收,方便引擎明确哪块做用域的变量能够进行回收。
8.暂时性死区:
{
typeof a; // undefined 未声明的反而不会报错
typeof b; // referenceErroe 暂时性死区
let b;
}
复制代码
1.词法做用域意味着做用域是由书写代码时函数声明的位置决定的。
2.eval()和with()能欺骗词法做用域,并且还会影响性能(由于js引擎不能事先肯定变量和函数的定义位置,即不能进行词法静态分析)。
3.函数在哪里调用没有关系,变量的位置在编译的词法分析阶段就肯定了:
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo(); // 这里其实就是闭包,包含了该函数的词法做用域
}
bar(); // 1
// 函数调用位置更换:
bar(); // undefined 全局value虽然声明了,可是在bar函数调用的后面才进行赋值,因此是undefined
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
复制代码
1.可参考我写的这篇博客:[闭包]该如何理解?
1.switch语句可判断值、字符串、表达式等,且是全等比较,不会产生类型转换(实际上是===不容许进行类型转换)。
2.其实没有else if这个规范,其实真正是:
else{ // 省略了{}这个块而已
if () {
} else {
}
}
复制代码
3.switch:
// 例一:
switch(a){
case 1: // case不能放逻辑表达式,只能是常量表达式,即只能进行单一的===对比
// code
break;
case 2:
// code
break;
default:
// code
}
// 例二:
var b = '42';
switch(true){
case b == 2: // 要进行类型转换比较则采起这种方式
// code
break;
case b == 42:
// code
break;
case b > 30: // 大小比较
// code
break;
default:
// code
}
// 例三:
var c = '42';
switch(c){
case 1:
case 2:
default:
console.log('default')
case 3:
console.log('3');
break;
case 4:
console.log('4')
}
// 会获得'default' '3', 首先会遍历全部的case,而后没有符合的case,而后执行default,以后没遇到break就继续往下执行case 3,最后到break中止。
复制代码
1.for循环中先把范围值保存为变量,优化循环。
2.do while
do {
// code
} while ('条件'); // 记得加上后面的分号
复制代码
3.遍历对比:
自身:
- ① Object.keys返回对象自身的可枚举属性(数组)。
- ② Object.getOwnPropertyNames返回对象自身可枚举和不可枚举属性(数组),如数组的length属性。
- ③ hasOwnPropery()遍历自身可枚举和不可枚举属性。
自身和原型:
- ① in操做符能访问自身和原型上的可枚举和不可枚举属性。
- ② for in 能访问自身和原型上的可枚举属性,不含不可枚举属性。
4.循环更改格式:[ [ {}, {} ,{} ], [ {}, {} ,{} ], [ {}, {} ,{} ] ] 若是要转为[ [ ], [ ], [ ] ] 或者其余格式,可先用concat()方法把数组中的数组先循序链接起来,而后再用其余方法处理。
5.可使用while来判断循环,直到不知足条件后才中止判断运行,比for循环直观方便,如:
while( i<5 ) { // i为大小不肯定值
// code
i++;
}
复制代码
6.中断循环:forEach不能中断,for能够。
7.break和continue:break能跳出循环,但也只能跳出一层循环,若是须要跳出多层循环,则须要使用标签;continue能跳过本轮循环,继续下轮循环:
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log('i=' + i + ', j=' + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// 标签至关于定位符,用于跳转到程序的任意位置,语式以下:
label:
复制代码
1.基本类型:number 、string、boolean、null、undefined、symbol。 引用类型:object (包含子类型function、array)。
typeof function a(){}; // 'function'
复制代码
2.typeof 检测能获得的类型:
1.JavaScript 语言的底层根本没有整数,全部数字都是小数(64位浮点数)。
2.在JavaScript内部,整数和浮点数是一样的储存方法,因此3和3.0被视为同一个值:
3.0 === 3; // true
复制代码
3.数字的二进制浮点数没那么精确:
0.1 + 0.2 === 0.3; // false
复制代码
4.数字范围:2的1024次方到2的-1023次方。
5.最大的安全整数:2^53。
6.parseInt方法用于将字符串转为整数。若是parseInt的参数不是字符串,则会先转为字符串再转换。字符串转为整数的时候,是一个个字符依次转换,若是遇到不能转为数字的字符,就再也不进行下去,返回已经转好的部分。而isNaN是先将总体参数转化为number再进行判断:
parseInt('abc'); // NaN
parseInt('.3'); // NaN
parseInt(''); // NaN
parseInt('+'); // NaN
parseInt('+1'); // 1
parseInt('1000', 2); // 8 可接受第二个进制参数
复制代码
7.toFixed注意事项:
typeof 12.236.toFixed(2); // 'string' 指定保留位数后数字变成了字符串
42.toFixed(3); // 会报错,由于会把小数点算为42的一部分,须要用使用如下方式:
(42).toFixed(3);
42.0.toFixed(3)
42..toFixed(3)
复制代码
8.判断是否为整数:
// 方式一:
typeof a === 'number' && num%1 === 0
// 方式二:
Number.isInteger(a);
// 方式三:
Number.isSafeInteger(a);
复制代码
9.NaN:
NaN === NaN // false
NaN !== NaN // true
Boolean(NaN) // false
typeof NaN // 'number'
// 判断是否为NaN:
// 原生方式:
Number.isNaN(n);
// 自定义方式:
function isNaN(n) {
return n !== n;
}
复制代码
1.字符串可以使用方括号[ ]来获取该位置上的字符,也可查询长度,但没法像数组同样增长或删除字符。
2.数字字符串转数字的一种方式:字符串与1想乘:typeof ('2' * 1) 或者typeof (+'2')
3.数字转字符串的一种方式:数字加空字符串: typeof (1 + '')
4.拆分:
'a b c'.split(' ');
// ['a', 'b', '', '', 'c'] b和c之间有三个空格,因此三个空格会获得夹着的两个空格。
复制代码
5.字符串没有map()、join()等方法,但能够经过Array.prototype.call()来借用,reverse()不可借用,可先转为数组再使用。
6.截取:
①substring() : 参数若是是负数,会变为0,若是第一个参数大于第二个参数,则会调换位置。
②substr(): 第一个参数是开始位置,第二个是长度,若是第一个参数是负数,则表示倒数计算的字符位置,若是第二个参数是负数,则返回空字符串(至关于返回长度为0)。
③match(): 用于肯定原字符串是否匹配某个子字符串,返回一个数组,成员为匹配的第一个字符串。若是没有找到匹配,则返回null。
④search(): search方法的用法基本等同于match,可是返回值为匹配的第一个位置。若是没有找到匹配,则返回-1。
1.六个false值:“”,null, undefined, 0, NaN,false。
2."''"不是空字符串,是true。
3.document.all是ie中的假值对象,是false。
1.null和undefined的名称既是类型也是值,null指空值,曾赋过值,但目前为没有值,undefined指没有值,未赋值。
2.null是js中的一个bug,由于不一样的对象在底层都表示为二进制,在js中二进制前三位都为0时就判断为object类型,而null的二进制表示是全0,因此执行typeof时会获得‘object’(或者把null当成一个空对象指针,因此typeof检测会获得object)。
3.null==undefined 是true,且不进行类型转换,由于它们是相似的值,且只有null和undefined是==,和其它对比都是false,因此:
null == 0 // false
undefined == 0 // false
null == '' // false
undefined == '' // false
null == fasle // false
undefined == false // fasle
// 只有自身转化才会是布尔值:
!null == true // true
!undefined == true // true
// 但运算时,null会转型为0,undefined转为NaN:
null + 3 // 3
undefined + 3 // NaN
// 判断类型:
typeof null // 'object'
typeof undefined // 'undefined'
复制代码
1.全部的对象都是继承自Object的,都会带有这些属性,toString(), valueOf(), constructor。
2.建立对象 :
// ①字面量方式:
var o = {};
// ②Object.create方式:
Object.create('这个对象的原型,对象属性的描述')
Object.create({x:1,y:2}) // 继承了这个对象的属性
Object.create(null) // 则不会继承任何属性和方法;
Object.create(Object.prototype) // 和new Object()同样建立了一个空对象
// ③构造函数方式:
function createPerson (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name);
}
}
// ④工厂模式方式:
function createPerson (name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
alert(this.name);
}
return o;
}
复制代码
构造函数与工厂模式区别:
构造函数过程:
构造函数之因此叫“构造函数”,就是说这个函数的目的,就是操做一个空对象(即this对象),将其“构造”为须要的样子。构造函数中若是有return一个对象,则new这个构造函数时获得的是这个对象,而不是新的this对象(能够认为构造函数内开头先定义了一个this变量,而后最后返回this)。
构造函数内的方法在每次生成实例的时候,实例对象内的函数都是新生成的,至关于new了一个函数,由于函数也是对象,因此每次生成实例对象内的函数的时候,就至关于定义了一个对象,因此虽然它们名字相同,但倒是不一样的函数。
// o指对象,返回的就是对象自己
o.valueOf() === o // true
// 数组也是如此,由于数组也是对象,也能够用构造器生成:
var a = new Array()
// 就像构造函数建立对象,因此a也会带有toString等属性,由于对象都会继承toString等方法。
复制代码
4.访问对象属性:若是对象的属性是动态、不可预测或不符合变量规范的,用方括号的形式person["name"],而不能用点.方式,方括号内要放字符串,但当name是变量时,也能够用person[name]来访问属性。
5.检测属性:
in
// 检测属性是否存在于自身或原型上,含不可枚举属性hasOwnProperty()
// 检测属性是否存在于自身,含不可枚举属性propertyIsEnumerable()
// 检测属性是否可枚举6.对象转换:
// ①Object()可将任何值转为对象;Object()返回一个空对象;若是Object方法的参数是一个对象,它老是返回该对象:
var value = {};
var obj = Object(value) // 返回原对象
obj === value // true
// ②valueOf返回一个对象的“值”,默认状况下返回对象自己:
var obj = new Object();
obj.valueOf() === obj // true
// ③new Object(value)的值是value对象。
复制代码
var o1 = new Object();
o1.toString() // "[object Object]" 注意大小写
复制代码
数组、字符串、函数、Date 对象都分别部署了自定义的toString方法,覆盖了原生的Object.prototype.toString方法,原生的Object.prototype.toString()返回的是类:
// 数组:
[1, 2, 3].toString(); // "1,2,3"
// 字符串:
'123'.toString(); // "123"
// 函数:
(function () { return 123;}).toString(); // "function () { return 123; }"
// Date:
(new Date()).toString(); // "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
复制代码
8.对象是引用同一个地址:
var o1 = {};
var o2 = o1;
o1 = 1; // o1是改变了本身的指向,而不是改变{}
o2; // {} o2已指向{}的地址,只要这个地址的对象没有变,它就不会变
复制代码
原始类型是值拷贝:
var x = 1;
var y = x;
x = 2;
y // 1
复制代码
深拷贝:
// 方式一:
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
// 方式二:
function deepCopy (p, c) {
c = c || {};
for (let i in p) {
if (p.hasOwnProperty[i]) { // 排除继承属性
if (typeof p[i] === 'object') {
c[i] = Array.isArray(p[i]) ? [] : {};
deepCopy[p[i], c[i]];
} else {
c[i] = p[i];
}
}
}
return c;
}
复制代码
9.对象属性描述符:
// configurable 可否修改属性
// enumerable 是否可枚举
// writable 可否修改属性的值
// value 属性的数据值
var myObject = { a: '2' };
var b = Object.getOwnPropertyDescriptor(myObject, 'a');
console.log(b); // {value: "2", writable: true, enumerable: true, configurable: true}
Object.defineProperty(myObject, 'a', {
value: '3',
writable: true, // 可修改
enumerable: true, // 可枚举
configurable: true // 可配置,若是为false,则不能修改以上配置,但能够//myObject.a= 5, writable能够变为false, 但不能变为true
})
复制代码
10.get set
var other = {
get a(){
return this._a_;
},
set a(val){
this._a_ = val*2;
}
}
console.log(other); // {}
console.log(other.a); // undefined
other.a = 2;
console.log(other.a); // 4
复制代码
11.Function.prototype是一个函数,RegExp.prototype是一个正则表达式,Array.prototype是一个数组,它们都是空的,(但总的来讲它们都是对象)。
12.字符串要访问属性或方法时,js会自动将其转化包装对象,这种让js自行执行,而不要人为转为包装对象,不然会影响性能。
'abc'.length // 3
复制代码
1.函数中执行return语句后马上退出,因此放在return语句后面的语句不会执行;未指定返回值的函数返回的是undefined。
2.函数的参数在内部是用数组来表示的,arguments是类数组,可用arguments[0]来获取参数,arguments的长度是由传入的参数个数决定的,而不是由命名参数的个数决定的;参数传递的都是值,传入引用类型值时注意是否有影响。
3.函数名称和参数长度:a.name , a.length是预期传入的参数个数,不是实际参数个数。
4.没有函数签名,因此没有重载,即同名函数会被后面发覆盖,可是能经过判断参数的类型和数量来做出不一样的反应来模仿方法的重载。
5.函数其实是对象,每一个函数都是Function类型的实例,并且和其余应用类型同样具备属性和方法,如call、apply、length、contructor、prototype、name等属性,函数名其实是指向函数对象的指针。
6.区分函数声明和表达式的方法是看function出如今声明的哪一个位置,若是function是第一个词,就是函数声明,不然为函数表达式(自执行函数是以括号开头,因此为表达式)。
7.函数内有两个特殊的对象:
①arguments: arguments有一个callee属性,是一个指针,指向拥有这个arguments对象的函数。
② this: this引用的是函数据以执行的环境对象。
8.一些区别:
①函数声明:function a() {}
可直接a()调用,花括号后面不用分号结尾。
②函数表达式:let t = function() {}
可用t()调用,且通常不带函数名,若是加上函数名,该函数名只在函数体内部有效,在函数体外部无效,花括号后面带分号:
var print = function x(){
console.log(typeof x);
}
x; // ReferenceError: x is not defined
print(); // function
复制代码
var add = new Function(
'x',
'y',
'return x + y'
)
// 等同于
function add(x, y) {
return x + y;
}
复制代码
var a = 1;
var x = function () {
console.log(a);
}
function f() {
var a = 2;
x();
}
f(); // 1
复制代码
9.原生函数:
10.类型判断:
var a = new String('abc');
typeof a; // 'object' a为包装对象
a instanceof String // true
Object.prototype.toString(a); // '[object, Object]' 若是不使用call,不论传入什么,都为Object类,这个没什么用,若是要用于判断类型,都得加call
Object.prototype.toString.call(a); // '[object, String]' 让a调用Object上的toString方法,属于String类
复制代码
11.返回
return ( // return若是有换行,须要加括号
a*2;
)
复制代码
12.若是构造函数内部有return语句,并且return后面跟着一个对象,new命令会返回return语句指定的对象;不然,就会无论return语句,返回this对象:
// 例一:
var Vehicle = function (){
this.price = 1000;
return { price: 2000 };
}
(new Vehicle()).price; // 2000 若是不使用new,则this将变为全局的
// 例二:若是对普通函数使用new命令,则会返回一个空对象:
function getMessage() {
return 'this is a message';
}
var msg = new getMessage();
msg // {}
typeof msg // "object"
复制代码
1.可经过设置数组的长度对数组进行增长或删减元素,也能够为数组添加字符串键,但不会算入数组长度(数字字符串除外),如:a['13'] = 'test'
2.检测是否为数组的两种方法:
3.对数组调用toString()方法时返回每一个值的字符串以逗号链接起来的字符串,alert()接受的是字符串参数,因此:
var people=['per1', 'per2'];
alert(people.valueOf());
// 返回的仍是以逗号链接的字符串,由于会默认调用后台的toString()方法将people转为字符串
复制代码
4.value.join("|"),不传参时默认以逗号链接。
5.返回值:
6.sort()是高阶函数,可传入方法:
var arr = [2, 10, 20, 1];
arr.sort(function (x, y) { // 升序
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]
//或者
function(x, y){
return x - y; // 升序
}
复制代码
7.栈与队列:
8.数组原始值是否改变:
不改变原数组:(链接\截取\循环)
改变原数组:(增长\删除\换序)
var a = [1, 2, 3, 4];
a.splice(2); // [3, 4]
a; // [1, 2]
复制代码
9.delete删除数组元素,不会改变数组长度,该位置会变空为undefined。
10.类数组转数组:由于slice内部返回的是新建的数组(使用循环取值):
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 }) // ['a', 'b']
Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);
复制代码
11.reduce():
应用:找出最长字符串:
function findLongest(entries) {
return entries.reduce(function (longest, entry) {
return entry.length > longest.length ? entry : longest;
}, '');
}
findLongest(['aaa', 'bb', 'c']); // "aaa"
复制代码
12.数组去重:
let s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
let arr = [..s];
let arrs = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
arrs.filter(function (element, index, self) {
return self.indexOf(element) === index;
})
复制代码
13.空单元数组:
// 例一:
var arr = ["a", "b", "c"];
console.log(arr['2']); // 'c'
arr['5'] = 'e';
console.log(arr.length); // 6
console.log(arr); // ["a", "b", "c", empty × 2, "e"]
// 例二:
var a = new Array(3);
console.log(a); // [empty × 3] 空单元数组
var b = [undefined,undefined,undefined]; // 这个不是空单元数组,是值为undefined的数组
// 例三:
var c = [];
c.length = 3;
console.log(c); // [empty × 3] 空单元数组
复制代码
14.数组和字符串都有的方法:splice()、indexOf()、lastIndexOf()、contact()
1.toString()转换为字符串,若是是数字,可传递基数来确认返回的是多少进制的数字字符串:
let num = 12;
num.toString(8) // 返回8进制字符串
复制代码
2.alert
会调用对象的toString()
方法,alert(a)
和alert(a.toString())
是同样的。
3.对象转化:
①对象转数字默认先调用valueOf()方法,若是返回的不是原始值,则再调用toString()方法。
②对象转字符串默认先调用toString()方法,若是返回的不是原始值,则再调用valueOf()方法。
③日期对象转数字时会默认直接调用toString()方法。
4.null和undefined没有toString()方法,可是可使用String()来将它们转为字符串。
5.Number转化:
Number({}); // NaN
Number({a: 1}); // NaN
Number([1, 2, 3]); // NaN
Number([]); // 0
Number([5]); // 5
String([]); // ""
复制代码
6.使用:
var a;
typeof a; // undefined
typeof b; // undefined 尽管没声明b,但不报错,但若是使用b,则会报错
var c = {};
c.a // undefined 访问不存在的对象属性不会报错,因此也不能根据c.a===undefined来判断是否有a属性。
复制代码
7.数组的toString方法(即Array.prototype.toString())被从新定义过,将全部单元字符串后用逗号链接起来,而原生的Object.prototype.toString()返回的是“类”。
var a = [1, 2, 3];
Object.prototype.toString(a); // "[object Object]" 返回“类”
console.log(a.toString()); // '1,2,3' 会先找到Array上的toString方法
console.log(Array.prototype.toString.call(a)); // '1,2,3' 让a调用Array上的toString方法
console.log(Object.prototype.toString.call(a)); // [object Array] 让a调用Object上的toString方法
复制代码
8.JSON.stringify()能够将对象转化为字符串,但它本质上是若是对象中有toJSON方法就先调用toJSON方法将所要转化的对象换为安全的JSON值,把循环引用类型、函数、null、undefined等不符合json的值过滤掉,而后再交由toString方法来转化。
JSON.stringify()还可接受数组参数或函数参数,做用和toJSON相似,用于过滤对象:
var a = {
b: 42,
c: '36',
d: [1,2,3]
};
JSON.sringify(a, ["b", "c"]); // "{"b":42, "c":"36"}"保留传入数组中包含的对象属性
JSON.stringify(a, function(k, v) {
if (k !== "c"){
return v;
}
}) // "{"b":42, "d":[1,2,3]}"
复制代码
9.parseInt:
parseInt(new String(42)) // 42 是数字
复制代码
由于parseInt是针对字符串的,所要parseInt会先调用所传入参数的toString方法将参数转化为字符串,而后再解析数字。
10.在存在布尔值中使用==或===进行比较,或数字与字符串比较时,都是先将不是数字的那方先转换为数字(转为数字的优先级:布尔值>对象>字符串>数字),而后再进行比较:
var a = '123';
var b = true;
a == b; // false
//由于123不等于1,会先将布尔值转为1,而后和'123'比较,而后将'123'转为123再进行最后比较,因此“存在”和“==true”是不同的,好比:
var a = '42';
// if(a) 和 if(a==true) 不同。
复制代码
11.进行算数运算时,优先调用valueOf()方法来转化数字,若是未转化成原始类型,则再调用toString()方法,可是Data对象是优先调用toString()方法。
由于比较多,因此目前只整理到这里,后续有些比较重要难懂的模块会分开更新,但愿对你有所帮助,若有不合理的地方欢迎指正,喜欢的话欢迎关注一波,后续会持续更新。