javaScript高级
js高级
[Toc]
一、基础总结深入
1、数据类型1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_数据类型</title>
</head>
<body>
<!--
1. 分类
基本(值)类型
-String:任意字符串
-Number:任意数字
-boolean:true false
-undefined:undefined
-null:null
对象(引用)类型
-Object:任意对象
-Fucition:一种特别的对象(可以执行)
-Array:一种特别的对象(数值下标,内部数据是有序的)
2. 判断
1、typeof
-可以判断undefined,数值,字符串,布尔值,function
-不能判断null和Object,Object和array
2、instanceof
-判断对象的具体类型
3、===
-可以判断undefined,null
-->
<script type="text/javascript"> // 1、基本
var a;
console.log(a,typeof a,typeof a==='undefined',a===undefined);//undefined 'undefined' true true
console.log(undefined==='undefined');//false
a=3;
console.log(typeof a==='number' );//true
a='xiaolin';
console.log(typeof a==='string');//true
a=true;
console.log(typeof a==='boolean');//true
a=null;
console.log(typeof a,a===null);//object,true
console.log('=====================');
var b1={
b2:[1,"abc",console.log],
b3:function(){
console.log('b3');
return function(){
return 'xiaolin';
}
}
};
console.log(b1 instanceof Object,b1 instanceof Array);//true false
console.log(b1.b2 instanceof Array,b1.b2 instanceof Object);//true true
console.log(b1.b3 instanceof Function,b1.b3 instanceof Object);//true true
console.log(typeof b1.b2);//object
console.log(typeof b1.b3,typeof b1.b3==='function');// 'fucction' true
console.log(typeof b1.b2[2]==='function');//true
b1.b2[2](4);//4
console.log(b1.b3()());//xiaolin
b1.b3();//b3
/* var obj = {
name:"Tom",
age:18
};
function test(){
var a=3;
}
var arr=[3,"abc"]; */
// alert(arr[1]); </script>
</body>
</html>
2、数据类型2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_相关问题</title>
</head>
<body>
<!--
1. undefined与null的区别?
-undefined代表定义了未赋值
-null代表定义并赋值了,只是值为null
2. 什么时候给变量赋值为null呢?
-初始赋值,表明将要赋值为对象
-结束前赋值为null,让其成为垃圾对象(被垃圾回收器回收)
3. 严格区别变量类型与数据类型?
-数据的类型
1、基本类型
2、对象类型
-变量的类型(变量内存值的类型)
-基本类型:保存的就是基本类型的数据
-引用类型:保存的是地址值
-->
<script type="text/javascript"> //实例:实例对象
// 类型:类型对象
function Person(name,age){ //构造函数 类型
this.name=name;
this.age=age;
}
var p = new Person('tom',18);//根据类型创建的实例对象
// Person('jack',12);//合法但不合理
//1. undefined与null的区别?
var a;
console.log(a);//undefined
a=null;
console.log(a);//null
var b=null;//初始赋值为null,表明将要赋值为对象
//确定对象就赋值
b = ['xiaolin',18];
// 最后
b=null;//切断指向对象的线,后会成为垃圾对象被回收期自动回收
// b=2;
var c=function(){
};
console.log(typeof c);//'function' </script>
</body>
</html>
3、数据、变量和内存1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_数据_变量_内存</title>
</head>
<body>
<!--
1. 什么是数据?
-存储在内存中代表特定信息的东西,本质上是0101...
-数据的特点:可传递,可运算
-一切皆数据
-内存中所有操作的目标:数据
-算数运算
-逻辑运算
-赋值运算
-运行函数
2. 什么是内存?
-内存条通电以后产生的可存储数据的空间(临时的)
-内存产生和死亡:内存条(电路板)==>通电==>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失
-一块小内存的2个数据
-内存存储的数据
-地址值
-内存分类
-栈内存:全局变量和局部变量
-堆内存:对象
3. 什么是变量?
-可变化的量,由变量名和变量值组成
-每个变量都对应一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据
4. 内存,数据, 变量三者之间的关系
-内存是用来存储数据的空间
-变量是内存的标识
-->
<script type="text/javascript"> var age=18;
var a =2;
var obj = {
name:'tom'
};
console.log(obj.name);
function fn(){
var obj ={name:'tom'};
}
var a =3;
var b=a+2; </script>
</body>
</html>
4、数据、变量和内存2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>关于赋值和内存的问题</title>
</head>
<body>
<!--
问题: var a = xxx, a内存中到底保存的是什么?
xxx是基本数据,保存的就是这个基本数据
xxx是对象,保存的就是对象的地址值
xxx是变量,保存的xxx的内存内容(可能是基本数据,也可能是地址值)
-->
<script type="text/javascript"> var a = 3;
var a =function(){
};
var b="abc";
a=b;
b={}
a=b </script>
</body>
</html>
5、数据、变量和内存3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_关于引用变量赋值问题</title>
</head>
<body>
<!--
关于引用变量赋值问题
多个引用变量指向同一个对象,通过其中一个变量修改对象内部数据
其他所有变量看到的是修改之后的数据
两个引用变量指向同一个对象,现在让其中一个引用变量指向另一个对象,另一个引用
变量仍然指向原来的对象,此时两个引用变量互不相关
-->
<script type="text/javascript"> var obj1={name:'tom'};
var obj2=obj1;
obj1.name='jack';
console.log(obj2.name);//'jack'
function fun(obj){
obj.name='bob';
}
fun(obj1);
console.log(obj2.name);//bob
var a = {age:12};
var b = a;
a = {name:'bob',age:13};//a断开原来的连接,指向新创建的一个对象了
console.log(b);//指向原来a指向的对象
b.age=14;
console.log(b.age,a.name,a.age);//14 bob 13
function fun2(obj){
obj = {age:15};
}
fun2(a);
console.log(a.age);//13 </script>
</body>
</html>
6、数据变量和内存4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_关于数据传递问题</title>
</head>
<body>
<!--
问题: 在js调用函数时传递变量参数时, 是值传递还是引用传递
理解1:都是值(基本数据/地址值)传递
理解2:可能是值传递,也可能是引用传递(地址值)
-->
<script type="text/javascript"> var a=3;
function fn(a){
a=a+1;
}
fn(a);
console.log(a);//3
function fn2(obj){
console.log(obj.name);
}
var obj={name:'tom'};
fn2(obj); </script>
</body>
</html>
7、数据、变量和内存5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_内存管理</title>
</head>
<body>
<!--
问题: JS引擎如何管理内存?
1. 内存生命周期
-分配小内存空间,得到它的使用权
-存储数据,可以反复进行操作
-释放当前的小内存空间
2. 释放内存
-局部变量:函数执行完自动释放
-对象:成为垃圾对象==>垃圾回收器自动回收
-->
<script type="text/javascript"> var a=3;
var obj = {};
obj=null;
function fn(){
var b ={};
}
fn();//执行完,b自动释放,b所指向的对象是在后面的某个时刻由垃圾回收器回收的 </script>
</body>
</html>
8、对象1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_对象</title>
</head>
<body>
<!--
1. 什么是对象?
-多个数据的封装体
-用来保存多个数据的容器
-一个对象代表现实中的一个事物
2. 为什么要用对象?
-统一管理多个数据
3. 对象的组成
-属性:属性名(字符串)和属性值(任意类型)组成
-方法:一种特别的属性(属性值是函数)
4. 如何访问对象内部数据?
-对象.属性名:编码简单,有时不能用
-对象['属性名']:编码麻烦,但是里面可以放变量,通用
-->
<script type="text/javascript"> var tom = {
name:'tom',
age:18,
setName:function(name){
this.name=name;
},
setAge:function(age){
this.age=age;
}
};
/* var name='tom';
var age = 18; */
tom.setName('bob');
tom['setAge'](23);
console.log(tom.name,tom['age']); </script>
</body>
</html>
9、对象2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_相关问题</title>
</head>
<body>
<!--
问题: 什么时候必须使用['属性名']的方式?
1、属性名包含特殊字符: - 空格
2、属性名不确定
-->
<script type="text/javascript"> var p ={};
// 1、给p对象添加一个属性:content-type:text/json
// p.content-type:'text/json';
p['content-type']='text/json';
console.log(p['content-type']);
// 2、属性名不确定
var propName = 'myAge';
var value = 18;
// p.propName = value;//这样存储的属性名是propName
// console.log(p);
p[propName]=value;
console.log(p[propName]);//18 </script>
</body>
</html>
10、函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_函数</title>
</head>
<body>
<!--
1. 什么是函数?
-实现特定功能的n条语句的封装体
-只有函数是可以执行的,其他类型的数据不能执行
2. 为什么要用函数?
-提高代码复用
-便于阅读交流
3. 如何定义函数?
-函数声明
-表达式
4. 如何调用(执行)函数?
-test():直接调用
-obj.test():通过对象调用
-new test():new调用
-test.call/apply(obj);//临时让test成为obj的方法被调用
-->
<script type="text/javascript"> /*
编写程序实现以下功能需求:
1. 根据年龄输出对应的信息
2. 如果小于18, 输出: 未成年, 再等等!
3. 如果大于60, 输出: 算了吧!
4. 其它, 输出: 刚好!
*/
function showInfo(age){
if(age<18){
console.log("未成年,再等等!");
}else if(age>60){
console.log("算了吧");
}else{
console.log('刚好');
}
}
showInfo(17);
showInfo(20);
showInfo(65);
function fn1(){//函数声明
console.log('fn1()');
}
var fn2 = function(){ //表达式
console.log('fn2()');
}
fn1();
fn2();
var obj={};
function test2(){
this.name ='xiaolin';
}
test2.call(obj);//obj.test2();//可以让一个函数成为指定任意对象的方法进行调用
console.log(obj.name);//xiaolin </script>
</body>
</html>
11、回调函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_回调函数</title>
</head>
<body>
<button id="btn">测试点击事件</button>
<!--
1. 什么函数才是回调函数?
-你定义的
-你没有调用
-但最终它执行了(在特殊条件或时刻)
2. 常见的回调函数?
-dom事件回调函数
-定时器回调函数
-ajax请求回调函数
生命周期回调函数
-->
<script type="text/javascript"> var btn=document.getElementById("btn");
btn.onclick=function(){//dom事件回调函数
alert(this.innerHTML);
}
// 定时器
// 超时定时器
// 循环定时器
setTimeout(function(){//定时器回调函数
alert('到点了');
},2000); </script>
</body>
</html>
12、IFFE立即执行函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_IIFE</title>
</head>
<body>
<!--
1. 理解
* 全称: Immediately-Invoked Function Expression
立即执行函数
2. 作用
-隐藏实现
-不会污染外部(全局)命名空间
-用它来编写js模块
-->
<script type="text/javascript"> (function (){ //匿名函数自调用
// console.log('......');
var a =3;
console.log(a+3);
})();
var a =4;
console.log(a);
(function (){
var a=1;
function test(){
console.log(++a);
}
function test2(){
console.log('test2');
}
window.$=function(){ //向外暴漏一个函数
return {
test:test
}
}
})();
console.log(typeof $()==='function');
$().test();//1、$是一个函数,2、$执行后返回的是一个对象 </script>
</body>
</html>
13、函数中的this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>07_函数中的this</title>
</head>
<body>
<!--
1. this是什么?
* 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
* 所有函数内部都有一个变量this
* 它的值是调用函数的当前对象
2. 如何确定this的值?
* test(): window
* p.test(): p
* new test(): 新创建的对象
* p.call(obj): obj
-->
<script type="text/javascript"> function Person(color) {
console.log(this);
this.color = color;
this.getColor = function () {
console.log(this);
return this.color;
};
this.setColor = function (color) {
console.log(this);
this.color = color;
};
}
Person("red"); //this是谁? window
var p = new Person("yellow"); //this是谁? p
p.getColor(); //this是谁? p
var obj = {};
p.setColor.call(obj, "black"); //this是谁? obj
var test = p.setColor;
test(); //this是谁? window
function fun1() {
function fun2() {
console.log(this);
}
fun2(); //this是谁? window
}
fun1(); </script>
</body>
</html>
14、分号问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_分号问题</title>
</head>
<body>
<!--
1. js一条语句的后面可以不加分号
2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢
3. 在下面2种情况下不加分号会有问题
* 小括号开头的前一条语句
* 中方括号开头的前一条语句
4. 解决办法: 在行首加分号
5. 强有力的例子: vue.js库
6. 知乎热议: https://www.zhihu.com/question/20298345
-->
<script type="text/javascript"> var a = 3
;(function () {
})()
/*
错误理解
var a = 3(function () {
})();
*/
var b = 4
;[1, 3].forEach(function () {
})
/*
错误理解
var b = 4[3].forEach(function () {
})
*/ </script>
</body>
</html>
二、函数高级
1、原型与原型链
1、原型--prototype
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_原型(prototype)</title>
</head>
<body>
<!--
1. 函数的prototype属性(图)
* 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
* 原型对象中有一个属性constructor, 它指向函数对象
2. 给原型对象添加属性(一般都是方法)
* 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
-->
<script type="text/javascript"> console.log(Date.prototype,typeof Date.prototype);//Object
function Fun(){
}
console.log(Fun.prototype);//默认指向一个object空对象(没有我们的属性)
//原型对象中有一个属性constructor, 它指向函数对象
console.log(Date.prototype.construtor===Date);//true
console.log(Fun.prototype.construtor===Fun);//true
// 给原型对象添加了属性(一般是属性)==>实例对象可以访问
Fun.prototype.test=function(){
console.log('test()');
}
var fun = new Fun();
fun.test(); </script>
</body>
</html>
2、显示原型和隐式原型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_显式原型与隐式原型</title>
</head>
<body>
<!--
1. 每个函数function都有一个prototype,即显式原型
2. 每个实例对象都有一个__proto__,可称为隐式原型
3. 对象的隐式原型的值为其对应构造函数的显式原型的值
4. 内存结构(图)
5. 总结:
* 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
* 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
* 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
-->
<script type="text/javascript"> // 定义构造函数
function Fn(){ //内部语句:this.prototype={}
}
//1. 每个函数function都有一个prototype,即显式原型属性,,默认指向一个空的object对象
console.log(Fn.prototype);
//2. 每个实例对象都有一个__proto__,可称为隐式原型
//创建实例对象
var fn = new Fn();//内部语句:fn.__proto__ = Fn.prototype;
console.log(fn.__proto__);
//3. 对象的隐式原型的值为其对应构造函数的显式原型的值
console.log(Fn.prototype===fn.__proto__);//true
//给原型添加方法
Fn.prototype.test=function(){
console.log('test()');
};
//通过实例调用原型的方法
fn.test(); </script>
</body>
</html>
3、原型链
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_原型链</title>
</head>
<body>
<!--
1. 原型链(图解)
* 访问一个对象的属性时,
* 先在自身属性中查找,找到返回
* 如果没有, 再沿着__proto__这条链向上查找, 找到返回
* 如果最终没找到, 返回undefined
* 别名: 隐式原型链
* 作用: 查找对象的属性(方法)
2. 构造函数/原型/实体对象的关系(图解)
3. 构造函数/原型/实体对象的关系2(图解)
-->
<script type="text/javascript"> // console.log(Object);
// console.log(Object.prototype);
console.log(Object.prototype.__proto__);//null
function Fn(){
this.test1=function(){
console.log('test1()');
}
}
console.log(Fn.prototype);
Fn.prototype.test2=function(){
console.log('test2()');
}
// console.log(Fn.prototype);
var fn=new Fn();
fn.test1();
fn.test2();
console.log(fn.toString());
console.log(fn.test3);//undefined
fn.test3();
/*
1、函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
*/
console.log(Fn.prototype instanceof Object);//true
console.log(Object.prototype instanceof Object);//false
console.log(Function.prototype instanceof Object);//true
/*
2、所有函数都是Function的实例(包括它本身)
*/
console.log(Function.__proto__===Function.prototype);
/*
3、Object的原型对象是原型链的尽头
*/
console.log(Object.prototype.__proto__);//null </script>
</body>
</html>
4、原型链--属性问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_原型链_属性问题</title>
</head>
<body>
<!--
1. 读取对象的属性值时: 会自动到原型链中查找
2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
-->
<script type="text/javascript"> function Fn(){
}
Fn.prototype.a ="xxx";
var fn1=new Fn();
console.log(fn1.a,fn1);
var fn2=new Fn();
fn2.a='yyy';//在fn2自身定义了一个属性
console.log(fn1.a);//xxx
console.log(fn2.a,fn2);//yyy
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.setName=function(name){
this.name=name;
}
var p1 = new Person('tom',12);
p1.setName('bob');
console.log(p1);
var p2 = new Person('jack',12);
p1.setName('lili');
console.log(p2); </script>
</body>
</html>
5、探索instanceof
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_探索instanceof</title>
</head>
<body>
<!--
1. instanceof是如何判断的?
* 表达式: A instanceof B
* 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
2. Function是通过new自己产生的实例
-->
<script type="text/javascript"> /*
案例1
*/
function Foo(){
}
var f1=new Foo();
console.log(f1 instanceof Foo);//true
console.log(f1 instanceof Object);//true
/*
案例2
*/
console.log(Object instanceof Function);//true
console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Function instanceof Object);//true
function Foo(){}
console.log(Object instanceof Foo);//false </script>
</body>
</html>
6、面试题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_面试题</title>
</head>
<body>
<script type="text/javascript"> /*
测试题1
*/
var A = function() {
}
A.prototype.n = 1;
var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();
console.log(b.n, b.m, c.n, c.m);//1,undefined,2,3
/*
测试题2
*/
var F = function(){};
Object.prototype.a = function(){
console.log('a()');
};
Function.prototype.b = function(){
console.log('b()');
};
var f = new F();
f.a();//找到Object.prototype,输出a()
// f.b();//找不到,报错not a function
F.a();//找到Object.prototype,输出a()
F.b();//找到Function.prototype,输出b()
console.log(Object.prototype);
console.log(Function.prototype); </script>
</body>
</html>
2、执行上下文与执行上下文栈
1、变量提升与函数提升
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_变量提升与函数提升</title>
</head>
<body>
<!--
1. 变量声明提升
* 通过var定义(声明)的变量, 在定义语句之前就可以访问到
* 值: undefined
2. 函数声明提升
* 通过function声明的函数, 在之前就可以直接调用
* 值: 函数定义(对象)
3. 问题: 变量提升和函数提升是如何产生的?
-->
<script type="text/javascript"> /*
面试题:输出undefined
*/
var a=3;
function fn(){
console.log(a);
var a =4;
}
/*
上面函数等同于
*/
/* function fn(){
var a ;
console.log(a);
a=4;
} */
fn();//因为,局部变量提升,先声明了,所以不找全局变量的a,但此时未赋值,所以输出undefined
fn2();//可调用,函数提升
fn3();//不能调用,变量提升,认为fn3是变量,而不是一个函数,会报错
function fn2(){
console.log('fn2()');
}
var fn3 =function(){
console.log('fn3()');
} </script>
</body>
</html>
2、执行上下文
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_执行上下文</title>
</head>
<body>
<!--
1. 代码分类(位置)
* 全局代码
* 函数代码
2. 全局执行上下文
* 在执行全局代码前将window确定为全局执行上下文
* 对全局数据进行预处理
* var定义的全局变量==>undefined, 添加为window的属性
* function声明的全局函数==>赋值(fun), 添加为window的方法
* this==>赋值(window)
* 开始执行全局代码
3. 函数执行上下文
* 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的,存在于栈中)
* 对局部数据进行预处理
* 形参变量==>赋值(实参)==>添加为执行上下文的属性
* arguments==>赋值(实参列表), 添加为执行上下文的属性
* var定义的局部变量==>undefined, 添加为执行上下文的属性
* function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
* this==>赋值(调用函数的对象)
* 开始执行函数体代码
-->
<script type="text/javascript"> // 全局执行上下文
console.log(a1,window.a1);
a2();
console.log(this);
var a1=3;
function a2(){
console.log('a2()');
}
console.log(a1);
console.log("===========");
//函数执行上下文
function fn(a1){
console.log(a1);//2
console.log(a2);//undefined
a3();//a3()
console.log(this);//window
console.log(arguments);//伪数组(2,3)
var a2=3;
function a3(){
console.log('a3()');
}
}
fn(2,3); </script>
</body>
</html>
3、执行上下文栈
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_执行上下文栈</title>
</head>
<body>
<!--
1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后, 栈中只剩下window
-->
<script type="text/javascript"> var a=10;
var bar = function(x){
var b=5;
foo(x+b);
}
var foo=function(y){
var c=5;
console.log(a+c+y);
}
bar(10);//
bar(10); </script>
</body>
</html>
4、执行上下文栈2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_执行上下文栈2</title>
</head>
<body>
<!--
1. 依次输出什么?
gb:undefined
ge:1
fb:1
fb:2
fb:3
fe:3
fe:2
fe:1
2. 整个过程中产生了几个执行上下文?
5个
-->
<script type="text/javascript"> console.log('global begin:'+i);//undefined
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);//1 </script>
</body>
</html>
5、面试题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_面试题</title>
</head>
<body>
<script type="text/javascript"> /*
测试题1:先执行变量提升,再执行函数提升?
函数提升优先级高于变量提升,且不会被同名变量声明覆盖,但是会被变量赋值后覆盖。而且存在同名函数与同名变量时,优先执行函数。
*/
function a(){}
var a;
console.log(typeof a);//function
/*
测试题2
*/
if(!(b in window)){
var b=1;
}
console.log(b);//undefined
/*
测试题3
*/
var c=1;
function c(c){
console.log(c);
}
/* var c;
function c(c){
console.log(c);
}
c=1; */
c(2);//报错,not a function </script>
</body>
</html>
3、作用域和作用域链
1、作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_作用域</title>
</head>
<body>
<!--
1. 理解
* 就是一块"地盘", 一个代码段所在的区域
* 它是静态的(相对于上下文对象), 在编写代码时就确定了
2. 分类
* 全局作用域
* 函数作用域
* 没有块作用域(ES6有了)
3. 作用
* 隔离变量,不同作用域下同名变量不会有冲突
-->
<script type="text/javascript"> /*
//没有块作用域
if(true){
var c=3;
}
console.log(c); */
var a=10;
var b=20;
function fn(x){
var a=100;
var c=300;
console.log('fn()',a,b,c,x);
function bar(x){
var a=1000;
var d=400;
console.log('bar()',a,b,c,d,x);
}
bar(100);
bar(200);
}
fn(10); </script>
</body>
</html>
2、作用域与执行上下文
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_作用域与执行上下文</title>
</head>
<body>
<!--
1. 区别1
* 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
* 全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建
* 函数执行上下文环境是在调用函数时, 函数体代码执行之前创建
2. 区别2
* 作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
* 执行上下文环境是动态的, 调用函数时创建, 函数调用结束时上下文环境就会自动释放
3. 联系
* 执行上下文环境(对象)是从属于所在的作用域
* 全局上下文环境==>全局作用域
* 函数上下文环境==>对应的函数使用域
-->
<script type="text/javascript"> var a=10;
var b=20;
function fn(x){
var a=100;
var c=300;
console.log('fn()',a,b,c,x);
function bar(x){
var a=1000;
var d=400;
console.log('bar()',a,b,c,d,x);
}
bar(100);
bar(200);
}
fn(10); </script>
</body>
</html>
3、作用域链
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_作用域链</title>
</head>
<body>
<!--
1. 理解
* 多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
* 查找变量时就是沿着作用域链来查找的
2. 查找一个变量的查找规则
* 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
* 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
* 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
-->
<script type="text/javascript"> var a=1;
function fn1(){
var b=2;
function fn2(){
var c=3;
console.log(c);//3
console.log(b);//2
console.log(a);//1
console.log(d);//not defined
}
fn2();
}
fn1(); </script>
</body>
</html>
4、作用域面试题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_作用域_面试题</title>
</head>
<body>
<script type="text/javascript"> var x=10;
function fn(){
console.log(x);
}
function show(f){
var x=20;
f();
}
show(fn);//10 </script>
</body>
</html>
5、作用域面试题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_作用域_面试题2</title>
</head>
<body>
<script type="text/javascript"> var fn=function(){
console.log(fn);//现在函数自身里面找,找不到,再到全局作用域找,找到fn
};
fn();//fn=function(){console.log(fn);};
var obj={
fn2:function(){
// console.log(fn2);
console.log(this.fn2);
}
};
obj.fn2(); </script>
</body>
</html>
4、闭包
1、引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>00_引入</title>
</head>
<body>
<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求: 点击某个按钮, 提示"点击的是第n个按钮"
-->
<script type="text/javascript"> var btns=document.getElementsByTagName("button");
var length = btns.length;
// 遍历添加点击事件
/*
for(var i=0;i<length;i++){
var btn=btns[i];
btn.onclick=function(){
alert("点击的是第"+(i+1)+"个按钮!");//
}
} */
// console.log(i);//3
/* for(var i=0;i<length;i++){
var btn=btns[i];
// 将btn所对应的下标保存到index属性上
btn.index=i;
btn.onclick=function(){
alert("点击的是第"+(this.index+1)+"个按钮!");//
}
} */
// 利用了闭包
for(var i=0;i<length;i++){
(function (i){
var btn=btns[i];
btn.onclick=function(){
alert("第"+(i+1)+"个");
}
})(i)
} </script>
</body>
</html>
2、理解闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_理解闭包</title>
</head>
<body>
<!--
1. 如何产生闭包?
* 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
2. 闭包到底是什么?
* 使用chrome调试查看
* 理解一: 闭包是嵌套的内部函数(绝大部分人)
* 理解二: 包含被引用变量(函数)的对象(极少数人)
* 注意: 闭包存在于嵌套的内部函数中
3. 产生闭包的条件?
* 函数嵌套
* 内部函数引用了外部函数的数据(变量/函数)
-->
<script type="text/javascript"> function fn1(){
var a=2;
var b='abc';
function fn2(){//执行函数定义就好产生闭包(不用调用内部函数)
console.log(a);
}
fn2();
}
fn1(); </script>
</body>
</html>
3、常见的闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_常见的闭包</title>
</head>
<body>
<!--
1. 将函数作为另一个函数的返回值
2. 将函数作为实参传递给另一个函数调用
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
function fn1(){
var a=2;
function fn2(){
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f();//3
f();//4
// fn1();
//2、将函数作为实参传递给另一个函数调用
function showDelay(msg,time){
setTimeout(function(){
alert(msg);
},time);
}
showDelay('xiaolin',2000); </script>
</body>
</html>
4、闭包的作用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_闭包的作用</title>
</head>
<body>
<!--
1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
问题:
1. 函数执行完后, 函数内部声明的局部变量是否还存在? 一般是不存在了,存在于闭包中的变量才可能存在
2. 在函数外部能直接访问函数内部的局部变量吗? 不能,但是我们可以通过闭包让外部操作它
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
function fn1(){
var a=2;
function fn2(){
a++;
console.log(a);
}
function fn3(){
a--;
console.log(a);
}
return fn3;
}
var f = fn1();
f();//1
f();//0 </script>
</body>
</html>
5、闭包的生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_闭包的生命周期</title>
</head>
<body>
<!--
1. 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
2. 死亡: 在嵌套的内部函数成为垃圾对象时
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
function fn1(){
// 此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
var a=2;
function fn2(){
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f();//3
f();//4
f=null;//让闭包死亡(包含闭包的函数对象成为了垃圾对象) </script>
</body>
</html>
6、闭包的应用---自定义js模块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_闭包的应用_自定义JS模块</title>
</head>
<body>
<!--
闭包的应用2 : 定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包信n个方法的对象或函数
* 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javaScript" src="myModule.js"></script>
<script> var module = myModule();
module.doSomething();//doSomething() MY JAVASCRIPT
module.doOtherthing();//doOtherthing() my javascript </script>
</body>
</html>
myModule.js
function myModule(){
// 私有数据
var msg="my JavaScript";
// 操作数据的函数
function doSomething(){
console.log('doSomething() '+msg.toUpperCase());
}
function doOtherthing(){
console.log('doOtherthing() '+msg.toLowerCase());
}
// 向外暴露对象(给外部使用的方法)
return {
doSomething:doSomething,
doOtherthing:doOtherthing
};
}
7、闭包的应用---自定义js模块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_闭包的应用_自定义JS模块2</title>
</head>
<body>
<!--
闭包的应用2 : 定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包信n个方法的对象或函数
* 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script src="myModule2.js"></script>
<script>
myModule2.doSomething();
myModule2.doOtherthing();
</script>
</body>
</html>
myModule2.js
(function(window){
// 私有数据
var msg="my JavaScript";
// 操作数据的函数
function doSomething(){
console.log('doSomething() '+msg.toUpperCase());
}
function doOtherthing(){
console.log('doOtherthing() '+msg.toLowerCase());
}
window.myModule2={
doSomething:doSomething,
doOtherthing:doOtherthing
};
})(window);//传入window可以实现代码压缩
8、闭包的缺点及解决
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_闭包的缺点及解决</title>
</head>
<body>
<!--
1. 缺点
* 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
* 容易造成内存泄露
2. 解决
* 能不用闭包就不用
* 及时释放
-->
<script type="text/javascript"> function fn1(){
var arr=new Array(100000);
function fn2(){
console.log(arr.length);
}
return fn2;
}
var f = fn1();
f();//100000
f=null;//让内部函数成为垃圾对象---->回收闭包 </script>
</body>
</html>
9、内存溢出和内存泄露
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_内存溢出与内存泄露</title>
</head>
<body>
<!--
1. 内存溢出
* 一种程序运行出现的错误
* 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
2. 内存泄露
* 占用的内存没有及时释放
* 内存泄露积累多了就容易导致内存溢出
* 常见的内存泄露:
* 意外的全局变量
* 没有及时清理的计时器或回调函数
* 闭包
-->
<script type="text/javascript"> // 1. 内存溢出
var obj = {};
for (var i = 0; i < 10000; i++) {
obj[i] = new Array(1000000);
// console.log('-----');
}
// 2. 内存泄露
// 意外的全局变量
function fn() {
a = new Array(10000000);
console.log(a);
}
fn();
// 没有及时清理的计时器或回调函数
var intervalId = setInterval(function () { //启动循环定时器后不清理
console.log('----');
}, 1000);
// clearInterval(intervalId)
// 闭包
function fn1() {
var a = 4;
function fn2() {
console.log(++a);
}
return fn2;
}
var f = fn1();
f();
// f = null; </script>
</body>
</html>
10、面试题1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>07_面试题1</title>
</head>
<body>
<script type="text/javascript"> //代码片段一
var name ="The Window";
var object = {
name: "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
// 没有使用闭包
// object.getNameFunc()得到的就是一个函数,函数(),里面的this就是window
alert(object.getNameFunc()());//The Window
// 代码片段二
var name2 ="The Window";
var object2 = {
name2: "My Object",
getNameFunc : function(){
var that=this;
return function(){
return that.name2;
};
}
};
// 使用了闭包
// object2.getNameFunc()得到一个函数,执行函数,把object2对象赋值给that,that指向object2
alert(object2.getNameFunc()());//My Object </script>
</body>
</html>
11、面试题2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>07_面试题2</title>
</head>
<body>
<script type="text/javascript"> // 关键点在于有没有产生新的闭包
function fun(n,o){
console.log(o);
return {
fun:function(m){
return fun(m,n);
}
};
}
var a =fun(0);//undefined,返回一个对象,产生了闭包
a.fun(1);//0 m=1,n=0 ==> 输出0 ,产生一个新的闭包,返回了一个对象,但是没有接收,闭包很快就消失了
a.fun(2);//0 m=2,n=0 同理
a.fun(3);//0 m=3,n=0 同理
var b = fun(0).fun(1).fun(2).fun(3);//undefined 0 1 2,返回的对象被接收了,产生了新的闭包
var c = fun(0).fun(1);//undefined 0
c.fun(2);//1
c.fun(3);//1 </script>
</body>
</html>
三、对象高级
1、对象创建模式
1、Object构造函数模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_Object构造函数模式</title>
</head>
<body>
<!--
方式一: Object构造函数模式
* 套路: 先创建空Object对象, 再动态添加属性/方法
* 适用场景: 起始时不确定对象内部数据
* 问题: 语句太多
-->
<script type="text/javascript"> /*
一个人: name:"Tom", age: 12
*/
var p =new Object();
p.name='tom';
p.age=12;
p.setName=function(name){
this.name=name;
}
// 测试
p.setName('jack');
console.log(p); </script>
</body>
</html>
2、对象字面量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_对象字面量</title>
</head>
<body>
<!--
方式二: 对象字面量模式
* 套路: 使用{}创建对象, 同时指定属性/方法
* 适用场景: 起始时对象内部数据是确定的
* 问题: 如果创建多个对象, 有重复代码
-->
<script type="text/javascript"> var p={
name:'tom',
age:12,
setName:function(name){
this.name=name;
}
};
// 测试
p.setName('marry');
console.log(p.name);
// 代码重复
var p2={
name:'jack',
age:16,
setName:function(name){
this.name=name;
}
}; </script>
</body>
</html>
3、工厂模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_工厂模式</title>
</head>
<body>
<!--
方式三: 工厂模式
* 套路: 通过工厂函数动态创建对象并返回
* 适用场景: 需要创建多个对象
* 问题: 对象没有一个具体的类型, 都是Object类型
-->
<script type="text/javascript"> // 返回一个对象的函数==>工厂函数
function createPerson(name,age){
var obj={
name:name,
age:age,
setName:function(name){
this.name=name;
}
};
return obj;
}
function createStudent(name,sno){
var obj={
name:name,
sno:sno,
setSno:function(sno){
this.name=sno;
}
};
return obj;
}
// 创建2个人
var p1= createPerson('tom',12);
var p2= createPerson('jack',15);
var s = createStudent("zs",21281084);
console.log(typeof p1===typeof s);//true </script>
</body>
</html>
4、自定义构造模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_自定义构造函数模式</title>
</head>
<body>
<!--
方式四: 自定义构造函数模式
* 套路: 自定义构造函数, 通过new创建对象
* 适用场景: 需要创建多个类型确定的对象
* 问题: 每个对象都有相同的数据, 浪费内存
-->
<script type="text/javascript"> function Person(name,age){
this.name=name;
this.age=age;
this.setName=function(name){
this.name=name;
}
}
function Student(name,sno){
this.name=name;
this.sno=sno;
this.setName=function(name){
this.name=name;
}
}
var p = new Person('zz',18);
p.setName('jack');
console.log(p1.name,p.age);
console.log(p instanceof Person);//true
var s = new Student('zs',120310);
console.log(s);
console(s instanceof Student);//true
var p2=new Person('fs',12);
console.log(p1,p2); </script>
</body>
</html>
5、构造函数+原型的组合模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_构造函数+原型的组合模式</title>
</head>
<body>
<!--
方式六: 构造函数+原型的组合模式
* 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
* 适用场景: 需要创建多个类型确定的对象
-->
<script type="text/javascript"> function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.setName=function(name){
this.name=name;
};
var p1= new Person('zs',19);
var p2= new Person('sd',11);
console.log(p1,p2); </script>
</body>
</html>
2、继承模式
1、原型链继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_原型链继承</title>
</head>
<body>
<!--
方式1: 原型链继承
1. 套路
1. 定义父类型构造函数
2. 给父类型的原型添加方法
3. 定义子类型的构造函数
4. 创建父类型的对象赋值给子类型的原型
5. 将子类型原型的构造属性设置为子类型
6. 给子类型原型添加方法
7. 创建子类型的对象: 可以调用父类型的方法
2. 关键
1. 子类型的原型为父类型的一个实例对象
-->
<script type="text/javascript"> // 父类型
function Supper(){
this.supProp="Super property";
}
Supper.prototype.showSupperProp=function(){
console.log(this.supProp);
}
// 子类型
function Sub(){
this.subProp ="Sub property";
}
// 子类型的原型是父类型的一个实例对象
Sub.prototype = new Supper();
// 让子类型的原型的constructor指向子类型
Sub.prototype.constructor=Sub;
Sub.prototype.showSubProp=function(){
console.log(this.subProp);
}
var sub=new Sub();
sub.showSupperProp();
// sub.toString();
sub.showSubProp();
console.log(sub.constructor); </script>
</body>
</html>
2、借用构造函数继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_借用构造函数继承</title>
</head>
<body>
<!--
方式2: 借用构造函数继承(假的)
1. 套路:
1. 定义父类型构造函数
2. 定义子类型构造函数
3. 在子类型构造函数中调用父类型构造
2. 关键:
1. 在子类型构造函数中通用call()调用父类型构造函数
-->
<script type="text/javascript"> function Person(name,age){
this.name = name;
this.age=age;
}
function Student(name,age,price){
Person.call(this,name,age);//相当于this.Person(name,age);
/* this.name = name;
this.age=age; */
this.price=price;
}
var s=new Student("XiaoLin",21,14000);
console.log(s.name,s.age,s.price); </script>
</body>
</html>
3、组合继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_组合继承</title>
</head>
<body>
<!--
方式3: 原型链+借用构造函数的组合继承
1. 利用原型链实现对父类型对象的方法继承
2. 利用call()借用父类型构建函数初始化相同属性
-->
<script type="text/javascript"> 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;//修正constructor属性
Student.prototype.setPrice=function(price){
this.price=price;
}
var s=new Student("XiaoLin",21,14000);
s.setName('xiaolin');
s.setPrice(15000);
console.log(s.name,s.age,s.price); </script>
</body>
</html>
四、线程机制与事件机制
1、进程与线程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_进程与线程</title>
</head>
<body>
<!--
1. 进程:程序的一次执行, 它占有一片独有的内存空间。分配资源的最小单位
2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程,cpu调度的最小单位
3. 进程与线程
* 应用程序必须运行在某个进程的某个线程上
* 一个进程中一般至少有一个运行的线程: 主线程,进程启动后自动创建的
* 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
* 一个进程内的数据可以供其中的多个线程直接共享
* 多个进程之间的数据是不能直接共享的
* 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
4. 浏览器运行是单进程还是多进程?
* 有的是单进程
* firefox
* 老版IE
* 有的是多进程
* chrome
* 新版IE
5. 如何查看浏览器是否是多进程运行的呢?
* 任务管理器==>进程
6. 浏览器运行是单线程还是多线程?
* 都是多线程运行的
7、 什么是多进程和多线程?
多进程:一个应用程序可以同时启动多个实例运行
多线程:在一个进程内,同时有多个线程运行
8、比较单线程和多线程
多线程:
优点:有效提升cpu的利用率
缺点:创建多线程开销、线程间切换开销(单核)、死锁与状态同步问题
单线程:
优点:顺序编程简单易懂
缺点:效率低
9、 js是单线程还是多线程?
js是单线程运行的
但是使用Html5的Web Workes可以多线程运行
-->
</body>
</html>
2、浏览器内核
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_浏览器内核</title>
</head>
<body>
<!--
1. 什么是浏览器内核?
* 支持浏览器运行的最核心的程序
2. 不同的浏览器可能不太一样
* Chrome, Safari: webkit
* firefox: Gecko
* IE: Trident
* 360,搜狗等国内浏览器: Trident + webkit
3. 内核由很多模块组成
主 * js引擎模块:负责js程序的编译与运行
线 * html,css文档解析模块 : 负责页面文本的解析
程 *dom/css模块 : 负责dom/css在内存中的相关处理
* 布局和渲染模块 : 负责页面的布局和效果的绘制
分 * 定时器模块 : 负责定时器的管理
线 * 网络请求模块 : 负责服务器请求(常规/Ajax)
程 * 事件响应模块 : 负责事件的管理
-->
</body>
</html>
3、定时器引发的思考
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_定时器引发的思考</title>
</head>
<body>
<button id="btn">启动定时器</button>
<!--
1. 定时器真是定时执行的吗?
* 定时器并不能保证真正定时执行
* 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)
2. 定时器回调函数是在分线程执行的吗?
* 在主线程执行的, js是单线程的
3. 定时器是如何实现的?
* 事件循环模型(后面讲)
-->
<script type="text/javascript"> var btn = document.getElementById('btn');
btn.onclick=function(){
// var start = new Date.getTime();
var start = Date.now();
console.log('启动定时器前...');
setTimeout(function(){
console.log('定时器执行了',Date.now()-start);
},200);
console.log('启动定时器后...');
// 做一个长时间的工作
for(var i=0;i<1000000000;i++){
}
// 定时器执行时间延迟了
}; </script>
</body>
</html>
4、js是单线程执行的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_JS是单线程的</title>
</head>
<body>
<!--
1. 如何证明js执行是单线程的?
* setTimeout()的回调函数是在主线程执行的
* 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式, 而不用多线程模式?
* JavaScript的单线程,与它的用途有关。
* 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
* 这决定了它只能是单线程,否则会带来很复杂的同步问题
3. 代码的分类:
* 初始化代码
* 回调代码
4. js引擎执行代码的基本流程
* 先执行初始化代码: 包含一些特别的代码 回调函数(异步执行)
* 设置定时器
* 绑定事件监听
* 发送ajax请求
* 后面在某个时刻才会执行回调代码
-->
<script type="text/javascript"> setTimeout(function(){
console.log('timeout 2222');
alert('22222');
},5000);
setTimeout(function(){
console.log('timeout 1111');
alert('11111');
},3000);
setTimeout(function(){
console.log('timeout 0000');
},0);//alert----先输出
function fn(){
console.log('fn()');
}
fn();
// 先输出1,再1111,再2222
console.log('alert()之前');
alert('------');//暂停当前主线程的执行,也暂停了计时,点击确定后才恢复程序的执行和计时,现在2022并不会暂停计时
console.log('alert()之后'); </script>
</body>
</html>
5、浏览器的事件循环(轮询)模型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_事件循环模型</title>
</head>
<body>
<button id="btn">测试</button>
<!--
1. 所有代码分类
* 初始化执行代码(同步代码): 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
* 回调执行代码(异步代码): 处理回调逻辑
2. js引擎执行代码的基本流程:
* 初始化代码===>回调代码
3. 模型的2个重要组成部分:
* 事件(定时器/DOM事件/Ajax)管理模块
* 回调队列
4. 模型的运转流程
* 执行初始化代码, 将事件回调函数交给对应模块管理
* 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
* 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
-->
<script type="text/javascript"> function fn1(){
console.log('fn1()');
}
fn1();
var btn=document.getElementById('btn');
btn.onclick=function(){
console.log('点击了btn');
};
setTimeout(function(){
console.log('定时器执行了');
},2000);
function fn2(){
console.log('fn2()');
}
fn2();
// fn1(),fn2(); </script>
</body>
</html>
6、H5 Web Workers(多线程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_Web Workers_测试</title>
</head>
<body>
<!--
1. H5规范提供了js分线程的实现, 取名为: Web Workers
2. 相关API
* Worker: 构造函数, 加载分线程执行的js文件
* Worker.prototype.onmessage: 用于接收另一个线程的回调函数
* Worker.prototype.postMessage: 向另一个线程发送消息
3. 不足
* worker内代码不能操作DOM(更新UI)
* 不能跨域加载JS
* 不是每个浏览器都支持这个新特性
-->
<input type="text" placeholder="数值">
<button id="btn">计算</button>
<script type="text/javascript"> // 编程实现斐波那契数列(Fibonacc sequence)的计算
// F(0)=0,F(1)=1,....F(n)=F(n-1)+F(n-2);
function fibonacci(n){
return number<=2 ? 1: fibonacci(number-1)+fibonacci(number-2);
/* var res = [0, 1];
if(n < 2) {
return res[n];
}
var first = 0;
var second = 1;
var fibn = 0;
for(var i = 2; i <= n; i++) {
fibn = first + second;
first = second;
second = fibn;
}
return fibn; */
}
// 获取输入框中的内容
var input = document.getElementsByTagName("input")[0];
document.getElementById('btn').onclick=function(){
var num = input.value;
var result = fibonacci(num);
alert(result);
} </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" placeholder="数值" id="number">
<button id="btn">计算</button>
<script> var input = document.getElementById("number");
document.getElementById('btn').onclick=function(){
var number = input.value;
// 创建一个worker对象
var worker = new Worker('worker.js');
// 绑定接收消息监听
worker.onmessage=function(event){
console.log('主线程接收分线程返回的数据:'+event.data);
alert(event.data);
}
// 向分线程发送数据
worker.postMessage(number);
console.log('主线程向分线程发送的数据:'+number);
} </script>
</body>
</html>
function fibonacci(number){
return number<=2 ? 1: fibonacci(number-1)+fibonacci(number-2);
/* var res = [0, 1];
if(n < 2) {
return res[n];
}
var first = 0;
var second = 1;
var fibn = 0;
for(var i = 2; i <= n; i++) {
fibn = first + second;
first = second;
second = fibn;
}
return fibn; */
}
var onmessage = function(event){
var num = event.data;
console.log("分线程接收到主线程发送来的数据:"+num);
// 计算
var result = fibonacci(num);
postMessage(result);
console.log('分线程向主线程返回数据:'+result);
// alert(result);//alert是window的方法。在分线程不能调用
// 分线程中的全局对象不再是window,所以分线程不可能更新线程
}
console.log(this);
本文作者:_xiaolin
本文链接:https://www.cnblogs.com/SilverStar/p/17415637.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。