轮播图步骤:
第一步: 结构 结构牢记
第二步:css 外面小盒子根据图片的宽度进行设置 内部大盒子 宽度是根据图片的个数进行的设置的
第三步: js行为
//1、点击按钮让图片先动起来(只点击右侧) 每次点击要准备走的距离都是-600,这个距离需要用定时器慢慢走,
// 需要求每一步的距离 元素起始位置我们是可以获取到的, 结束位置我们也求出来;
//2、 看什么时候元素停止,当刚好元素走的位置和开启求出来的结束位置一样的时候,停止定时器;
//3、左边按钮和右边按钮 几乎一致, 只是点左边按钮的时候,元素要准备走的距离是600,其它的都不变,因此封装函数move(flag)
函数传参为true就是点右 false就是点左
//4、无缝的操作 结构需要变化 最前面加最后一张 最后面加第一张; 在清除定时器的时候,去判断是否元素走到了最后一张的位置和第一 张的位置,如果走到,让元素瞬变到相应的位置
//5、小圆点变色 排他 关键点在求出哪一个小圆点变色,就是要拿到小圆点变色的下标,通过元素最终位置去求
//6、点击小圆点,图片移动对应位置 要传递元素准备移动的最终位置 跟点击的小圆点下标相关,move里面参数要根据类型进行判断
//到底是点的按钮还是点的小圆点,因为传过来的参数不同
//7、自动轮播 , 根据图片的下标进行move 传的也是元素准备移动的最终位置, 下标需要进行判断 为6 变回1
//8、自动轮播鼠标行为的同步 鼠标移入清除自动轮播 鼠标移出重启自动轮播
//9、移入之后,鼠标点击按钮或者小圆点,都要去把自动轮播的下标值 进行更新, 否则没法同步;
一、内存、变量、数据
内存
计算机:cpu(寄存器) 内存 硬盘 电源
硬件内存条:
二极管
4G 4G字节
存储1或者0(通电和不通电)
内存地址(内存编号)
内存的东西断电消失
硬盘的东西永久性存储
运行内存(虚拟内存):(了解)
内存结构:栈内存和堆内存 (c语言、java)
但是在js当中所有的内存都属于堆内存 然后在堆内存内部又分为栈结构和堆结构
var a = 10;
a作为window对象的属性
window又是一个对象,对象肯定是在堆结构当中的
变量
可以变化的量
程序和进程
变量:可以变化的量:就是存储数据的容器;
var a = 5,b = 10;
var a = 5;
var b = 10;
本质上是内存空间
数据
分类(2大类)
* 基本(值)类型
* Number: 任意数值
* String: 任意文本
* Boolean: true/false
* undefined: undefined
* null: null
* 对象(引用)类型
* Object: 任意对象
* Array: 一种特别的对象类型(下标/内部数据有序)
* Function: 一种特别的对象类型(可执行)
备注:准确来说Array和Function属于一种特别的Object类型。
**数据存储**
基本数据存储 数据本身
对象数据存储 地址值
备注:内存当中存储的都是值,一个存的是数据本身,另一个存的是数据所在的内存(堆结构)地址;
**鉴别数据类型:**
* typeof:注意typeof的返回值是类型的字符串名称(首字母是小写的)
* 可以区别: 数值, 字符串, 布尔值, undefined, function
* 不能区别: null与数组、对象
* 对于typeof:
* 一个不正确:typeof null的结果是object
* 一个不精确:typeof []的结果是object
* instanceof: A instanceof B ==> 判断A是否是B这个构造函数的实例对象(B是构造函数名)
* 专门用来判断对象数据的具体类型: Object, Array
* ===
* 可以判断: undefined和null
* 备注:因为undefined类型只有一个值、null类型也只有一个值,所以可以用===判断
所有数据类型转化布尔值:
* 主要是处理 if(){};
基本数据类型:
‘’ 0 NaN undefined null false
对象数据类型:
全是true
*备注:js当中只有6个false值,其余全是true;
所有的数据类型进行判等 ==
*基本数据类型
如果是同种的基本数据类型,那么就直接比较两个值是否一样
如果是不同的基本数据类型,那么两个值都要去转数字;
*备注:当出现undefined和null的时候,他们两个是相等的;
0和null
''和null
false和null 全都不等
*对象数据类型
所有的对象去比较,比较的是地址,如果引用(地址)相同就相等;
[] == [];
[] == ![];
*基本数据类型和对象数据类型之间的转化;
对象数据类型和基本数据类型之间进行比较、判等和运算的时候,需要将对象数据类型转化基本数据类型,再按照基本数据类型的规 则进行运算
对象数据类型转基本数据类型规则:
1、首先看对象能不能转化为一个基本值类型 看看对象能不能使用valueOf方法转化一个基本值类型,调用的全是Object的原型对象 当中的valueOf方法;
2、我们发现所有的对象在调用valueOf方法的时候都返回自身;
3、如果对象调用valueof方法返回的不是基本值类型,那么会接着调用toString方法转化基本值;
*备注:在真正开发当中我们很少去处理不同数据类型之间的判等,因此推荐在判等的时候使用===
面试题:
//对象类型数据的判断
var b1 = {
b2:[2,'atguigu',console.log],
b3:function () {
alert('hello')
}
}
console.log(b1,b1.b2,b1.b3)//
console.log(b1 instanceof Object,typeof b1)//
console.log(b1.b2 instanceof Array,typeof b1.b2)//
console.log(b1.b3 instanceof Function,typeof b1.b3)//
console.log(typeof b1.b2[2])
console.log(typeof b1.b2[2]('atguigu'))//
1. undefined与null的区别?
* undefined代表定义变量没有赋值 var a;
* null代表赋值了, 只是值为null var a = null;
2. 什么时候给变量赋值为null呢?
对象初始化
删除对象 obj = null ==》 obj变为垃圾对象
3. 严格区别变量类型与数据类型?(js中了解行了)
在c语言当中 变量也是有类型的 int a = 10; char a float a;
在js当中,变量类型是弱类型, 只有在数据确定存储之后,变量类型才确定 而且可以改变;(根据存储数据类型的不同而不同);
关于引用变量赋值问题
1). 2个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 另一个引用变量也看得见
var arr1 = [1,2,3];
var arr2 = arr1;
arr1[1] = 22;
console.log(arr2);
2). 2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
var obj1 = {};
var obj2 = obj1;
obj2 = {};
obj2.name = 'zhaoliying';
console.log(obj1);
关于函数传参传值的问题
传基本数据值
var a = 10;
var b = 20;
function add(a,b){
a = 20;
return a + b;
}
add(a,b);
console.log(a);
传引用数据值
var arr = [1,2,3];
function fn(arr){
arr[1] = 22;
}
fn(arr);
console.log(arr);
关于内存释放(堆结构)的问题
obj = null;
垃圾回收机制:堆结构当中的对象数据,要想被回收释放,必须成为垃圾对象,也就是没有人再指向这个对象数据;
二、对象基础
1. 什么是对象?
* 代表现实中的某个事物, 是该事物在编程中的抽象(无序的键值对的集合)
* 多个数据的集合体(封装体)
* 用于保存多个数据的容器
var obj = {
name:'赵丽颖‘,
age:33
eat:funcition(){
console.log('吃货');
}
}
obj.eat();
console.log()
2. 为什么要用对象?
* 便于对多个数据进行统一管理
* 为了去描述某个复杂的事物
3. 创建对象?
*
4. 对象的组成
* 属性
* 代表现实事物的状态数据
* 由属性名和属性值组成
* 属性名都是字符串类型, 属性值是任意类型
var obj = {name:'zly','name':'',"name":''}
* 方法
* 代表现实事物的行为数据
* 备注:方法是一种特别的属性==>属性值是函数
5. 如何访问对象内部数据?
* 对象.属性名: 编码简单, 但有时不能用
var obj = {};
obj["content-type"] = '12';
var a = 10;
obj[a]
* 对象['属性名']: 编码麻烦, 但通用
* 对象[变量名]:变量里面的值会被转化成字符串,作为属性名
问题: 什么时候必须使用['属性名']的方式?
* 属性名不是合法的标识符
* 属性名是变量
6、面试题
var a = {};//
var obj1 = {m:2}//
var obj2 = {n:2}// [1,2,3]
var obj3 = function(){};
a[obj1] = 4 // '[object Object]' a['[object Object]'] = 4
a[obj2] = 5 '1,2,3' a['1,2,3'] = 5
a.name ='kobe'
a[obj3] = 6;
console.log(a[obj1]) 5
console.log(a) //
a{
1,2,3:5
[object Object]:4,
name:'kobe',
function(){}:6
}
三、函数基础
1. 什么是函数?
* 具有特定功能的n条语句的封装体
* 只有函数是可执行的, 其它类型的数据是不可执行的
* 函数也是对象
2. 为什么要用函数?
* 提高代码复用
* 便于阅读和交流
* 把一个项目模块化
3. 如何定义函数?
* 函数声明(字面量) function fn(){};
* 函数表达式 var fn = function(){};
构造函数 var add = new Function(‘a’,‘b’,‘return a + b’)//了解
4. 函数的2种角色
* 函数: 通过()使用
通过new和()使用
* 对象: 通过.使用 ==> 称之为: 函数对象
5. 如何调用(执行)函数?
* test()
* new test()
* obj.test()
* test.call/apply(obj)
6、函数执行的过程(内存变化)
7、回调函数
什么函数才是回调函数?
* 你定义的
* 你没有直接调用
* 但最终它执行了(在特定条件或时刻)
常见的回调函数?
* DOM事件函数
* 定时器函数
* ajax回调函数(后面学)
* 生命周期回调函数(后面学)
8、IIFE
理解
* 全称: Immediately-Invoked Function Expression 立即调用函数表达式
* 别名: 匿名函数自调用
作用
* 隐藏内部实现
* 不污染外部命名空间
案例:
var a = 2
var b = 3
function sum(a,b) {
return a + b
}
var a = 'haha';
sum();
var a = 'haha';
(function () {
var a = 2
var b = 3
function fn() {
return a + b
}
window.fn = fn
})()
fn()
9、this的总结
this是什么?
* 一个关键字, 一个内置的引用变量
* 在函数中都可以直接使用this
* this代表调用函数的当前对象(函数的调用者)
* 在定义函数时, this还没有确定, 只有在执行时才动态确定(绑定)的
function fn(){}; fn() fn.call(obj);
如何确定this的值?
* test()
* obj.test()
* new test()
* test.call/apply(obj)
总结: 函数的调用方式决定了this是谁
this的出现场合: 函数中 方法中 事件中 构造函数中 call/apply()
10、递归(后面说)
四、执行上下文、执行上下文栈、预解析、作用域、作用域链、 (打断点)
执行上下文(执行上下文环境):
程序在解析和运行的时候所依赖和使用的环境;
执行上下文栈:
程序为了管理执行上下文(确保程序的执行顺序)所创建的一个栈数据结构,被称作执行上下文栈;
预解析(变量提升):
先解析函数:函数重名覆盖
再解析变量:变量重名忽略
作用域:(抽象的概念,代码定义的时候作用域就确定死了)
变量起作用的范围;
作用域;隔离变量,防止变量命名污染;
作用域定义时候确定
作用域链:
真实存在的,作用域链是使用执行上下文当中变量对象所组成的链条结构(数组结构)
查找的时候其实真正是先去自身的变量对象当中查找,如果没有,去上级执行上下文的变量对象当中去查找,直到找到全局执行上下文的变量对象; 函数上一级的变量对象其实是在函数定义的时候都已经确定好的******
程序开始执行:(全局环境和函数环境)
全局执行上下文(分为创建阶段和执行阶段)代码开始执行之前和之后
1、全局执行上下文压入执行上下文栈)
创建上下文阶段(确定作用域):
1、收集变量形成变量对象 函数 var的变量会收集
预解析(其实在创建变量对象的时候已经做了预解析)
2、确定this指向(可以认为确定执行者)
3、创建自身执行上下文的作用域链
注意:同时确定函数在调用时候的上级作用域链。(根据ECMA词法去确定,看内部是否引用外部变量确定)
2、执行全局执行上下文
执行全局上下文阶段
为变量真正赋值
顺着作用域链查找要使用的变量或者函数执行
函数执行上下文
1、函数执行上下文压栈
1、收集变量 var 形参 arguments 函数
函数的作用域链: 自己定义的时候已经确定了函数在调用时候的上级作用域链,因此,在函数调用的时候,只需要将
自己的变量对象添加到作用域的顶端;
2、执行函数执行上下文
全局:创建全局执行上下文--全局执行上下文压栈--执行全局执行上下文--
函数:创建函数执行上下文--函数执行上下文压栈--执行函数执行上下文--函数执行上下文出栈--
执行全局执行上下文--全局执行上下文出栈
创建全局上下文:1、收集变量形成变量对象(预解析)2、确定this指向 3、创建自身作用域链(同时函数确定调用的上级作用域链)
//预解析 作用域链面试题
var x = 10;
function fn() {
console.log(x);//10
}
function show(f) {
var x = 20;
f();
}
show(fn);
var a;
function a() {}
console.log(typeof a)//function
if (!(b in window)) {
var b = 1;
}
console.log(b)//undefined
var c= 1
function c(c) {
console.log(c)
var c = 3
}
c(2) //c is not a function
var fn = function () {
console.log(fn)
}
fn()
var obj = {
fn2: function () {
console.log(fn2)//
}
}
obj.fn2()
五、闭包(面试题)
1. 如何产生闭包(条件)?
* 函数嵌套
* 内部函数引用外部函数的局部变量
* 调用外部函数,调用或者引用内部函数;
2. 闭包到底是什么?
* 理解一: 闭包是嵌套的内部函数(绝大部分人)
* 理解二: 包含被引用变量(外部函数)的对象(极少数人)
* 理解三: 所谓的闭包是一个引用关系,该引用关系存在于内部函数中,引用的是外部函数的变量的对象(深入理解)
3、常见的闭包
1. 将函数作为另一个函数的返回值
2. 将函数作为实参传递给另一个函数调用
3. 使用闭包实现私有方法操作独立的私有属性
4、闭包的作用
1. 延长外部函数变量对象的生命周期
2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
3. 注意: 浏览器为了性能后期将外部函数中不被内部函数使用的变量清除了
5、闭包的生命周期
1. 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
2. 死亡: 在嵌套的内部函数成为垃圾对象时
6、自定义模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包含n个方法的对象或函数
* 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
使用window和不使用window区别:两种都使用的是闭包思想;
使用window会污染window对象的属性
7、闭包的缺点和解决(内存泄漏和内存溢出)
闭包是一把双刃剑:有优点也有缺点;
优势:
1. 延长外部函数变量对象的生命周期
2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
缺点:
会造成内存泄漏,甚至导致内存溢出;
内存泄漏:代表对象占着内存,不会释放
内存溢出:代表不会释放的东西太多,导致内存满了;
一般我们再使用闭包的时候,不用的时候记得把内部函数变为垃圾对象,这样就可以防止内存泄漏;
8、面试题
//代码片段一
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
}
};
console.log(object.getNameFunc()()); //the window
//代码片段二
var name2 = "The Window";
var object2 = {
name2: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name2;
};
}
};
console.log(object2.getNameFunc()());// "My Object"
//代码片段三
function fun(n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m, n)
}
}
}
var a = fun(0) //undefined
a.fun(1) //0
a.fun(2) //0
a.fun(3) //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
//代码片段四
function Foo() {
getName = function () { alert (1); };
return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
六、原型和原型链、终极原型链
七、面向对象(原型继承、构造函数继承、组合继承) 面向对象三大特性:封装继承多态
原型继承:
让父类的实例作为子类的原型,将子类的原型构造器补充完整 (为了让子类继承方法)
构造函数继承:
在子类当中去调用父类的构造函数(为了让子类继承属性)
组合继承:
原型继承方法,构造函数继承属性
方法重写(多态的表现形式之一)
方法重载
八、事件循环机制
多进程和多线程
1. 进程:程序的一次执行, 它占有一片独有的内存空间
2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程
3. 进程与线程
* 一个进程中一般至少有一个运行的线程: 主线程
* 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
* 一个进程内的数据可以供其中的多个线程直接共享
* 多个进程之间的数据是不能直接共享的
4. 浏览器运行是单进程还是多进程?
* 有的是单进程
* firefox
* 老版IE
* 有的是多进程
* chrome
* 新版IE
5. 如何查看浏览器是否是多进程运行的呢?
* 任务管理器==>进程
6. 浏览器运行是单线程还是多线程?
* 都是多线程运行的
js是单线程的
1. 如何证明js执行是单线程的?
* setTimeout()的回调函数是在主线程执行的
* 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式, 而不用多线程模式?
* JavaScript的单线程,与它的用途有关。
* 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
* 这决定了它只能是单线程,否则会带来很复杂的同步问题
3. 代码的分类:
* 初始化代码(同步代码)
* 回调代码
4. js引擎执行代码的基本流程
* 先执行初始化代码: 包含一些特别的代码
* 设置定时器
* 绑定监听
* 发送ajax请求
* 后面在某个时刻才会执行回调代码
同步 同步执行完成才会去执行异步
异步 只要是异步的任务都会有自己的管理模块进行托管
回调
事件
定时器
ajax
事件循环模型
1. 所有代码分类
* 初始化执行代码(同步代码): 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
* 回调执行代码(异步代码): 处理回调逻辑
2. js引擎执行代码的基本流程:
* 初始化代码===>回调代码
3. 模型的2个重要组成部分:
* 事件管理模块
* 回调队列
4. 模型的运转流程
* 执行初始化代码, 将事件回调函数交给对应模块管理
* 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
* 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
Web Workers模拟多线程(了解~)
1. H5规范提供了js分线程的实现, 取名为: Web Workers
2. 相关API
* Worker: 构造函数, 加载分线程执行的js文件
* Worker.prototype.onmessage: 用于接收另一个线程的回调函数
* Worker.prototype.postMessage: 向另一个线程发送消息
每个线程可以向不同线程发送消息 也可以接收不同线程传来的消息
主线程操作
发送消息: worker.postMessage(消息可以是任何数据)
接受消息: worker.onmessage = function(e){
console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中
}
子线程操作
发送消息: this(self).postMessage(消息可以是任何数据)
接受消息: this(self).onmessage = function(e){
console.log(e.data)//接收到的消息或者数据在事件对象的data属性当中
}
3. 不足
* worker内代码不能操作DOM(更新UI)
* 不能跨域加载JS
* 不是每个浏览器都支持这个新特性
4、计算得到fibonacci数列中第n个数的值
在主线程计算: 当n的数较大时, 会阻塞主线程, 导致界面卡死
在分线程计算: 不会阻塞主线程