Javascript深度解析笔记

514 阅读9分钟

根据B站的小野森森老师的js课程整理的笔记

JS发展史

五大浏览器内核

image-20200907093818902

浏览器的历史和JS诞生

image-20200907095231983

image-20200907095238631

image-20200907100354338

image-20200907100512968

ECMA

image-20200907100958991

编程语言

image-20200907102110437

image-20200907102124144

Javascript

  • ECMAscript
  • DOM
  • BOM

image-20200907103612341

JS的值

image-20200907105938166

循环

类型转换

typeof

typeof返回的值都是字符串

image-20200907162100604

显示类型转换

Number

字符串都是NaN

image-20200907163417215

image-20200907163226130

image-20200907163244992

image-20200907163307680

parseInt

转化为整型

image-20200907163544418

image-20200907163607628

image-20200907163636635

true,null,undefined,NaN都是一样的结果:

image-20200907163746404

第二个参数:

image-20200907163945570

image-20200907170111558

parseFloat

image-20200907170313706

string

image-20200907170417744

Boolean

undefined null NaN "" 0 :false 其他的都是true

隐式类型转换

image-20200907171521021

image-20200907171611746

image-20200907171646636

image-20200907171856329

image-20200907171949891

undefined和null既不大于0也不小于0也不等于0

但是image-20200907172457118

isNaN

image-20200907173138457

TRUE FALSE FALSE TRUE FALSE TRUE

函数

函数属性

length:

prototype: 是不可枚举的,因此不可以用for-in发现

实参形参

执行:

test(1)

image-20200909100451044

函数参数默认值

image-20200831104806071

递归

image-20200831104223653

image-20200831105039456

预编译

暗示全局变量

image-20200831110239564

image-20200831111904847

AO - activation object 活跃对象, 函数上下文

image-20200831145605070

image-20200831145609483

执行结果:

image-20200831145914703

案例分析:

image-20200831145635649

执行结果: 输出function

GO- global object 全局上下文

image-20200831150442427

案例一:

image-20200831151753849

结果: 1 6 6

案例二:

image-20200831151903893

结果输出2

案例三:

image-20200831152642840

2 undefined undefined 4

作用域链

在函数被定义的时候生成该函数的作用域链,在函数执行前一刻生成自己的AO

分析函数

image-20200828170243170

a函数被定义时

image-20200828163907465

a函数被执行前一刻

image-20200828163914024

b函数被定义时

image-20200828163922328

b函数被执行前一刻

image-20200828163948444

b函数执行结束后

image-20200828163936759

image-20200828163955964

a函数执行结束时

image-20200828164001336

image-20200828164005727

闭包基础

定义

当内部函数被返回到外部并保存时,一定会产生闭包,闭包会产生原来的作用域链不释放,过度的闭包可能会导致内存泄漏,或加载过慢。

分析函数

image-20200828171122062

image-20200828174015442

image-20200828174021550

image-20200828174027950

image-20200828203656087

image-20200828174034060

例子:闭包返回两个函数

例一

image-20200828174043042

例二

image-20200828204909515

例子:闭包返回对象

image-20200828210412290

立即执行函数IIFE

自动执行,执行完成以后立即释放

IIFE : immediately-invoked function expression

写法

//1.括号里面包裹的,不管是什么,最终都会变成表达式
//2.立即执行函数不需要函数名,写不写都一样,因为是立即执行(表达式忽略函数名)
(function() {...})()

(function() {...}()) //W3C建议

//函数声明变成表达式的方法: + - ! || &&
1 && function test() {
    console.log(1)
}()

image-20200901155356041

image-20200828214500860

立即执行函数通常在前面加分号防止连起来会报错

image-20200828220201055

面试题

image-20200828214107399

注意: 这里第二个函数括号被认为是一个表达式,所以第二个函数不会执行

逗号运算符

image-20200828220412498

经典案例

下面这段代码的运行结果是什么?

image-20200828221153169

分析:

image-20200828223828665

解决方法一: 使用立即执行函数

image-20200828224200235

解决方法二: 使用外部传参

image-20200828224400648

解决方法三: 使用立即函数传参(重要)

每次i值不一样,立即执行函数所得到的参数j也就不一样,所以每次都是使用不同的j值的函数传给数组.

image-20200828225210963

面试题1

image-20200828225604871

这样的结果是点击每个i都是打印5

解决办法: 使用立即执行函数

image-20200828230631806

面试题2

image-20200828225925898

解析:

  1. if的括号里面是一个函数,所以肯定不是false(null,undefined,0,false),和函数是否为空函数无关,所以if里面的语句执行
  2. (function b() {}) 函数声明外部有括号,所以变成了表达式,表达式内部忽略函数名,所以b就被忽略了,typeof(b)就为undefined
  3. a = 10 + undefined之后就变成了'10undefined'字符串

传参

(function(a,b) {
	console.log(a+b)
}(3,5))

获取返回值

var x = (function(a,b) {
	return a + b
}(3,5))

题目:

image-20200828233218135

对象

删除对象方法:

image-20200831165728289

创建对象

image-20200831171129475

自定义构造函数

image-20200831171631607

规范写法:

image-20200831172004079

类比于vue实例

image-20200831172054569

构造函数

构造函数的this指向

image-20200831202612930

原理剖析

image-20200831204726458

不用new的等效写法

image-20200831204748782

修改构造函数

image-20200831205918132

包装类

new Number

image-20200831230446217

image-20200831225000391

new String

image-20200831225930252

image-20200831230434512

注意

image-20200831230601537

这两个都会报错,因为undefined和null不可以设置任何的属性和方法。

js包装类

image-20200831231630722

但是下面这个为什么不报错呢?

image-20200831233139662

解答:

字符串是原始值,没有属性和方法。通过str.length系统也创建了一个String对象并将length赋值3。但是new String()里面自带了一个le ngth属性。所以可以通过包装类来访问到String里面独有的length属性。

实际上是console.log(new String(str).length)

数组的截断方法

image-20200831232408757

length赋值为多少,就取前几位,剩下的截断。

如果length赋值为6,则增加一位empty

image-20200831233417560

那么对于字符串呢?

image-20200831234025424

也是因为包装类.

面试题

题目一:

image-20200831234442231

答案:

image-20200831234341728

题目二:

image-20200901094718089

答案:

image-20200901095004493

题目三:

image-20200901095425941

答案:

image-20200901100055581

题目四:

哪个能输出1 2 3 4 5?

image-20200901100658690

答案:

image-20200901101124959

所以是第一个和第三个执行了

ASCII码和UNICODE码

image-20200901102325663

Unicode码0-255位跟ASCII码一样,每个占一个字节,255位以后每个占2个字节.

应用:

image-20200901102653323

答案:

image-20200901164041384

题目

写一个构造函数,接受的参数数量不限,要求构造函数有两个方法,一是对输入的参数进行相加,二是对输入的参数进行相乘操作.

写法一:

image-20200901105631127

写法二:

image-20200901105652925

原型

prototype与_proto__

原理

image-20200901145856318

特点

image-20200901150409269

原型重写

image-20200901151441639

image-20200901153737676

window与return

image-20200901155248227

插件的常用写法:

image-20200901155820385

例子:

image-20200902092233078

原型链

原型链的顶端是Object.prototype,它里面保存了一个toString方法

image-20200901165956851

笔试题

题目一:

image-20200901170704184

答案:

image-20200901170554476

题目二:

image-20200901192308177

答案:

image-20200901192502536

即给student本身添加一个students属性,并把原型上该属性的值加1并且赋值给它.

所以结果是:

image-20200901192621685

题目三:

image-20200901192919754

解析:

image-20200901193658504

如果是Car.prototype.intro(),则输出mazda

Object.create()

image-20200901195620363

image-20200901200243642

所以不是所有的对象都继承于Object.prototype

image-20200901200827651

undefined和null能不能使用toString()

image-20200901200954247

image-20200901201557653

undefined和null既没有包装类也没有原型,所以没有toString方法,也没有相应的属性.

Object.prototype.toString与Number.prototype.toString

image-20200901202843942

image-20200901204051918

call和apply

image-20200901204645375

image-20200901210127901

应用:

image-20200902095843929

继承

圣杯模式

image-20200902101457868

代码:

image-20200902101510995

结果:

image-20200902101623536

圣杯模式的封装

image-20200902102946987

image-20200902102952533

image-20200902103858297

作业

image-20200902105509420

答案:

image-20200902112916921

面试题

image-20200903144033452

解析:

Foo.getName(); -> 2

把Foo这个函数当成一个对象,然后借用了这个对象的getName函数并执行,与Foo函数内部没有关系.

getName(); -> 4

预编译问题,先变量声明,然后函数声明,最后运行. getName最后运行的时候被赋值,覆盖了前面的函数.

Foo().getName(); -> 1

先执行Foo()函数,Foo内部getName之前没有var,所以当成全局的getName来处理,全局的getName这时又被Foo中的getName覆盖.然后执行this.getName(),this是window,就是log(1)了

getName(); -> 1

全局的getName函数在上一步中被Foo中的getName覆盖,所以还是log(1)

new Foo.getName(); -> 2

Foo后面没有执行符号,这时点的优先级比new高,执行Foo.getName(),所以是2. new 2 没有意义.

new Foo().getName(); -> 3

Foo后面有个执行符号,先执行 new Foo(),创建了一个实例,最后执行实例的getName函数,但是这个实例本身没有getName函数(因为Foo里面没有this.getName=...),而实例的原型上有getName函数,所以log(3)

new new Foo().getName(); -> 3

相当于new 3

对象相关

链式调用

原理

image-20200902144623578

结果

image-20200902144637483

对象属性遍历

for...in

image-20200902150127823

hasOwnProperty

image-20200902150737897

结果是: Benz red 3.0

判断属性是否存在

image-20200902151319931

instanceof

判断A对象是否是构造函数B实例化出来的: A instanceof B

image-20200902152007972

判断数组的方法: 三种

image-20200902152653239

建议使用的方法:

image-20200902153309428

typeof返回的值:6种

注意: typeof返回的值都是string类型

object(null),boolean,number,string,undefined,function

this指向

全局的this -> window

预编译函数内部的this -> window

image-20200902153843453

构造函数的this -> 实例

image-20200902155103579

call和apply

image-20200902160843841

callee和caller

argument.callee

返回实参所对应的正在执行的函数

image-20200902162035514

结果: 3 3 2

image-20200902162120727

应用:自执行函数

image-20200902162418634

caller

image-20200902162949850

isNaN 内部原理

image-20200902165237933

笔试题

题目一:

image-20200902205911399

解析:

image-20200902210737453

题目二:

image-20200902210941177

深拷贝

方法一:

function deepClone(origin,target) {
    var tar = target || {},
        toStr = Object.prototype.toString,
        arrType = '[Object Array]';

    for (var key in origin) {
        //剔除原型上的属性
        if (origin.hasOwnProperty(key)) {
            //判断是否为引用类型
            if (typeof(origin[key]) === 'object' && origin[key] !== null) {
                //判断你是否为数组
                toStr.call(origin[key]) === arrType ? tar[key] = [] 
                : tar[key] = {};
                deepClone(origin[key],tar[key]);
            } else {
                tar[key] = origin[key];
            }
        }
    }
    return tar
}

方法二:使用json

var str = JSON.stringify(origin)
var target = JSON.parse(str)

数组

底层

image-20200903095916217

数组实际上就是对象的另外一种形式:

image-20200903100908831

稀松数组

image-20200903100241406

如果逗号后的空值为最后一位,那么这一位无效,即不存在.

用构造函数构造数组,不能有逗号之间的空值,否则会报错.

用构造函数构造数组,若只填一个数字,则代表数组长度

image-20200903100549061

方法(修改原数组)

push unshift

image-20200903102200682

手写push:

image-20200903102850333

pop shift

image-20200903103211323

reverse

翻转

splice

image-20200903103832294

image-20200903104013403

image-20200903104043763

sort

image-20200903105710967

image-20200903110838791

随机排序

image-20200903111344150

方法(不修改原数组)

concat

image-20200903151043184

toString

image-20200903151148801

slice

复制数组:

image-20200903151406654

截取: [start, end) 前面闭区间,后面开区间

image-20200903151957813

join

不填相当于toString

image-20200903152148080

填了就是放入分隔符

image-20200903152241690

split

不放参数的话,把整个字符串当成一个元素放入数组

放参数就是根据分隔符放入数组

image-20200903152545324

第二个参数就是截取的位数

image-20200903152648082

重写unshift

使用splice

image-20200903162616059

使用concat

image-20200903163141777

数组按照元素的字节数排序

image-20200904090029961

数组去重

image-20200904092720857

类数组

是类似于数组的对象,但是没有继承数组的原型,即没有数组的方法.直接继承的是对象的原型:

image-20200903153531654

用对象模拟类数组:

image-20200903153816535

类数组转化为数组

image-20200903162933153

push原理

image-20200903154241544

面试题

image-20200903154305845

解析:

image-20200903154448522

应用:

image-20200903155619863

封装一个typeof方法

提示:

image-20200903160030698

答案:

image-20200904090947638

tip:

typeof里面放一个未声明的变量输出undefined 不报错

JS错误信息类型

SyntaxError 语法错误

image-20200904142737313

ReferenceError 引用错误

image-20200904143028450

RangeError 范围错误

image-20200904143246784

TypeError 类型错误

image-20200904143640836

URIError URI错误

知识普及

image-20200904144222913

image-20200904144226742

image-20200904144920957

image-20200904145042343

错误

image-20200904145336131

EvalError eval函数执行错误

表现

image-20200904145819835

JSON数据

image-20200904150157181

eval用法(不推荐使用)

es6摒弃

用法不规范(见表现) 不好调试 性能问题 网络安全

将json的字符串数据转化为可循环的对象

image-20200904150604057

总结

以上6种错误都可以用户自定义并抛出,即都有对应的实例化函数

image-20200904150912911

还有一个总的error

image-20200904151004660

手动抛出错误

try...catch

image-20200904151527545

image-20200904151749712

finally

image-20200904151933335

throw

扔出错误信息

image-20200904153801980

ES5严格模式

ESMAScript历程

image-20200904154540209

启动严格模式

第一种:

最上面一行

image-20200904154802456

第二种: 函数内部

image-20200904154851117

实例

with函数

image-20200904155221896

image-20200904155832715

严格模式规则

caller callee

image-20200904160701603

image-20200904160735472

a = 1 或者 a =b =1

image-20200904160901305

image-20200904160910823

this指向

this要赋值,不然指向undefined

image-20200904160947709

image-20200904161051504

image-20200904161129248

image-20200904161233921

函数的参数不能重复

image-20200904161401194

对象的属性重复的不会显示,但不会报错

image-20200904161458197

eval

严格模式下,eval有自己的作用域;非严格模式,eval是全局的作用域

image-20200904161719264

image-20200904161704157

image-20200904161744386

垃圾回收

原理

  1. 找出不再使用的变量
  2. 释放其占用内存
  3. 固定的时间间隔运行

方式

标记清除

排除闭包里的变量和全局变量

image-20200905101951798

引用计数

image-20200905102215156