学习笔记
- 查询文档 https://developer.mozilla.org/zh-CN/
- 博客 http://www.cnblogs.com/pandawind/p/9829898.html
- js笔记 https://duyiedu.github.io/
1、js是解释性语言也是单线程,其实js引擎是单线程,同步(只做一件事)
2、link和script标签是异步加载(同时进行)
3、js分为ECMAscript(基础语法)、DOM(文档对象模型)、BOM(浏览器)
4、js执行队列,轮转时间片:类似吃饭,吃一口这个,再吃一口那个
5、变量var a = 1;----> var a; a=1
6、if、function、for后面不用加分号
7、错误 - 低级错误(语法解析错误)
js语法错误会引发后续代码终止,但不会影响其他js代码块 - 逻辑错误(标准错误,情有可原)
8、任何数据类型加字符串都是字符串,加number会将其隐式转换成数字相加
9、var a = 1;var b = a-- + --a; ++在后先运算在++,++在前先++在运算
var a = 0;
console.log(a++); // 0 ++在后运行完在
console.log(a); // 1
//-----------
var a = 2;
var b = a-- + --a + ++a ;
// a-- 2 1
// --a 1-1 0
// ++a 0+1 1
console.log(b); //3
console.log(a);//1
10、但凡运算就要求出结果
var a = 1 > 2; console.log(a) false
var b = 1 && 2; console.log(b) 2
11、undefined、null、NaN、""、0、false,都为假
12、type undefined 为字符串 undefined
13、2 > 1 && document.write('如果2大于1,就打印出write')
14、for循环,控制循环圈数和i的变化
15、编程就是找规律
16、break必须放在循环里面
17、js即面向过程也面向对象
18、typeof 返回6个值
string、number、boolean、undefined、function、object
19、parsetInt(参数,以目标进制(2-36)为基地转为10进制)转整形
parseInt(3,8) //把3当做8进制的数转换为10进制
20、想把谁转换为字符串,就 点toString(),undefined和null不可以使用,tostring里面有个参数是以10进制为基地转换为目标进制
21、类型转换前,先进行隐式类型转换
var a = "123";-----a ++ -----Number(123) ----123
22、当+号两侧有一个是字符串的话,就会转换字符串
23、隐式类型中undefined和null不能和其他值比较
24、未定义的变量放在typeof里面不会报错,还会返回字符串的undefined,除此之外都会报错XX not is undefinde
25、函数的作用——避免重复定义,相同功能放一起(高内聚、低耦合)
函数定义(函数里面也分为堆内存和栈内存)
1、函数声明 function name(){}
2、命名函数表达式(忽略name1的名字) var name = function name1(){}充当表达式之后,就变成匿名的了 name.name = name1
3、匿名函数表达式(函数表达式) var demo = function() {} demo.name = demo
4、每个函数里面都有放参数的地方argument内数组(实参列表),它和形参有套隐射规则(只有参数相等的时候),你变我也变,注意一点实参有几个实参列表就有几个,不会和形参行程关联
5、函数必须有个return才结束(终止函数),我们没有写的时候,系统会自己加return,所以有时打印的函数是undefined
6、函数调用等他执行完返回结果,才算完事
递归
1、找规律(return公式 n = n * (n-1) ,才会循环计算)
2、找出口
阶乘就是利用自身的功能,求出结果,函数调用等他执行完返回结果,才算完事
3、递归唯一一点让代码变得更加简洁,但是递归的运算很慢需要等最底层1的结果出来,慢慢往上返,最后才能算出5的阶乘
4、斐波那列数列的公式就是n-1 + n-2 的和
5、递归中先执行的函数最后才有结果
闭包、作用域
预编译
1、预编译之前语法分析、预编译、解释执行
2、函数声明整体提升,变量 声明提升
3、预编译过程(发生在函数执行的前一刻)
- 创建AO对象
-
找形参和变量声明,将变量和形参作为AO属性名,值为undefinde
-
将实参值和形参统一
-
在函数体里面找函数声明,值赋予函数体,如有遇到相同属相名,忽略不计,将函数体赋值即可
4、预编译结束后,函数开始执行,在预编译过程中,函数声明已被提前,所以不用再看,变量也忽略
5、任何全局变量就是window上的属性,未经声明的变量也归window所有
6、函数在预编译时,不管(走)if,if里面有啥都会拿出来
7、if里面不能声明function
作用域
1、作用域属于函数,每个函数产生独有的作用域
2、函数每执行一次,便产生一个AO,执行完函数销毁,进入等待队列
3、a被定义时,产生一个GO
4、a执行时,产生自己的aAO,将它放在作用域的最顶端
5、b函数创建时,是基于a函数基础上的,拿的是a函数的引用
6、b函数执行时,在aAO基础上生成自己的执行期上下文,放在最顶端
7、a的执行产生b的定义,相关数据在doing里,a重新执行时,将产生新的b定义,
8、闭包,但凡是内部的函数被保存到外部,一定生成闭包(a执行产生b的定义)
闭包
过多的占用系统资源叫做内存泄露
1、闭包,但凡是内部的函数被保存到外部,一定生成闭包(a执行产生b定义)
2、b执行完改变num,自身销毁,但是b会在定义时的数据不会销毁,num是在b身上aAo里,再次执行时,还是建立aAo上
3、a销毁的时候b还没执行,b还拿着a的上下文,被保存到外部
4、闭包缺点,造成内存泄露(泄露的多了,就剩的少了,和沙子一样)
5、闭包的作用
6、返回两个闭包,公用的都是父级的变量
7、demo food 储存结构
7-1、变量私有化,外部访问不了
7-2、命名空间,防止变量污染
8、函数定义时不用管,执行时才看如何操作的
9、a执行产生了b定义,b具用了a的劳动成成果,a、b用的同一个引用,a执行完销毁时,引用之间的联系就没了
10、b被保存在全局的变量demo里,脱离了a,当a执行完销毁时,b还存在,他拿着a的引用
11、函数执行完,一直是等待状态,等着下次执行,占用空间,立即执行函数执行完便销毁
立即执行函数(函数执行完立即销毁,在执行队列任务里也查不到它)
1、初始化函数,只执行一次,返回其结果
2、能被执行的表达式,函数名称会被忽略,能被执行符号执行的表达式,就是立即执行函数
var test = function(){
console.log('this is test')
}
console.log(test) // undefined 执行完后被销毁
//这样也是表达式,而且可以忽略函数的名字
+ function(){
console.log("a")
}()
3、坑
// 这样会报错
function(){
console.log()
}()
// 有参数就不会报错,系统会默认换行
function(a,b){
console.log(a+b)
}(1,2)
4、只有表达式才能被执行,一旦表达式执行,便失去对原来函数的索引(一次性的)
5、立即执行函数也有作用域
6、利用闭包解决闭包
27、只要if里面不为那6个假值,都为真
28、this是第一人称我,谁调方法用this,this就指向谁
29、增删改查
delete obj.name // 删除
对象
1、对象的创建方法
- 字面量 var obj = { }
- 构造函数
1、系统自带构造函数 var obj = new Object();new Object()可以产生一个对象
2、自定义(工厂模式),命名方式为首字母大写,加个new 就可以返回对象了
- 构造函数内部原理
1、在函数体最前面隐式的加上this = {}
2、执行this.xxx = xxx
3、隐式的返回this
4、模拟构造函数
5、有new 返回对象,不可以返回原始值
包装类
1、原始值没有属性和方法
2、构造函数的原始值具有属性和方法
// 这样通过new的原始值具有属性和方法,但是num经过运算后,又变成了最初的原始值
var num = new Number(123)
var str = new String("abcd")
3、原始值是没有属性和方法的,之所以可以用 点length,是因为有包装类(执行的过程中,产生隐式的转换就是包装类)
var num = 123;
// 新建new Number(123).len 来弥补操作的不足
num.len = 3 // 这一步发生了隐式的转化new Number(123).len = 3 执行完这个后系统会delete(因为原始值没有属性)
console.log(num.len) //会在此新建new Number(123).len,此时打印是undefined
4、number没有length,string调用length,要经过包装类的
5、坑
原型
1、原型描述的就是继承关系
2、constructor返回他的构造函数,构造函数自身带有constructor,可以进行手动更改,指向其他的构造函数
3、__ proto__里面放的是原型prototype,虽然是系统内部属性,但可以进行更改,和constructor一样
- person不是构造函数,所以没有prototype,但他有__ proto__,指向Person.prototype
Person.prototype = {
thgf:11.2,
bldc:13.2
};
function Person(name,age){
this.name = name;
this.age = age;
}
var person = new Person();
// person不是构造函数,所以没有prototype,但他有__ proto__,指向Person.prototype
console.log(person1.__proto__)
4、剖析__ proto__,在new 构造函数时,系统自动创建一个this对象,每个对象都有proto指向构造函数的原型prototype
5、 改变了person的原型
Person.prototype = {
thgf:11.2,
bldc:13.2
};
function Person(name,age){
this.name = name;
this.age = age;
}
var obj = {
one:'1'
}
var person = new Person();
// 改变了person的原型
person.__proto__ = obj;
console.log(person)
6、原型赋值的坑,点的写法是在原有的基础上更改或赋值, = 的写法相当于开辟另一个空间
7、原型prototype也有隐式原型__proto __,原型上有原型形成的链就是原型链,原型链的连接点就是proto,原型链的最终原型是Object.prototype,它没有proto,和作用域链一样,自己有就使用自己的,自己没有就向上一直找
8、this指向问题
function Person(){
// var this = {
// __proto__: Person.prototype
// }
this.eat = function(){
// this.height = this.height +1
this.height ++
}
}
Person.prototype.height = 100;
var person = new Person();
person.eat()
console.log(person.__proto__) // 100 --->Person.prototype.height = 100
console.log(person.height) // 101 -->person调用了eat方法 this.height = 100 +1
9、字面量方法和new Object相等
10、构造函数的prototype指向Object.prototype,绝大多数对象最终都会继承Object.prototype,还有小部分是受Object.create影响,如果create(null),就是去了系统内部属性
11、object.create(原型,这里面参数必填,当为null时,原型上就没有内置的属性和方法),改变对象原型或者是给某个对象创建原型
var obj = {name:"jialin",age:25}
// 这里就改变了obj1的__proto__(原型)指向obj
var obj1 = Object.create(obj);
function Person(){
}
Person.prototype.name = "jialin"
// 改变obj的proto
var obj = Object.create(Person.prototype)
console.log(obj)
12、undefined、null、Object.create(null),三者没有包装类,没有toString方法
13、toString()
var obj = {}
obj.toString() // [Object Object]
14、同一名字不同功能的方法toString,叫重写
15、document.write就利用了toString方法
16、关于取整
call、apple改变this指向,传参列表不同
1、让Person里面所有的this都指向obj
function Person(){
this.name = "jialin";
this.age = 20
}
var obj = {}
// 让Person里面的this指向obj
Person.call(obj)
console.log(obj.name)
2、借用Person的方法实现obj的功能
3、谁调用this指向谁
4、apply要传数组
继承
原型是实现继承的一种方法
1、公有原型,一个原型,两个构造函数使用
2、不是让对象继承,而是让某个构造函数继承
3、有自己的继承,又不影响你,找一个中间层(圣杯模式)
4、圣杯模式
5、雅虎的(行成闭包,f是私有化变量)
6、命名空间
7、闭包变量私有化,不会污染全局变量
对象枚举
1、变量拼接属性名
会转换为obj['name']
2、hasOwnProerty 验证是否是自己的方法
3、instanceof
a是不是 b构造函数构造出来的
4、判断是数组还是对象
- instanceof
- constructor
-
toString()
this
1、预编译函数声明、变量提升
2、预编译this指向window
3、如果test 使用 new的话,this指向就改变了
4、在其他函数里面执行,没人调用也是走预编译环节
5、new的时候this发生改变
argument
1、arguments.callee 指向当前函数的引用,引用就是函数自己
2、fun.caller 不是arguments的属性,它是函数自己的属性,demo在那个环境被调用的环境
深度克隆
- 封装typeof
数组常用方法
1、数组所有的方法来自Array.prototype
2、长度为10的空数组,new Array(10)
3、改变原数组push、pop、shift、unshift、sort、reverse、splice
-
push 给数组最后一位添加
unshift 给数组前一位添加
-
splice(从第几位开始,截取多少的长度,在切口处添加新的数据随便添加),负数就是倒数,返回值就是截取的,没有返回值原数组发生改变
sort 排序,是按照asic码算的,想要实现我们自己的效果,它内部提供一个借口让我们自己写方法实现
sort排序的原理是冒泡排序
// 记着,位置和位置比较,不是数和数比较
var arr = [1,22,4,5,6,9,7,8,36,7]
// 1.必须写两形参
// 2.看返回值:当返回值为负数时,那么前面的数放在前面
// 当返回值为整数时,后面的数在前
// 为0则不动
// 步骤:1.第一次将 第一位和第二位传进来,进行比较1,22;1,4;1,5
var b = arr.sort(function(a,b){
return a - b;
})
console.log(b)
记着,位置和位置比较,不是数和数比较,位置和位置比较后,会将最小的数放在前面
a > b 可以理解为 a - b > 0
将有序数组打乱,利用Math.random()随机数,0—1开区间(不包括0和1)
思维拓展
按照字节长度来排
编程就是将想法抽象,一步一步试错,程序化思维
4、不改变原数组concat、join———split、toString、slice
- slice(从该位开始截取,截取到该位)
-
join(参数是字符串,将数组以参数分割返回字符串,不传是,)
类数组
1、在对象上增加数组push方法,形成类似组,具有数组的形式,类似数组
2、是对象可以当做数组使用
3、隐式的push方法
4、思维拓展 关键点在于length
DOM操作全是类数组的形式
复习
1、包装类
// 原始值没有属性和方法,之所以具有属性的原因是经过了包装类new
var str = "abc";
console.log(str.length) // 3
// 在这个过程中会new String("abc") 这个构造函数上有 点length的属性
// 这个隐式的过程就是包装类,new String(str) 将str隐式的包裹起来
2、原型
-
任何一个函数都有prototype,这个prototype是这个函数构造出对象的公有祖先,祖先上的方法和属性,由这个构造函数构造出的对象都可以使用
3、Object.create(prototupe,特性)创建对象
没有lastName,就去它的父级上寻找
4、this call -
call可以改变函数里this的指向
-
call里面写值的话,就是函数运行时this指向的环境
-
new的时候,this指向是构造函数原型
- 闭包的表现就是函数套函数,将被套的函数弄到外面执行,必然形成闭包
-
通过构造函数生产对象,每次都new一下,执行函数就不用new
5、闭包生成的私有变量,不想让别人进行访问
-
空数组不等于空数组,每个引用值都有独立的地址,虽然长的一样,但是地址不同
6、深度克隆
-
浅层克隆是将obj遍历一遍,将其属性放到obj1上,obj的引用值改变obj1也会改变(因为是同一地址或者引用),这不是想要的,由此得深度克隆
1、深度克隆主要处理引用值,首先分析是不是引用值
2、如果是对象,就新建一个,再去处理原有对象里面是什么值,原始值直接使用(相当于备份),引用值在进行判断,因为操作一样就形成了递归
3、这样之间的对象是相互独立的
7、系统规定的undefined和null不能进行隐式类型转换,不能和数字比较,但他两都是false
8、预编译 ,发生在函数执行前
1、生成Ao
2、找函数里面的形参(相当于变量声明,和变量重名时,取一个即可,对象里面不可能有相同属性名)和变量声明,把他们当做AO的属性名并赋值undefined
3、实参形参相统一,将实参值赋给形参
4、找函数声明,将函数声明的名字,作为AO对象的属性名,如果有相同的直接进行覆盖,值为函数体
5、函数执行所访问的变量、修改都是用AO对象里的值
6、接着开始看参数都具有什么值,遇到var 声明和函数声明直接跳过,他们在预编译时已执行
9、凡是var 变量,都删除不了
10、最经典的继承就是圣杯模式
11、优化代码
类和构造函数相似
try catch 捕获异常
1、在try里面发生的错误,不会执行错误后的try里面的代码
2、错误类型
严格模式
-
"use strict"
-
while 可以改变作用域链,使程序执行效率降低,在es5中不支持
- 严格模式下的局部this直接打印为undefined,也就是预编译的过程中this不指向window
-
eval('这里面能将字符传当做代码执行')可以改变作用域
DOM
1、DOM不能直接操作css,可以同过间接样式,行内样式
2、反转
3、选项卡
4、运动
5、键盘操作
6、滑动变色
DOM基本操作(一系列方法的集合)
1、方法操作
- getElementsByTagName 选择标签名,是个类数组,既能当对象使用,又能到数组使用
- getElementsByClassName 选择class名,兼容性不好,ie9以下不支持
- querySelectAll 唯一缺点选择的元素不是实时的,动态添加的数据获取不了
2、节点操作
节点操作没有节操,什么都可操作,无兼容问题,元素节点会有兼容问题
3、节点属性
4、节点类型nodeType
让他更像数组,加个splice
DOM结构树
1、document的构造函数HTMLDocument
2、封装函数,返回元素e的第n层祖先元素节点
3、封装chileren方法
4、返回元素e的第n个元素节点
- 为正一种循环,为负一种循环
-
还有一种先循环,在判断
-
思维开拓
DOM增删改查
1、document.createElement
2、给每个标签设置属性
3、插入元素
日期对象
1、求程序运行的时间 getTime时间戳
2、倒计时可以使用setTime
3、定时器里面的事件不可更改
- 高性能js
- 你不知道的js
-
DOM操作艺术
4、setInterval 会返回数字唯一标识,clear清除的就是所记录的数字
5、清除
操作滚动条
1、横向滚动条距离
- ie9以下 document.body.scorllLeft/document.documentElement.scorllLeft 这两个比较混乱,处理时用+
-
ie9以上 window.pageXOffset
2、封装的方法
3、滚动条滚了400像素,求浏览器顶端到滚动条滚动的位置400px+首屏像素,滚动条滚动的距离就是多摞出来的 或者是 滚动条滚动了400px,此时屏幕的底端距离网页的最顶端的距离 就是400px+首屏
可视区域
-
怪异模式向后兼容,一旦启动(去掉!document html)就不是最新的语法
1、方法的封装
查看几何尺寸
优先(距离有定位的父级)
1、求文档相对相对于定位的坐标
滚动条滚动
- scrollBy 累加滚动距离
- 自动阅读器
这样写有个bug 就是多次点击start时,会不断触发点击事件
- 解决方案
加个开关解决
脚本化css
这里的null获取的是伪元素的值
封装方法getStyle()
事件(交互体验的核心功能)
1、事件处理函数
2、运行环境
封装地方法
3、解除事件处理函数
4、事件处理模型
5、取消冒泡和默认事件
6、事件对象
7、事件委托
8、事件分类
9、事件分类
-
mousedown + mouseup =click
区分click 和 mousedown
10、键盘事件
- keydown 可以监听到所有键盘事件,监听字符按键不准,操作类按键
-
keypress 只能监听到字符(就是aisc码里面对应的)按键
11、文本类
-
input事件相当于v-model
12、窗口
- domTree(先解析img标签,之后异步下载图片) + cssTree = renderTree,先看完domTree,在看cssTree,深度(纵向,看一条枝干)优先
- domTree数的完成代表着解析完成,比不是加载完成
-
domTree一旦改变,renderTree需要重新构建(效率比较低)
-
重绘影响比较小,改变的是css
- 等到所有图片、资源下载完成onload才执行
拖拽
1、left不给值的话是auto,默认给个0
2、e.pageX和e.pageY是鼠标位置
3、鼠标按下在执行鼠标移动事件
4、鼠标抬起取消事件
5、因为left和top的位置是盒子的左上角,所以需要重新计算
6、鼠标每秒可以移动一百次但是对我们对事件的监听达不到一百次,鼠标移出盒子外面是监听不到的,所以绑定在docuemnt上
json 是对象
1、转换
2、字符串json
异步加载
-
发生在页面解析完时
-
加载完执行
-
创建script
-
状态码已经完成
-
回调函数执行后才执行test
时间线
-
document.write() 具有消除文档流的操作
1、创建docuement对象(1)
2、文档解析完成(2,3,4,5)
3、文档解析完并且加载完毕(6-10) -
触发三个状态
正则表达式
1、\转义成文本
2、\n回车
3、\t table
4、正则处理字符串
5、\abc\ 定义规则,red.test(str)意思是正则测验下字符串里面含不含有我规定的片段
6、正则里面的加i忽视大小写,加g是全局,加m是多行匹配
7、match和test是相反的,test是正则的属性返回true&false,math是字符串的属性str.match(reg),返回值是个数组
8、[]方括号是表达式,代表一位(或者是一个范围),一个表示式就是一位,里面是区间,比如cd,就是c到d,^放在中括号里面代表非,其他地方代表以什么什么开头
9、解析
- 第一位不是a的匹配2位
- 第二位不是b的匹配2位
10、元字符
-
w
-
d
-
s
-
b
-
t
-
量词 n*量词
-
贪婪原则(能匹配多就不匹配少)
-
光标也可以匹配
-
区间匹配
-
实际结果必须是abc才行
-
写一个正则,首尾是否含有数字
-
reg.exec()
lastindex就是游标
-
(会记录括号里面的内容)子表达式,\1反向引用,引用第一个子表达式里面的内容
匹配第一个子表达式里面匹配的内容,
-
\2反向引用第二个子表达式
-
支持正则的string方法
search 但凡不返回的-1都是匹配成功,返回匹配到的位置
split 里面可以写正则,以什么什么分割
replace(老参数,新参数) ,没有匹配全局的能力,replace(正则,“新参数”)
可以放方法,第一个参数值正则匹配的结果,第二个是第一个子表达式内容,第三个是第二个子表达式内容
字符串大小写转换toUpperCase()、toLowerCase()
-
正向预查或者正向断言
-
非贪婪匹配 能有1个绝不多个,在后面加?
-
字符串去重
-
给数字加。
从后往前查,查3的位数个替换的是空,还不能是单词边界