Javascript高级程序设计
最近想把Javascript再撸一篇,加深理解。所以在啃
Javascript高级程序设计
。在这里记录下那些易遗忘的知识点记录下来,方便以后回顾。会一直更新。
1.浏览器作用
浏览器的主要功能就是向服务器发出请求,在浏览器窗口中展示您选择的网络资源。这里所说的资源一般是指 HTML 文档,也可以是 PDF、图片或其他的类型。资源的位置由用户使用 URI(统一资源标示符)指定。
2.浏览器高层结构
1. 用户界面 - 包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面。
2. 浏览器引擎 - 在用户界面和呈现引擎之间传送指令。
3. 呈现引擎 - 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
4. 网络 - 用于网络调用,比如 HTTP请求。其接口与平台无关,并为所有平台提供底层实现。
5. 用户界面后端 - 用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
6. JavaScript 解释器。用于解析和执行 JavaScript 代码。
7. 数据存储。这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。
3.主流程
呈现引擎将开始**解析 HTML 文档**,并将各标记逐个转化成“内容树”上的 DOM 节点。同时也会解析外部 CSS 文件以及样式元素中的样式数据。HTML 中这些带有视觉指令的样式信息将用于创建另一个树结构:呈现树。
呈现树包含多个带有视觉属性(如颜色和尺寸)的矩形。这些矩形的排列顺序就是它们将在屏幕上显示的顺序。
呈现树构建完毕之后,进入“布局”处理阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标。下一个阶段是绘制 - 呈现引擎会遍历呈现树,由**用户界面后端层将每个节点绘制出来。
需要着重指出的是,这是一个渐进的过程。为达到更好的用户体验,呈现引擎会力求尽快将内容显示在屏幕上。它不必等到整个 HTML 文档解析完毕之后,就会开始构建呈现树和设置布局。在不断接收和处理来自网络的其余内容的同时,呈现引擎会将部分内容解析并显示出来。
4.什么是JavaScript解析引擎?
简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序。比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2。
学过编译原理的人都知道,对于静态语言来说(如Java、C++、C),处理上述这些事情的叫编译器(Compiler),相应地对于JavaScript这样的动态语言则叫解释器(Interpreter)。这两者的区别用一句话来概括就是:编译器是将源代码编译为另外一种代码(比如机器码,或者字节码),而解释器是直接解析并将代码运行结果输出。比方说,firebug的console就是一个JavaScript的解释器。
但是,现在很难去界定说,JavaScript引擎它到底算是个解释器还是个编译器,因为,比如像V8(Chrome的JS引擎),它其实为了提高JS的运行性能,在运行之前会先将JS编译为本地的机器码(native machine code),然后再去执行机器码(这样速度就快很多),相信大家对JIT(Just In Time Compilation)一定不陌生吧。
我个人认为,不需要过分去强调JavaScript解析引擎到底是什么,了解它究竟做了什么事情我个人认为就可以了。对于编译器或者解释器究竟是如何看懂代码的,翻出大学编译课的教材就可以了。
这里还要强调的就是,JavaScript引擎本身也是程序,代码编写而成。比如V8就是用C/C++写的。
5. JavaScript解析引擎与ECMAScript是什么关系?
JavaScript引擎是一段程序,我们写的JavaScript代码也是程序,如何让程序去读懂程序呢?这就需要定义规则。比如,之前提到的var a = 1 + 1;,它表示:
左边var代表了这是申明(declaration),它申明了a这个变量
右边的+表示要将1和1做加法
中间的等号表示了这是个赋值语句
最后的分号表示这句语句结束了
上述这些就是规则,有了它就等于有了衡量的标准,JavaScript引擎就可以根据这个标准去解析JavaScript代码了。那么这里的ECMAScript就是定义了这些规则。其中ECMAScript 262这份文档,就是对JavaScript这门语言定义了一整套完整的标准。其中包括:
var,if,else,break,continue等是JavaScript的关键词
abstract,int,long等是JavaScript保留词
怎么样算是数字、怎么样算是字符串等等
定义了操作符(+,-,>,<等)
定义了JavaScript的语法
定义了对表达式,语句等标准的处理算法,比如遇到==该如何处理
⋯⋯
标准的JavaScript引擎就会根据这套文档去实现,注意这里强调了标准,因为也有不按照标准来实现的,比如IE的JS引擎。这也是为什么JavaScript会有兼容性的问题。
简单的说,ECMAScript定义了语言的标准,JavaScript引擎根据它来实现,这就是两者的关系。
6.input="type='number'"会有滚轮
去除浏览器默认样式
input::-webkit-outer-spin-button, //谷歌浏览器
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type="number"] { //火狐浏览器
-moz-appearance: textfield;
}
7.javascirpt严格模式use-strict
严格模式为javascript定义了一种不同的解析和执行模型。在严格模式下,ECMAscript3中的一些不确定的行为将得到处理,而且对某些不安全的操作也会抛出错误。给未经申明的变量赋值在严格模式下会报ReferenceError 错误。
1.脚本顶部:"use strict";
2.函数体顶部:function doSomething(){
"use strict";
}
8.NaN
JS中,0除以0是NaN
,正数除以0为Infinity
,负数除以0为-Infinity
因此不会影响其他代码的执行。
- [x] 任何涉及NaN的操作都将返回NaN
- [x] NaN与任何值都不相等,包括自身
console.log(NaN == NaN); //false
isNaN()
函数用来判断参数不是一个数,该函数还将会把参数尝试着转成数值,再去判断
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false 10
alert(isNaN("10")); //false 10
alert(isNaN("blue")); //true
alert(isNaN(true)); //false 1
9.break
continue
break语句会立即退出循环,强制执行循环以后的语句。
continue语句虽然也是退出循环,但退出循环后,会退出循环从循环的顶部继续执行
//break
var num = 0;
for (var i=1; i < 10; i++) {
if (i % 5 == 0) {
break;
}
num++;
}
console.log(num); //4
//containue
var num = 0;
for (var i=1; i < 10; i++) {
if (i % 5 == 0) {
continue;
}
};
console.log(num); //8
10.基本数据类型
、引用数据类型
1.在js中分为基本数据类型和引用数据类型
2.基本数据类型保存那些基本数据片段,而引用数据类型中保存着对堆内存中对象的引用,是一个指针。与其他语言的不同是,你不可以直接访问堆内存空间中的位置和操作堆内存空间。只能操作对象在栈内存中的引用地址。
3.引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象。
4.在将一个保存着基本数据类型的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。
5.在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。(这里要理解的一点就是,复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量罢了)。多了一个指针。
6.可以为引用数据类型值添加属性和方法,不可以为基本数据类型值添加属性和方法。
资料链接:[资料链接](http://www.cnblogs.com/cxying93/p/6106469.html)
11.typeof
instanceof
`typeof`能够辨别基本数据类型,却无法辨别引用数据类型,只能判断出来是对象,而无法判定是什么类型的对象。
`instanceof`可以判断一个引用数据类型是什么类型的对象。
12.执行环境
执行环境定义了变量或者函数有权访问的的其他数据,每个执行环境都有一个与之关联的变量对象。环境中定义的的所有变量和函数都保存在这个对象中。我们编写代码时,无法去操控这个对象,但解析器在处理数据时,会在后台使用他们。
全局执行环境被认为是window对象,因为所有的全局变量和函数都是被当作属性和方法创建的。
某个执行环境中的所有代码执行完毕后,该环境中的所有变量和函数定义也将被销毁。
每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就被推入一个环境栈中,当函数执行完毕之后,栈将起环境推出,把控制权返回给之前的执行环境。ECMAscript程序的执行流正是由这个机制控制着。
函数在处于执行流时,会沿着作用域链去寻找变量,作用域链的前端始终是当前执行代码所在环境的变量对象下一个变量来自外部环境,再下一个来自下一个包含环境。一层一层往外寻找,当找到第一个符合变量时,不在继续寻找,当没有找到时,会报错。
13.垃圾回收机制
javascript具有垃圾回收机制,执行环境会管理代码执行过程中的内存使用。
原理:找到那些不在继续使用的变量,然后释放其内存。
方式:1.标记清除
这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
2.引用计数
另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。
14.Array.prototype
数组对象的方法,都是通过继承构造函数Array的原型对象方法而来的。可以在浏览器查看window.Array.prototype
一:数组插入和移除数组元素
1.push()
从数组的末尾插入任意多的元素,返回值为新数组长度。
var colors = new Array();
var count = colors.push("red", "green");
console.log(count); //2
2.pop()
从数组末尾移除一项,返回值为被移除的项。
var name = ["tom","jack","tony"];
var result = name.pop();
console.log(result);//"tony"
3.shift()
移除数组的第一项,返回值为被移除的项。和pop对立!
var name = ["tom","jack","tony"];
var result = name.shift();
console.log(result);//"tom"
4.unshift()
从数组的开头插入任意多的元素,返回值为新数组长度。和push()对立!
var colors = ["javascript","css","html"];
var count = colors.unshift("jquery", "vue");
console.log(count); //5
二:数组排序
1.sort(function)
sort排序并不会按照我们的意愿去排列数组,如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串toString(),以便进行比较。
要想按照我们人为的意愿,对数值数组进行排序:
可使用:arrayObj.sort(function(a,b){
return a-b;
})
2.reverse()
reverse会把数组中的元素颠倒过来。
三:数组截取
1.slice(a,b)
slice为数组截取,有两个参数,即是返回项的起始和结束位置。当只有一个参数时,会从当前数组项截取到数组末尾。当两个参数时,返回起始和结束项位置的元素,但是不包括结束位置的项。slice方法不影响原始数组。
2.splice(a,b,c)
1.删除-用于删除元素,两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数)
2.插入-向数组指定位置插入任意项元素。三个参数,第一个参数(插入位置),第二个参数(0),第三个参数(插入的项)
3.替换-向数组指定位置插入任意项元素,同时删除任意数量的项,三个参数。第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项)
四:位置方法
indexOf/lastIndexOf
分别为从数组的第一个元素和数组的最后一个元素查找特定项,返回值为查找的项在数组中的位置。
var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.indexOf(4)); //3
console.log(numbers.lastIndexOf(4)); //5
五:迭代方法
1、every(): 对数组中的每一项运行给定的函数,如果该函数对每一项都返回true,则结果返回true。
2、filter(): 对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
3、forEach(): 对数组中的每一项运行给定函数,这个方法没有返回值。
4、map(): 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
5、some(): 对数组中的每一项运行给定函数,如果该函数任意一项返回true,则返回true。
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
//every,每一项是否都满足
var everyResult = numbers.every(function(item, index, array) {
return (item > 2);
});
//some,是否有一些满足
var someResult = numbers.some(function(item) {
return (item > 2);
});
console.log(everyResult); //false
console.log(someResult); //true
//filter,找到符合条件的项
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var filterResult = numbers.filter(function(item) {
return (item > 2);
});
console.log(filterResult); \\[3, 4, 5, 4, 3]
//map,就是对数组中的每一项执行操作,再返回数组
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var mapResult = numbers.map(function(item) {
return (item * 2);
});
console.log(mapResult); //[2, 4, 6, 8, 10, 8, 6, 4, 2]
//forEach和for循环差不多,一般是用来循环数组元素,做一些操作
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
numbers.forEach(function(item, index, arr) {
//这里执行一些操作
});
六:并归
reduce()/reduceRight()
很多时候需要累加数组项的得到一个值(比如说求和)。之前都是用for循环,会很out...
reduce()方法接收一个函数callbackfn作为累加器(accumulator),数组中的每个值(从左到右)开始合并,最终为一个值。第二个参数可选,即是人为的插入并归起始项。
var arr = [0,1,2,3,4];
arr.reduce(function (preValue,curValue,index,array) {
return preValue + curValue;
}); //10
reduceRight()方法和reduce方法雷同,只不过从右边并归开始。
16.元素宽高和位置
- 页面适口大小(即我们看见的页面)
var pageWidth = window.innerWidth,//页面适口宽度
pageHeight = window.innerHeight;//页面适口高度
if (typeof pageWidth != "number"){
if (document.compatMode == "CSS1Compat"){
pageWidth = document.documentElement.clientWidth;
pageHeight = document.documentElement.clientHeight;
} else {
pageWidth = document.body.clientWidth;
pageHeight = document.body.clientHeight;
- 窗口位置
var leftPos = (typeof window.screenLeft == "number") ?
window.screenLeft : window.screenX;//窗口距左
var topPos = (typeof window.screenTop == "number") ?
window.screenTop : window.screenY;//窗口距右
- 元素
原生js中:
offsetHeight/offsetWidth:带边框高/宽
clientHeight/offsetWidth:不带边框高/宽
offsetTop/offsetLeft:相对视窗的上边/左边
jQuery中:
$(".box").offset().top/.left:相对视窗的上边/左边(和上面原生js一样)
$(".box").position().top/.left:相对父元素的上边/左边
$(".box").height(num)/width(num):获取/设置一个元素的宽高(不包括边框和padding)
$(".box").innerHeight()/innerWidth():获取一个元素的宽高(包含padding)
$(".box").outerHeight()/outerWidth():获取一个元素的宽高(包含padding和border)
- 事件对象获取目标元素坐标值
$(".box").click(function(e){
e.pageX/pageY:指的是触发事件距离于页面左边和顶端的距离
e.clientX/clientY:指的是触发事件距离于适口左边和顶端的距离
e.offsetX/offsetY:指的是触发事件距离于触发目标左边和顶端的距离
e.screenX/screenY:指的是触发事件距离于屏幕左边和顶端的距离
})