JavaScript - 基础笔记梳理

935 阅读16分钟

备战秋招,复习基础。如有错误,欢迎批评指正,共同进步!

基础知识

基本概念

javaScript
\begin{cases}
核心 & ECMAScript & 提供语言功能\\
文档对象模型 & DOM & 提供访问和操作网页内容的方法和接口\\
浏览器对象模型 & BOM & 提供与浏览器交互的方法和接口
\end{cases}

ECMAScript实现功能的宿主环境
\begin{cases}
web浏览器\\
Node(服务器JS平台)\\
Adobe Flash
\end{cases}

API:应用程序编程接口 application programminng interface

CSS:层叠样式表 cascading style sheets

在HTML中使用JS

  1. 将JS代码直接放入元素内部
<script type="text/javascript">
    function sayHi(){
        alert ("Hi!");
    }
</script>
  1. 引入外部js文件
<script type="text/javascript" src="example.js"></script>

属性:language src charset defer

  1. 延迟/异步
defer="defer" / async

数据类型

数据类型:undefined null boolean number string object

检测数据类型

typeof

alert(typeof "111"); //string
alert(typeof "null"); //object

instanceof

alert(a instanceof Array);
alert(p instanceof RegExp);

数字

是否有穷:isFinite(a) → true

是否可被转为数值:isNan(a) → true

0.1+0.2=0.3000000000004 → 不要测试a+b==0.3

其他进制转十进制:var num = parseInt("数字",进制);

十进制转其他进制:var num = 数字.toString(进制);

运算

前置递增递减与执行语句优先级相等 ++a+b → 先++a再+b

后置递增递减低于执行语句 a+++b → 先a+b 再a++

按位

按位非 ~ 值相当于 -num-1

按位与 &

按位或 |

按位异或 ^

左移 << 2<<5 → 64 -2<<5 → -64

右移 >> 以符号位填充空位

无符号右移 >>> 以0填充空位

逻辑

逻辑非 ! 一定返回布尔值

逻辑与 && 短路操作 不一定返回布尔值 (1true则返2)

逻辑或 || 短路操作 不一定返回布尔值 (1ture则返1) var a = 优先值 || 备用值

\begin{cases}
Inf * 0 = NaN & Inf * a = Inf\\
Inf / Inf = NaN & 0 / 0 = NaN & a/0=Inf\\
Inf \% Inf = Nan & Inf\%a=NaN & a\%0=NaN & a\%Inf=a\\
5+"5"=55 & 5-"3"=2
\end{cases}

null与undefined的异同点

  • 相同:

    1 if语句中,值为false

    2 都代表“无”

  • 差异:

    1 toNumber null→0 undefined→NaN

    2 undefined代表调用一个值,而该值没有赋值

    3 null常作为参数传入(说明该参数不是对象)

    4 设为null的变量或对象会被内存收集器回收

语句

do-while

do{
    statement
}while(expression)

while

while(expression){
    statement;
}

for

for (初始;限制;计数){
    statement;
}

for-in 精准迭代

for (property in expression) statement

添加标签

label:statement

with 将代码的作用域设置到特定对象中(严格模式不允许)

with (expression) statement;

switch语句在比较值时使用的是全等操作符,因此不会发生类型转换

作用域

作用域链:保证对执行环境有权访问的所有变量和函数的有序访问。执行代码所在环境的变量对象→包含环境→...→全局执行环境。内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境的任何变量和函数。

延长作用域链:1. try-catch语句的catch块:创建一个新的变量对象,包含的是被抛出的错误对象的声明。2.with语句:将指定的对象添加到作用域链中。

TBC

垃圾收集

  1. 标记清除
  2. 引用计数
  3. 管理内存:将不使用的数据设为null解除引用

引用类型(对象)

引用类型的值(对象)是引用类型的一个实例。

复制引用类型标量时,实际复制指针,指向同一对象。

object

创建新对象

  1. new操作符
var person = new Object();
  1. 对象字面量
var person = {
    name : "nic",
    age : 29
}
或
var person = {};
person.name = "nic";

person["first"]person.name等价

合并一个或多个对象

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

Array

创建新数组

  1. Array构造函数
var colors = new Array();
或
var colors = Array(3);
  1. 字面量表示法
var colors = ["red","blue","green"];

length

在末尾添加项colors[colors.length] = "red"

在末尾移除项colors.length = 2 → 移除前3项,移除后2项,被移除变为undefined

检测

Array.isArray(value) → 不管在哪个全局执行环境创建都可以判断

栈和队列

count = color.push("red"); 返回个数(末端插入)
item = color.pop(); 返回弹出项(末端)
count = color.unshift("red"); 返回个数(前端插入)
item = color.shift(); 返回弹出项(前端)

操作

转换:

join()   →  join("分隔符")
toLocalString() 
toString() 返回由数组中每个值的字符串形式拼接而成的以一个逗号分隔的字符串
valueOf() 返回数组本身

重排序:

reverse() 反转数组项顺序
sort() → sort(compare) → compare方法返回0 1 -1 → 第一个值在第二个值之前 返回-1

修改(会创建新数组):

concat() 创建当前数组的副本,将参数添加到副本末尾,返回新数组
slice(起始,末尾) 返回起始和结束位置之间且不包括结束位置的项的新数组
splice(起始,删除项数,插入项) 返回删除的项

位置:

indexOf(要查找的项,查找起点位置索引) 返回位置,无则-1
lastIndexOf(要查找的项,查找起点位置索引) 返回位置,无则-1

迭代:

every() 对数组每一项运行函数,都为true则返true
filter() 对数组每一项运行函数,返回为true的项组成的数组
forEach() 对数组每一项运行函数,无返回
map() 对数组每一项运行函数,返回每次函数调用结果组成的数组
some() 对数组每一项运行函数,存在一项为true则返true

归并:

reduce(函数,初值) 迭代数组所有项,构建最终返回值
reduceRight()

Date

创建新日期

var now = new Date();

用Date.parse创建指定日期

var someDate = new Date(Date.parse("May 25, 2004"));
或
var someDate = new Date("May 25, 2004");

用Date.UTC创建指定日期

var y2k = new Date(Date.UTC(2000,0)); //GMT时间2000年1月1日午夜零时
var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55)); //GMT时间2005年5月5日下午5:55:55 月份基数为0!

Date.now()var start =+new Date() → 返回调用这个方法时的日期和时间的毫秒数

RegExp 正则表达式

创建正则表达式

var expression = /pattern / flags ;

flags

  • g:全局模式,即模式将应用于所有字符串,在发现第一个匹配项时不停止;
  • i:不区分大小写;
  • m:多行模式,即在到达一行文本末尾时还会继续查找下一行是否存在与模式匹配的项。

实例方法

pattern.exec(text); 返回第一个匹配项信息的数组,或null
pattern.test(text); 匹配返回true,否则为false
toLocaleString()和toString()会返回正则表达式的字面量
valueOf()返回正则表达式本身

基本包装类型

使基本类型值拥有方法。调用方法时,后台自动处理:

1 创建String类型的一个实例
2 在实例上调用指定的方法
3 销毁这个实例

Boolean

Number

转化为科学计数法:toExponential(小数位数)

固定位数,包括小数和整数:toPrecision(位数)

String

字符方法

访问字符串中指定字符

charAt();返回字符
charCodeAt();返回字符编码

字符串方法

拼接 concat() 返回拼接得到的新字符串,不改变原来字符串

子串 slice(开始,结束); substr(开始,字符个数); substring(开始,结束) 传入负值时不同!

查找 indexOf() lastIndexOf()

删除空格trim() trimLeft() trimRight()

大小写转换 toLowerCase() toUpperCase()

模式匹配

match() 返回数组 → matches = text.match(pattern)与pattern.exec(text)相同
search() 返回索引
repleace(字符串/正则, 字符串/函数)
split(分割符/正则) 将字符串分割多个字符串放入数组中

eval方法

eval(要执行的字符串)

字符串中任何变量和函数都不会提升,只在eval执行时创建。

Math对象

最大值最小值方法

var values = [1, 2, 3, 4];
var max = Math.max.apply(Math, values); ← 一定记得apply!!!如(this,array)!!

舍入方法

Math.ceil() 向上舍入,取向上最接近的整数
Math.floor() 向下舍入,取向下最接近的整数
Math.round() 标准舍入,取四舍五入最接近的整数

范围内取随机值

selectFrom(最小值, 最大值)
相当于
Math.floor(Math.random()*可能值总数+最小值)

面向对象

对象

对象:无序属性的集合,其属性可以包含基本值、对象或者函数。

数据属性

  • Configurable 能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为访问器属性。
  • Enumerable 能否通过for-in循环返回属性。
  • Writable 能否修改属性的值。
  • Value 包含这个属性的数据值。默认undefined

修改属性默认的特性:Object.defineProperty(属性所在对象,属性名字,描述符对象) 如:

Object.defineProperty(person, "name", {
    writeble: false,
    value: "NIC"
});

修改configurable为false后,不可复原

访问器属性

访问器属性不包含数值

  • Configurable 能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为数据属性。
  • Enumerable 能否通过for-in循环返回属性。
  • Get 在读取属性时调用的函数
  • Set 在写入属性时调用的函数

访问器属性不能直接定义,必须使用Object.defineProperty():

Object.defineProperty(book, "year", {
    get:function(){
        return this._year;
    },
    set:function(newValue){
        this._year = newValue;
    }
});

其他属性方法

一次定义多个属性

Object.defineProperties(book, {
    _year:{
        writable:true,
        value:2004
        },
    edition:{
        writable:true,
        value:1
        }
    })

读取属性的特性

var descriptor = Object.getOwnPropertyDescriptor(book,"year");

创建对象

工厂模式

构造函数模式

原型模式

组合使用构造函数模式和原型模式

动态原型模式

寄生构造函数模式

稳妥构造函数模式

继承

ECMAScript只支持实现继承,依靠原型链。

原型链

原型链:利用原型让一个引用类型继承另一个引用类型的属性和方法。

所有函数的默认原型都是Object的实例!

通过原型链实现继承时,不能使用对象字面量创建原型方法。

再创建子类型的实例时,不能向超类型的构造函数中传递参数。

继承方法

借用构造函数:在子类型构造函数的内部调用超类型构造函数。

组合继承:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

原型式继承:Object.create(用作新对象原型的对象,(可选)为新对象定义额外属性的对象)

寄生式继承:创建一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后返回对象。

寄生组合式继承(组理想的继承方式):通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

函数表达式

Function函数

函数能够接收任意个参数 arguments对象可以与命名参数一起使用(值保持同步)

所有函数的参数都是按值传递!(引用类型变量传递的是地址)

创建函数

  1. 函数声明语法 提前解析
function sum(a,b){
    return a+b;
}
  1. 函数表达式 到代码行才解析
var sum = function(a,b){  ← 匿名函数
    return a+b;
};注意有分号!
  1. 使用Function构造函数
var sum = new Function ("a","b","return a+b"); 不推荐使用

访问函数的指针而不执行的话,去掉函数名后面的大括号

callee → 指向拥有这个arguments对象的函数

this → 引用函数执行的环境对象

caller → 调用当前函数的函数的引用

属性

length → 函数希望接收的命名参数的个数

prototype → 保存所有实例方法,不可枚举

在特定的作用域中调用函数:

apply(运行函数的作用域, 参数数组); → apply(this,[num1,num2]); 可用arguments
call(运行函数的作用域, 参数); → call(this, num1, num2); 参数必须逐个列举
bind(o); → 创建一个函数的实例,this值被绑定到传给bind()函数的值,this的值等于o

闭包

闭包:有权访问另一个函数作用域中的变量的函数 ← 在一个函数的内部创建另一个函数

当内部函数在外部函数之外被调用时就会形成闭包。

闭包只能取得包含函数中任何变量的最后一个值!

匿名函数的执行环境具有全局性!

内存泄漏

如果闭包的作用域链中保存着一个HTML元素,意味着该元素无法被销毁。

模仿块级作用域

用作块级作用域(私有作用域)的匿名函数语法:

(function(){
    //块级作用域 其中定义的任何变量,在执行结束时被销毁
})(); ← 圆括号会立即调用这个函数
只有函数表达式后面可以跟圆括号 → 函数声明转函数表达式 → 加圆括号

私有变量:任何在函数中定义的变量,都可以认为时私有变量,因为不能在函数外部访问这些变量。

特权方法:有权访问私有变量和私有函数的公有方法。

尾调用:函数最后一步是调用另一个函数。

函数柯里化

参考资料:详解JS函数柯里化

把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

// 普通的add函数
function add(x, y) {
    return x + y
}

// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3

curry的一些性能问题你只要知道下面四点就差不多了:

  • 存取arguments对象通常要比存取命名参数要慢一点
  • 一些老版本的浏览器在arguments.length的实现上是相当慢的
  • 使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
  • 创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上 其实在大部分应用中,主要的性能瓶颈是在操作DOM节点上,这js的性能损耗基本是可以忽略不计的,所以curry是可以直接放心的使用。

经典面试题:

// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9

事件

事件:文档或浏览器窗口中发生的特定交互瞬间

事件流:页面中接收事件的顺序。

IE事件流 - 事件冒泡:事件开始时由最具体的元素接收,逐级向上传播到较为不具体的节点。 <div> → <body> → <html> → document

netscape communicator事件流 - 事件捕获:事件开始时由不太具体的元素接收,逐级向下传播到最具体的节点。意在于在事件到达预定目标前捕获它。document → <htme> → <body> → <div>

DOM事件流:事件捕获(截获事件) → 事件目标 → 事件冒泡(响应事件)

事件对象:在触发DOM上的某个事件时,会产生一个事件对象event,包含导致事件的元素、事件的类型、与特定事件相关的信息

事件代理:利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行。打个比方:一个button对象,本来自己需要监控自身的点击事件,但是自己不来监控这个点击事件,让自己的父节点来监控自己的点击事件。

事件类型

UI事件

load事件:页面完全加载后触发

unload事件:文档完全卸载后触发

resize事件:浏览器窗口宽高调整

EventUtil.addHandler(window, "resize", function(event){
    alert("Resized!")
});

scoll事件:实际表示页面中对应元素的变化

焦点事件

鼠标与滚轮事件

键盘与文本事件

事件监听

addEventListener() removeEventListener()DOM方法,指定元素添加/移除事件句柄

element.addEventListener(指定事件名,触发时执行函数,(可选)是否在捕获或冒泡阶段执行)

表单

提交表单

<input type = "submit" value = "Submit Form">
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function(event){
    event = EventUtil.getEvent(event);
    ...
});

Canvas绘图

基本用法

var drawing = document.getElementById("drawing");

//验证浏览器是否支持<canvas>元素
if (drawing.getContext){
    var context = drawing.getContext("2d");
    
    //绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10,10,50,50);
}

DOM

文档对象类型。是针对HTML和XML文档的一个API。将HTML或XML文档描绘成一个由多层节点构成的结构。

  • Node类型:12种。nodeName / NodeValue

    Document类型:表示HTML文档。作为HTML Dodument实例的document对象。

      `open()`/`close()`打开/关闭流
      `document.write()`在文档流中写入字符串,一旦文档流已关闭,会打开新的文档流,重构DOM并渲染
    

    Element类型:表示XML或HTML元素。提供对元素标签名、子节点、特性访问。

    Text类型:包含可以照字面解释的纯文本内容。

    Coment类型:注释

  • Attribute对象:Attr对象表示html属性

  • Event对象:代表事件发生的状态,与函数结合使用

  • 关系:childNodes / parentNode

  • 操作:

    • 创建:
      • createDocumentFragment() //创建一个DOM片段
      • createElement() //创建一个具体的元素
      • createTextNode() //创建一个文本节点
    • 添加:appendChild()
    • 移出:removeChild()
    • 替换:replaceChild()
    • 插入:insertBefore()
    • 复制:cloneNode(true)
    • 查找:
      • getElementsByTagName() //通过标签名称
      • getElementsByClassName() //通过标签名称
      • getElementsByName() //通过元素的Name属性的值
      • getElementById() //通过元素Id,唯一性
var a = document.getElementById("dom"); 
      del_space(a); //清理空格 
      var b = a.childNodes; //获取a的全部子节点; 
      var c = a.parentNode; //获取a的父节点; 
      var d = a.nextSibling; //获取a的下一个兄弟节点 
      var e = a.previousSibling; //获取a的上一个兄弟节点 
      var f = a.firstChild; //获取a的第一个子节点 
      var g = a.lastChild; //获取a的最后一个子节点

获取页面所有元素

var tags = document.getElementsByTagName('*');  

DOM操作

  • 动态脚本

    <script>元素类似,页面加载时不存在,但将来的某一时刻通过修改DOM动态添加。

  • 动态样式

    <link>加入head中,<style>直接嵌入。

    页面加载完成后动态添加到页面中。

  • 操作表格

    <NodeList> → 对象是实时更新,动态变化的!容易出错!

动态样式 - 画圆

已知条件:圆点坐标(x0,y0),半径r,角度degree

计算:

Math.sin(x) x的正弦值,返回值在-1.0到1.0之间;
Math.cos(x) x的余弦值,返回值在-1.0到1.0之间;
x弧度的计算公式为,2*PI/360*degree

小球圆形运动轨迹:

<style>
    #wrap{position: relative;margin:40px auto;width: 400px;height: 400px;border:1px solid #eee;border-radius: 50%;}
    .ball{position: absolute;top:191px;left:-9px;width:6px;height: 6px;border:6px solid #f60;border-radius:50%;background:#f60;}
</style>
<div id="wrap">
    <div class="ball"></div>
</div>
<script>
 var ball = document.querySelector(".ball");
    var timer ;
    var x0=191,y0=191,r=200,degree=0;
    timer = setInterval(function () {
        degree++;
        var hudu = 2*Math.PI/360*degree;
        var x1 = x0 + Math.sin(hudu)*r;
        var y1 = y0 - Math.cos(hudu)*r;
        ball.style.left = x1 +"px";
        ball.style.top = y1 + "px";
    },50)
</script>

错误与调试

try-catch

try{
    可能错误的代码
}catch(error){
    发生错误时怎么办
}

throw 随时抛出自定义错误,代码立即停止运行

throw new Error("...");