一、原型与原先链 原型(prototype) 1、函数的prototype属性 每个函数都有一个prototype属性。它默认指向一个Object空对象(即成为:原型对象)
原型对象中有一个属性constructor,它指向函数对象
2、给原型对象添加属性(一般都是方法) 作用:函数的所有实例对象自动拥有原型中的属性(方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 console .log (Date .prototype , typeof Date .prototype );function fun ( ){ } console .log (fun.prototype );console .log (Date .prototype .constructor === Date ); console .log (fun.prototype .constructor === fun); fun.prototype .test = function ( ) { console .log ('test原型对象添加' ); } var f = new fun ();f.test ();
显式原型与隐式原型 每个函数function都有一个prototype,即显式原型属性,默认指向一个空的object对象
每个实例对象都有一个_proto _ ,可称为隐式原型
对象的隐式原型的值为其对应构造函数的显式原型的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function Fn ( ){ } console .log (Fn .prototype );var fn = new Fn (); console .log (fn.__proto__ );console .log (Fn .prototype === fn.__proto__ );Fn .prototype .test = function ( ){ console .log ('给原型对象添加方法' ) } fn.test ()
函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象
对象__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
程序员能直接操作显式原型,但不能直接操作隐式原型(ES6之前)
原型链 1 2 3 4 5 6 7 8 9 10 11 12 function Fn ( ){ this .test1 = function ( ){ console .log ('test()' ); } } Fn .prototype .test2 = function ( ){ console .log ('test2()' ) } var fn = new Fn ();fn.test1 (); fn.test2 ();
访问一个对象属性时,
先在自身属性中查找,找到则返回
如果没有,再沿着__proto__这条线往上找,找到则返回
如果最终没找到,返回undefined
原型链别名:隐式原型链
作用:查找对象属性
构造函数/原型/实例对象的关系 1、函数的显示原型指向的对象:默认是空Object实例对象(但Object不满足)
2、所有函数都是Function的实例(包含Function自身)
3、Object的原型对象是原型链的尽头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function Fn ( ){ this .test1 = function ( ) { console .log ('test1()' ); } } var fn = new Fn ();console .log (Fn .prototype instanceof Object ); console .log (Object .prototype instanceof Object ); console .log (Function .prototype instanceof Object ); console .log (Function .__proto__ === Function .prototype ); console .log (Object .prototype .__proto__ );
原型链属性 1、读取对象属性值时:会自动到原型链中查找
2、设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加属性并设置值
3、方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
instanceof instanceof是如何判断的
表达式:A instanceof B
如果 B函数对象的显示原型对象在 A对象的原型链上,返回true,否则返回false
Function是通过new自己产生的实例
二、执行上下文与执行上下文栈 变量提升与函数提升 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var a = 3 ;function fn ( ) { console .log (a); var a = 4 ; } fn ();function fn ( ) { var a; console .log (a); a = 4 ; } fn2 ();function fn2 ( ) { console .log ('fn2()' ); } fn3 (); var fn3 = function ( ) { console .log ('fn3()' ); }
1、变量声明提升
通过 var 定义(声明)的变量,在定义语句之前就可以访问到
值:undefined
2、函数声明提升
通过 function 声明的函数,在之前就可以直接调用
值:函数定义(对象)
执行上下文 代码分类(位置) 全局代码
函数(局部)代码
全局执行上下文 在执行全局代码前将window确定为全局执行上下文
对全局数据进行预处理
var定义的全局变量 ===》undefined,添加为window的属性
function声明的全局函数 ===》赋值(fun),添加为window的方法
开始执行全局代码
函数执行上下文 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)
对局部数据进行预处理
形参变量 ===》赋值(实参) ===》 添加为执行上下文的属性
arguments ==》赋值(实参列表),添加为执行上下文属性
var定义的局部变量 ===》undefined,添加为执行上下文的属性
function声明的函数 ===》 赋值(fun),添加为执行上下文的方法
this ===》赋值(调用函数的对象)
开始执行函数体代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function fn (a1 ) { console .log (a1); console .log (a2); a3 (); console .log (this ); console .log (arguments ); var a2 = 3 ; function a3 ( ) { console .log ('a3()' ); } } fn (2 , 3 );
执行上下文栈 在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
在全局执行上下文(window)确定后,将其添加到栈中(压栈)
在函数执行上下文创建后,将其添加到栈中(压栈)
在当前函数执行后,将栈顶的对象移除(出栈)
当所有代码执行完成后,栈中只剩下window
1 2 3 4 5 6 7 8 9 10 var a = 10 ;var bar = function (x ) { var b = ; foo (x + b); } var foo = function (y ) { var c = 5 ; console .log (a + c + y); } bar (10 )
例题 1、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 console .log ('global begin:' + i);var i = 1 ;foo (1 );function foo (i ) { if (i == 4 ) { return ; } console .log ('foo() begin:' + i); foo (i + 1 ); console .log ('foo() end:' + i); } console .log ('global end:' + i);
2、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function a ( ) {}var a;console .log (typeof a); if (!(b in window )) { var b = 1 ; } console .log (b); if (false ) { var b = 1 ; } console .log (b in window ); var c = 1 ;function c (c ) { console .log (c); } c (2 ); var c;function c (c ) { console .log (c); } c = 1 ; c (2 );
三、作用域与作用域链 作用域 理解 作用域就是一块“地盘”,一个代码短所在区域
它是静态的(相对于上下文对象),在编写代码时就确定了
分类 全局作用域
函数作用域
没有块作用域(ES6有)
作用 隔离变量,不同作用域下同名变量不会冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 if (true ) { var a = 4 ; } var a = 10 , b = 20 ; function fn (x ) { var a =100 , c = 300 ; console .log ('fn()' , a, b, c, x); function bar (x ) { var a = 1000 , d = 400 ; console .log ('bar()' , a, b, c, d, x); } bar (100 ); bar (200 ); } fn (10 );
作用域与全局上下文 区别 1、
全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
全局执行上下文环境时在全局作用域确定之后,js代码马上执行之前创建
函数执行上下文环境时在调用函数时,函数体代码执行之前创建
2、
作用域时静态的,只要函数定义好了就一直存在,且不会再变化
执行上下文环境时动态的,调用函数时创建,函数调用结束时上下文环境就会自动释放
3、
执行上下文环境(对象)时从属于所在的作用域
全局上下文环境==>全局作用域
函数上下文环境==>对应函数作用域
作用域链 理解 多个上下级关系的作用域形成的链,他的方向是从下向上的(从内到外)
查找变量时就是沿着作用域链来查找的
查找一个变量的查找规则 在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则进入2
在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入3
再次执行2的相同操作,直到全局作用域,如果还找不到就抛出找不到的异常(xxx is not defined)
1 2 3 4 5 6 7 8 9 10 11 12 13 var a = 1 ;function fn1 ( ) { var b = 2 ; function fn2 ( ) { var c = 3 ; console .log (c); console .log (b); console .log (a); console .log (d); } fn2 (); } fn1 ();
四、闭包 例子:实现按钮循环监听事件,点击相应按钮弹出点击的是第几个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <body > <button > 测试1</button > <button > 测试2</button > <button > 测试3</button > <script type ="text/javascript" > var btns = document .getElementsByTagName ('button' ); for (var i = 0 ,lengths = btns.length ; i < lengths; i++) { (function (i ) { var btn = btns[i]; btn.onclick = function ( ) { alert ('第' + (this .index + 1 ) + '个' ); } })(i); } </script > </body >
理解 如何产生闭包? 当一个嵌套的内部(子)函数引用了嵌套外部(父)函数的变量(函数)时,就产生了闭包
闭包到底是什么? 闭包是嵌套的内部函数包含被引用外部变量(函数)的对象
产生闭包的条件? 函数嵌套,内部函数引用了外部函数的数据(变量/函数)
如上图所示,可通过chrome调试模式查看Closure(闭包),当执内部行函数定义(并不是调用函数)时就产生了闭包。执行内部函数定义需要先调用外部函数,并不需要调用内部函数。
常见的闭包 1、将函数作为另一个函数的返回值
1 2 3 4 5 6 7 8 9 10 11 function fn1 ( ) { var a= 2 ; function fn2 ( ) { a++; console .log (a); } return fn2; } var f = fn1 (); f (); f ();
2、将函数作为实参传递给另一个函数调用
1 2 3 4 5 6 function fn (msg, time ) { setTimeout (function ( ) { alert (msg); }, time); } fn ('msg' , 2000 );
闭包的作用 使用函数内部的变量在函数执行后,仍然存活在内存中(延长了局部变量的声明周期)
让函数外部可以操作(读写)到函数内部的数据(变量/函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function fn1 ( ) { var a = 2 ; function fn2 ( ) { a++; console .log (a); } function fn3 ( ) { a--; console .log (a); } return fn3; } var f = fn1 (); f ();
问题 1、函数执行之后,函数内部声明的局部变量是否还存在?
一般时不存在。存在于闭包中的变量才可能会存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function fn1 ( ) { var a = 2 ; function fn2 ( ) { a++; console .log (a); } function fn3 ( ) { a--; console .log (a); } return fn3; } var f = fn1 (); f ();
2、在函数外部能直接访问函数内部的局部变量吗?
不能,但是我们可以通过闭包让外部间接操作它。例如上面代码所示。
闭包的生命周期 1、产生:在嵌套内部函数定义执行完时就产生了(不是调用)
2、死亡:在嵌套的内部函数成为垃圾对象时
1 2 3 4 5 6 7 8 9 10 11 12 13 function fn1 ( ) { var a = 2 ; function fn2 ( ) { a++; console .log (a); } return fn2; } var f = fn1 ();f ();f ();f = null ;
闭包的应用:定义JS模块 JS模块:
具有特定功能的js文件
将所有的数据和功能都封装在一个函数内部(私有的)
只向外暴露一个包含n个方法的对象或函数
模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function myModule ( ) { var msg = 'My Module' ; function doSomethiing ( ) { console .log ('doSomething()' , msg.toUpperCase ()); } function doOtherthing ( ) { console .log ('doOtherthing()' , msg.toLowerCase ()); } return { doSomethiing : doSomethiing, doOtherthing : doOtherthing } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!doctype html > <html class ="no-js" lang ="" > <head > <meta charset ="utf-8" > <title > </title > </head > <body > </body > <script type ="text/javascript" src ="js/myModule.js" > </script > <script type ="text/javascript" > var module = myModule (); module .doSomethiing (); module .doOtherthing (); </script > </html >
另一种,将要暴露的内容赋给window。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (function myModule2 ( ) { var msg = 'My Module' ; function doSomethiing ( ) { console .log ('doSomething()' , msg.toUpperCase ()); } function doOtherthing ( ) { console .log ('doOtherthing()' , msg.toLowerCase ()); } window .myModule2 = { doSomethiing : doSomethiing, doOtherthing : doOtherthing } })();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!doctype html > <html class ="no-js" lang ="" > <head > <meta charset ="utf-8" > <title > </title > </head > <body > </body > <script type ="text/javascript" src ="js/myModule2.js" > </script > <script type ="text/javascript" > myModule2.doSomethiing(); myModule2.doOtherthing(); </script > </html >
闭包的缺点 1、缺点
函数执行之后,函数内的局部变量没有释放,占用内存时间会变长
容易造成内存泄露
2、解决
能不用闭包就不用
及时释放
1 2 3 4 5 6 7 8 9 10 11 12 <script type ="text/javascript" > function fn1 ( ) { var arr = new Array [10000000 ]; function fn2 ( ) { console .log (arr.length ); } return fn2; } var f = fn1 (); f (); f = null ; </script >
补充 内存溢出 一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就会抛出内存溢出的错误
内存泄露 占用的内存没有及时释放
内存泄露累计多了就容易导致内存溢出
常见的内存泄露:
意外的全局变量
没有及时清理的计时器或回调函数
闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function fn ( ) { a = new Array (100000000 ); } fn ();var intervalId = setInterval (function ( ) { console .log ('------------' ); }, 1000 ); function fn1 ( ) { var a = 4 ; function fn2 ( ) { console .log ('---' , a); } return fn2; } var f = fn1 ();f ();
五、面向对象高级 对象创建模式 方式1:Object构造函数模式 套路:先创建空Object对象,再动态添加属性/方法
适用场景:起始时不确定对象内部数据
问题:语句太多
1 2 3 4 5 6 7 8 9 var p = new Object ();p.name = 'Tom' ; p.age = 12 ; p.setName = function (name ) { this .name = name; } p.setName ('JACK' ); console .log (p.name , p.age );
方式2:对象字面量模式 套路:使用 {} 创建对象,同时指定属性/方法
适用场景:起始时对象内部数据是确定的
问题:如果创建多个对象,有重复代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var p = { name : 'Tom' , age : 12 , setName : function (name ) { this .name = name; } } console .log (p.name , p.age );p.setName ('JACK' ); console .log (p.name , p.age );var p2 = { name : 'Bob' , age : 13 , setName : function (name ) { this .name = name; } }
方式3:工厂模式 套路:通过工厂函数动态创建对象并返回
适用场景:需要创建多个对象
问题:对象没有一个具体类型,都是Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function createPerson (name, age ) { var obj = { name : name, age : age, setName : function (name ) { this .name = name; } } return obj; } var p1 = createPerson ('Tom' , 12 );var p2 = createPerson ('Bob' , 13 );function createStudent (name, price ) { var obj = { name : name, price : price } return obj; } var s = createStudent ('张三' , 12000 );
方法4:自定义构造函数模式 套路:自定义构造函数,通过new创建对象
适用场景:需要创建多个类型确定的对象
问题:每个对象都有相同的数据,浪费内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function Person (name, age ) { this .name = name; this .age = age; this .setName = function (name ) { this .name = name; } } var p1 = new Person ('Tom' , 13 );p1.setName ('Jack' ); console .log (p1.name , p1.age );console .log (p1 instanceof Person );function Studen (name, price ) { this .name = name; this .price = price; this .setName = function (name ) { this .name = name; } } var s1 = new Studen ('KC' , 1200 );s1.setName ('KAKA' ); console .log (s1.name , s1.price );console .log (s2 instanceof Studen );
方式5:构造函数+原型的组合模式 套路:自定义构造函数,属性在函数中初始化,方法添加到原型上
适用场景:需要创建多个类型确定的对象
1 2 3 4 5 6 7 8 9 10 11 function Person (name, age ) { this .name = name; this .age = age; } Person .prototype .setName = function (name ) { this .name = name; } var p1 = new Person ('Tom' , 12 );var p2 = new Person ('Bob' , 13 );p1.setName ('JACK' );
原型链继承 套路:
定义父类型构造函数
给父类型的原型添加方法
定义子类型的构造函数
创建父类型的对象赋值给子类型的原型
将子类型原型的构造函数属性设置位子类型
给子类型原型添加方法
创建子类型的对象:可以调用父类型的方法
关键:
子类型的原型为父类型的一个实例对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function Supper ( ) { this .supProp = 'Supper property' ; } Supper .prototype .showSupperProp = function ( ) { console .log (this .supProp ); } function Sub ( ) { this .subProp = 'Sub property' ; } Sub .prototype = new Supper ();Sub .prototype .showSubProp = function ( ) { console .log (this .subProp ); } var sub - new Sub ();sub.showSupperProp (); sub.showSubProp ();
借用构造函数继承(假) 套路:
定义父类型构造函数
定义子类型构造函数
在子类型构造函数中调用父类型构造
关键:
在子类型构造函数中调用call() 调用父类型构造函数
1 2 3 4 5 6 7 8 9 10 11 function Person (name, age ) { this .name = name; this .age = age; } function Student (name, age, price ) { Person .call (this , name, age); this .price = price; } var s = new Student ('Tom' , 20 , 10000 );console .log (s.name , s.age , s.price );
*组合继承 原型链+借用构造函数的组合继承
利用原型链实现对父类型对象的方法继承
利用supper()借用父类型构建函数初始化相同属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function Person (name, age ) { this .name = name; this .age = age; } Person .prototype .setName = function (name ) { this .name = name; } function Student (name, age, price ) { Person .call (this , name, age); this .price = price; } Student .prototype = new Person (); Student .prototype .constructor = Student ; Student .prototype .setPrice = function (price ) { this .price = price; } var s = new Student ('Tom' , 24 , 15000 );s.setName ('Bob' ); s.setPrice (11100 ); console .log (s.name , s.age , s.price );
六、线程机制与事件机制 进程与线程 进程(process) 程序的一次执行,它占有一片独有的内存空间
可以通过window任务管理器查看进程
线程(thread) 线程是进程内的一个独立执行单元
是程序执行的一个完整流程
是CPU的最小的调度单元
相关知识 应用程序不许运行在某个进程的某个线程上
一个进程中至少有一个运行的线程:主线程,进程启动后自动创建
一个进程中可以同时运行多个线程,我们会说程序是多线程运行的
一个进程内的数据可以供其中的多个线程直接共享
多个进程之间的数据是不能直接共享的
线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
相关问题 何为多进程与多线程?
多进程运行:一个应用程序可以同时启动多个实例运行
多线程:一个进程内,同时多个线程运行
单线程与多线程
多线程:
优点:
能有效提升CPU的利用率
缺点:
创建多线程开销
线程间切换开销
死锁与状态同步问题
单线程:
优点:顺序编程简单易懂
缺点:运行效率低下
JS是单线程还是多线程?
JS是单线程运行的
但是通过H5中的Web Wokers可以多线程运行
浏览器运行时多线程还是单线程?
多线程
浏览器运行时单进程还是多进程?
有的时单进程:
firefox、老版本IE
有的时多进程:
chrome、新版IE
可以通过程序运行时查看window的任务管理器判断是多进程还是单进程
浏览器内核 浏览器内核是支撑浏览器运行的最核心程序
不同的浏览器可能不一样,例如chrome、Safrai使用webkit,firefox使用Gecko,IE使用Trident,360、搜狗等国内浏览器使用Trident+webkit
内核由很多模块组成:
主线程:
js引擎模块:负责js程序的编译与运行
html、css文档解析模块:负责页面文本的解析
DOM/CSS模块:负责dom/css在内存中的相关处理
布局和渲染模块:负责页面的布局和效果的绘制(内存中的对象)
分线程:
定时器模块:负责定时器的管理
DOM事件响应模块:负责事件的管理
网络请求模块:负责ajax请求
其它模块:……
定时器引发的思考 定时器真的是定时执行吗?
定时器并不能保证真正定时执行
一般会延迟一丁点(可接受范围内),但是也可能延迟很长事件(不可接受范围)
定时器回调函数是在分线程执行的吗?
在主线程执行的,js是单线程的
定时器是如何实现的?
事件循环模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <button id ='btn' > 启动定时器 </button > <script type ="text/javascript" > document .getElementById ('btn' ).onclick = function ( ) { var start = Date .now (); console .log ('启动定时器前...' ) setTimeout (function ( ) { console .log ('定时器执行了' , Date .now () - start); }, 200 ); console .log ('启动定时器后...' ) for (var i = 0 ; i < 1000000 ; i++) { } } </script >
JS是单线程的 1、如何证明js执行是单线程的?
setTimeout()的回调函数是在主线程执行的
定时器回到函数只有在运行栈中的代码全部执行完后才有可能执行
2、为什么js要用单线程模式,而不是多线程模式?
JavaScript的单线程,与它的用途有关
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以操作DOM
这决定了它只能是单线程,否则会带来复杂的同步问题
3、代码的分类
初始化代码
回调代码
4、js引擎执行代码的基本流程
先执行初始化代码:包含一些特别的代码 回调函数(异步执行)
设置定时器
绑定事件监听
发送ajax请求
后面在某个时刻才会执行回调代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 setTimeout (function ( ) { console .log ('timeout 2000' ) }, 2000 ); setTimeout (function ( ) { console .log ('timeout 1000' ); alert ('1000' ); }, 1000 ); setTimeout (function ( ) { console .log ('timeout 0' ); }, 0 ); function fn ( ) { console .log ('fn()' ); } fn ();console .log ('alert()之前' );alert ('--------' ); console .log ('alert()之后' );
事件循环模型 1、所有代码分类
初始化执行代码(同步代码):包含绑定dom事件监听,设置定时器,发送ajax请求的代码
回调执行代码(异步代码):处理回调逻辑
2、js引擎执行代码的基本流程:
初始化代码===>回调代码
3、模型的两个重要组成部分:
事件(定时器/DOM事件/Ajax)管理模块
回调队列
4、模型的运转流程
执行初始化代码,将事件回调函数交给对应模块管理
当事件发送时,管理模块会将函数及其数据添加到回调队列中
只有当初始化代码执行完后(可能要一定时间),才会遍历读取回调队列中的回调函数执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <button id ='btn' > 测试 </button > <script type ="text/javascript" > function fn1 ( ) { console .log ('fn1()' ); } fn1 (); document .getElementById ('btn' ).onclick = function ( ) { console .log ('点击了btn' ); } setTimeout (function ( ) { console .log ('定时器执行了' ); }, 2000 ); function fn2 ( ) { console .log ('fn2()' ); } fn2 (); </script >
Web Workers H5规范提供了js分线程的实现,取名为:Web Workers
相关API:
Worker:构造函数,加载分线程执行的js文件
Worker.prototype.onmessage:用于接收另一个线程的回调函数
Worker.prototype.postMessage:向另一个线程发送消息
不足:
Worker内代码不能操作DOM(更新UI)
不能跨域加载JS
不是每个浏览器都支持这个新特性
Web Workers实际应用: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <input type ="text" placeholder ="数值" id ="number" /> <button id ='btn' > 计算 </button > <script type ="text/javascript" > function fibonacci (n ) { return n <= 2 ? 1 :fibonacci (n-1 ) + fibonacci (n-2 ); } var input = document .getElementById ('number' ); document .getElementById ('btn' ).onclick = function ( ) { var number = input.value ; var result = fibonacci (number); alert (result); } </script >
使用Web Workers解决方案如下:(需要在容器中启动才能通过测试)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <input type ="text" placeholder ="数值" id ="number" /> <button id ='btn' > 计算 </button > <script type ="text/javascript" > var input = document .getElementById ('number' ); document .getElementById ('btn' ).onclick = function ( ) { var number = input.value ; var worker = new Worker ('myWorker.js' ); worker.postMessage (number); worker.onmessage = function (event ) { console .log ('主线程接收封线程返回的数据' , event.data ); alert (event.data ); } } </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function fibonacci (n ) { return n <= 2 ? 1 : fibonacci (n-1 ) + fibonacci (n-2 ); } var onmessage = function (event ) { var number = event.data ; console .log ('分线程接收到主线程发送的数据:' , number); var result = fibonacci (number); postMessage (result); }
workers不足: 1、速度慢 2、不能跨域加载js 3、不是每个浏览器都支持这个新特性 4、worker内代码不能访问DOM(更新