JavaScript基础知识

最近又把红宝书翻了一遍,顺便整理下基础的东西
前端大坑,现在还是再看看最基础的吧

JavaScript基础整理

类型

基本类型

* number
* string
* boolean
* null
* undefined

引用类型

* object
* array
* function(函数对象)

基本包装类型&特殊引用类型

(p119 不建议显式创建基本包装类型)

* Boolean
* Number
* String

str.tostring()

str.substring()

过程

* 创建实例
* 在该实例上调用制定方法
* 销毁这个实例 

查找字符串中所有字符

1
2
3
4
5
6
7
8
var str = 'hello world'
var posArr = new Array()
var pos = str.indexOf("o")
while(pos > -1) {
posArr.push(pos)
pos = str.indexOf("0",pos+1)
}
console.log(posArr) //[4,7]

基本类型检查测 typeof

用于检测基本类型

1
2
3
4
5
6
7
8
typeof undefined    //undefined
typeof '123' //string
typeof 123 //number
typeof true //boolean
typeof {} //object
typeof [] //object
typeof null //object
typeof console.log //function

引用类型检测

  • Object.prototype.toString.call(arr) //[object Array]
  • arr instanceof Array //true

类型转换

  • 字符串拼接时
    let msg = 100 + 10 //110
    let msg = 100 + ‘10’ //10010

  • if语句判断时

==/===

null == undefined
null !== undefined

内置函数

  1. object
  2. array
  3. boolean
  4. number
  5. string
  6. function
  7. data
  8. regexp
  9. error

数组迭代方法

  1. forEach
  2. every
  3. some
  4. sort //a-b (从小到大) b-a(从大到小)
  5. map
  6. filter

类数组对象转化为数组

Array.prototype.slice.call(arguments,0)

对象API

1
2
3
4
5
for(let key in obj){
if (obj.hasOwnProperty(key)) { //判断是否非原型中属性
console.log(key, obj[key])
}
}

object主要属性和方法

  • constructor //保存着创建当前对象的函数(即构造函数)
  • hasOwnProperty(prototype) //判断属性是否在当前实例中
  • isPrototypeOf(object) //检查传入的对象是否当前对象的原型

垃圾收集

  • 标记清除
  • 引用计数

对象,原型,原型链,继承

执行new的过程

使用new关键字调用函数(new ClassA(…))的具体步骤:

  1. 创建空对象;
      var obj = {};
  2. 设置新对象的constructor属性为构造函数的名称,设置新对象的proto属性指向构造函数的prototype对象;
      obj.proto = ClassA.prototype;
  3. 使用新对象调用函数,函数中的this被指向新实例对象:
      ClassA.call(obj);  //{}.构造函数();
  4. 将初始化完毕的新对象地址,保存到等号左边的变量中

创建对象的构造函数模式与原型模式

  • 构造函数模式缺陷:每个方法都在实例上重新创建了
  • 原型模式缺陷:属性与方法被共享,导致引用类型无法保证独立

    原型与构造函数组合创建对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function Ele (id) {
    thi.ele = document.getElementById(id)
    }
    Ele.prototype.html = function (val) {
    let ele = this.ele
    if (val) {
    ele.innerHTML = val
    return this //用于链式操作
    } else {
    return ele.innerHTML
    }
    }
    Ele.prototype.on = function (type, fn) {
    let ele = this.ele
    ele.addEventListener(type, fn)
    return this
    }
    var div = new Ele('div')
    div.html('XXX').on('click',() => {console.log('')})

常用操作

instanceof

instanceof 用于判断对象和函数 (即引用类型)
instanceof是检测对象的原型链是否指向构造函数的prototype对象

proto

指向其构造函数的prototype (指向上一层的原型)

hasOwnProtperty

obj.hasOwnProtperty(property) 检测是否为自身属性(不包含来自原型的属性)

in操作符

property in obj //判断property是否能在对象中访问到

constructorof

实例被创建时同时创建prototype对象,对象会自动获得constructor属性(P155)
subObj.constructorof == super
subObj.constructorof == Object

继承

确定原型与实例关系

  • 实例 instanceof 构造函数
  • 构造函数.prototype.isPrototypeOf(实例)

    (P165)判断构造函数的原型是否在实例的原型链中

原型链继承的例子

1
2
3
4
5
6
7
8
9
10
11
12
function Animal () {
this.eat = function () {
console.log ('animal eat')
}
}
function Dog () {
this.sleep = function () {
console.log('dog sleep')
}
}
Dog.prototype = new Animal () //原型链继承
let keji = new Dog()

存在的问题

1. 引用类型被共享 
2. 无法传递参数(若传递参数,则其他实例也会受影响)

借用构造函数

1
2
3
4
5
6
7
8
9
function SuperType (name) {
this.name = name
this.color = ['red','blue','black']
}
function SubType (name) {
//继承Super
SuperType.call(this, name)
}
let instance = new SubType('Nic')

存在问题

1. 方法在构造函数中,无法复用
2. 超类中原型中定义的方法,子类无法使用

组合继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function SuperType (name) {
this.name = name
this.color = ['red','blue','black']
}
SuperType.prototype.sayname = function () {
alert(this,name)
}
function SubType (name, age) {
//继承Super属性
SuperType.call(this, name)
}
SubType.prototype = new SuperType()
SubType.prototype.constructor = Subtyppe
SubType.prototype.sayage = function () {
alert(this.age)
}

let instance = new SubType('Nic','20')

函数

callee&caller

arguments.callee //指向arguments的对象函数本身,可用于递归
arguments.callee.calller&fun.caller //指向该函数引用(alert(fun.caller))

this

根据函数执行来确定
call(obj,param1,param2)
apply(obj,arguments)
箭头函数

this的指向问题

apply&call

  • appply(this.arguments)
  • call(this,param1,param2)

闭包的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function isFirstLoad () {
var _list = [] //私有变量
return function (id){
if (_list.indexOf(id) >= 0){
return false
} else {
_list.push(id)
return true
}
}
var firstLoad = is FirstLoad()
firstLoad(10) //true
firstLoad(10) //false
firstLoad(20) //true

10个li点击的应用

1
2
3
4
5
6
7
8
9
10
11
//错误方法
var i,a
for (i = 0;i < 10;i++) {
a=document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function (e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//正确方法(不传入变量i也可以)
var i
for (i = 0;i < 10;i++) {
(function (i){
var a
a=document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function (e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
})(i)

}

闭包中this指向(P182)

1
2
3
4
5
6
7
8
9
var obj = {
name: 'summerscar',
sayName: function () {
return function () {
return(this)
}
}
}
console.log(obj.sayName()()) //window

块级作用域(私有作用域)

1
2
3
4
(function(){
//此处为块级作用域
})()
//相当于建立一个自执行的函数作为一段代码中语句

相当于这种写法

1
2
3
4
let fn = function() {
//块级作用域
}
fn();

然而这样写会出错

1
2
3
function(){

}() //出错

P185 function作为关键字,会被认定为函数声明,因而不能使用(),而函数表达式可以使用(),为函数加上(fun(){})即可

私有属性(P186)

私有变量

特点:利用构造函数 每个实例拥有自己的属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
function MyObject() {
//私有变量及方法
var privateVar = 10
function privateFun() {
return false
}
//特权方法
this.publicMethod = function() {
privateVar++
return privateFun()
}
}

静态私有变量

特点:利用块级作用域,定义属性,使用函数表达式创建构造函数,方法定义在原型中,每个实例间可以共享方法和属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function(){
var privateVar = 10
function privateFun () {
return false
}

//构造函数
MyObject = function () { }
//特权方法
MyObject。prototype.publicMethod = funtion () {
privateVar ++
return privateFun ()
}

})()

以下两种还不太懂

模块模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var sigleton = function () {
var privateVar = 10
function privateFun () {
return false
}

//返回对象
return {
publicProperty: true,
publicMethod: funtion () {
privateVar ++
return privateFun ()
}
}
}

增强的模块模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var sigleton = function () {
var privateVar = 10
function privateFun () {
return false
}

//创建对象
var object
object.publicProperty: true,
object.publicMethod: funtion () {
privateVar ++
return privateFun ()
}
return object
}

DOM

dom数据结构为树形结构

DOM类型

  • document类型 nodeTyoe: 9
  • Element类型 nodeType: 1
    • 元素标签判断: elem.tagName.toLowerCase() == ‘div’
    • get/set/removeAttribute()自定义属性值
  • Attribute类型 nodeType: 2
  • Text类型 nodeType: 3
    • normalize() 合并两个或两个以上的文本节点
    • splitText(pos)根据pos位置分割文本节点

表格操作的特使方法

>P282

DOM对象节点获取

  • getElementById…
  • querySelector
  • querySelectorAll
  • matchesSelector()
    • el.matchesSelector(“el的CSS选择”) 判断调用元素是否与选择符匹配

自定义属性data

1
2
3
4
5
let div = get.elementById("myDiv")
//获取data-appid的值
var apppid = div.dataset.appid
//设置data-appid的值
div.data.appid = "233"

scrollIntoView() (P298)

//让元素可见(即出现在视口中)
div.scrollIntoView()

Attribute&property

Attribute //标签中属性
property //对象属性

DOM2与DOM3的变化

访问样式

  • 有连词符的需转换为驼峰式写法
  • float为JS的保留字,需写为cssFloat

cssText

  • 读取模式:访问style特性中的CSS代码
  • 写入模式:重写整个style特性的值,以前指定的样式将丢失

BOM

window

navigator.userAgent.indexOf(‘Chrome’)

screen

location

  • assign //下者调用该方法
  • href //完整链接&改变网站地址
  • replace //跳转但不产生记录
  • protocol //http:
  • host // xxx/
  • pathname // /xxx
  • search // ?查询字符
  • hash // #链接
  • reload //刷新 若reload(true),则刷新缓存

history

  • back
  • forword
  • go(num)

事件

冒泡&捕获

DOM2级事件规定的事件流 1.事件捕获阶段2.处于目标阶段3.时间冒泡阶段

事件对象

e.preventDefault //阻止默认事件
e.stopPropatation //阻止事件冒泡

blur与focus的焦点事件不会冒泡

HTML5事件(P388)

  • contentmenu //右击上下文菜单
  • beforeunload //浏览器卸载页面之前
  • DOMContentLoaded //DOM树形成后触发
  • hashchange //url后#后面字符发生变化时

Canvas

合成

  • globalAlpha
  • globalCompositionOperation

HTML5脚本编程

  • video与audio的属性与方法 (P487)

Ajax

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest()
xhr.open("GET", "URL", false)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if(xhr.status == 200){
console.log(xhr.responseText)
}
}
}
xhr.send(null)

readyState

  • 0 未初始化
  • 1 启动 已调用open()
  • 2 发送 已调用send()
  • 3 接收 已接收到部分数据
  • 4 完成

http返回码 status

  • 2xx 成功
  • 3xx 重定向(会自动跳转)
  • 4xx 客户端请求错误
  • 5xx 服务端错误

跨域

条件3个条件 1.协议 2.域名 3.端口

  • CORS
  • jsonp

Jsonp实现原理

1
2
3
4
window.callback = function (data) {
console.log(data)
}
<script src="api.js"></script> //返回 callback({x: 100}) 即调用callback函数

存储

浏览器性能相关

浏览器渲染页面过程

  • 根据HTML结构生成DOM tree
  • 根据CSS生成CSSOM
  • 将DOM和CSSM整合形成RenderTree
  • 根据 RenderTree 开始渲染和展示
  • 遇到 script标签时,会执行并阻塞渲染 (所以script放在body最后,不会阻塞Dom加载)

load & DOMContentLoaded 事件

  • load 页面全部资源加载完成
  • DOM 渲染完即执行,此时图片,视频可能未加载完成

加载资源加载优化

  • 静态资源合并(减少、合并静态资源的加载js,css img base64)
  • 静态资源缓存
  • 使用CDN
  • ssr服务器渲染,数据页面在服务器端完成

渲染优化

  • JS放后面
  • 懒加载
  • 减少DOM查询 (缓存在变量中)
  • 减少DOM操作(尽量合并操作,使用innerHTML操作)
  • 时间节流(事件的延迟执行,如查询时的输入下拉框)
  • 今早执行操作 DOMContentLoaded

安全

  1. XSS 跨站脚本攻击(Cross Site Scripting) 发送数据中包含script代码(替换关键字如/<)
  2. CSRF(Cross-site request forgery跨站请求伪造)伪造正确的链接(电子邮件中隐含的虚假链接,增加验证流程)
    本文简单的介绍Self-XSS(自跨站脚本攻击)、CSRF(跨站请求伪造攻击)和恶意服务器这三种社会工程学的辅助攻击手段, 希望能够给予自认为身处于安全环境中的网民以自知的同时, 学会不惮以最坏的恶意来推测他人.

Self-XSS
XSS(跨站脚本攻击)是一种攻击者在目标网站中嵌入恶意客户端脚本以达到其不可告人目的的攻击行为. 现在大多数的网站都对XSS有所防范, 攻击者已经很难在现代网站上找到可以提交恶意脚本的XSS漏洞.

在XSS前加上Self, 就是Self-XSS(自跨站脚本攻击), 与Self这个词的意思一样, 这是一种需要受害者自己配合才能成功的XSS攻击行为, 这也是它被我归类为一种社会工程学攻击的原因.

受害者出于某种原因, 在目标网站上运行了某段由攻击者提供的恶意脚本, 就使得Self-XSS攻击成立. 一些人看到这里可能会嗤之以鼻, 认为自己不会犯下这么低级的错误, 然而事实却是, Self-XSS可以从各种各样的渠道被实现, 尤其是很多没有代码审查能力的”自称极客”所使用的那些工具, 是的, 我说的就是Bookmarklet、Greasemonkey和其他在浏览器上安装的各种Extension, 它们都有可能被用于Self-XSS攻击, 成功的攻击范例数不胜数.

在Google+打开浏览器控制台, 会发现Google直接打印出了不要在此页面运行脚本的警告, 大多数的现代浏览器的地址栏, 也会在用户粘贴以”javascript:”开头的URL时, 自动去除”javascript:”内容, 可见Self-XSS的危险性.

CSRF
CSRF(Cross-Site Request Forgery)是一种欺骗式的攻击手段, 攻击者会构造一个带有恶意的目标网站的URL, 并引诱受害者点击链接或以其他方式迫使浏览器发出请求来达到攻击者的目的. 是否可以实现CSRF攻击, 与目标网站是否存在可供实现CSRF攻击的漏洞有关. 我们试想这样的一种情况, 目标网站有一个用于删除用户的URL地址, 当然, 只有拥有管理员Cookie的用户才可以通过请求这个URL来删除用户, 攻击者得知这个URL之后, 构造了一个带有欺骗性的链接, 引诱了拥有管理员Cookie的用户的点击, 使得目标用户被成功删除.

在非现代浏览器或同源策略存在漏洞的IE浏览器上, 可能会产生另一种利用带有Cookie的跨站请求实现的CSRF攻击, 不过只要用户使用大部分先进的现代浏览器, 便很难遭遇这种攻击. 另外, 网站开发者如果能严格遵守RESTful的URL规范和CORS协议, 不构建能通过GET请求对数据库进行增减操作的URL, 也能起到对CSRF攻击一定的防范效果.

恶意服务器
恶意服务器指那些被带有恶意的网站管理员控制的服务器, 是一个宽泛的概念, 恶意服务器有多种用法, 包括但不限于以下几种:

记录用户输入的错误密码
事实上, 有很多网站都可能是恶意服务器, 作为用户, 你不知道他们是否会将你在登录时的错误密码记录下来, 对于同时使用很多种密码的人而言, 这是一个巨大的威胁, 一旦你忘记自己在该网站上的密码, 你就会开始尝试自己常用的几种密码, 而在你使用正确的密码登录服务器之前, 你的错误密码已经被网站后台记录下来, 这在之后可能将被用于其他网站数据库的撞库测试.

要想避免这种攻击, 只能让网站本身不传输明文密码, 例如在前端的登录环节里加上一道单向加密, 这样你的明文密码才不会被传到服务器上, 当然, 后端也不能因为前端进行了加密, 就放弃双端加密的基本原则, 否则将得不偿失.

暴露目标用户的真实IP地址
这是一种典型的钓鱼手段, 在用户直接接入互联网的情况下, 如果打开了攻击者提供的网站, 那么用户的真实IP地址就很有可能被暴露给了攻击者, 攻击者就可以以此为基础实行其他的攻击.

不过在中国逐渐局域网化的今天, 这种攻击方式的成功率已经变得越来越低了.

行为记录
用户在网站上的行为, 实际上有可能被一一记录下来, 从这些记录里, 攻击者可以轻易的推算你的作息时间等信息, 网站规模越大, 可能掌握的信息也就越多, 可推测的情报也就越丰富. 一些现代浏览器加入了”防止追踪”的功能, 也是基于同样的考量.

恶意服务器的可怕之处在于你几乎无法知道你访问的是否是一个恶意服务器, 任何一个大网站都有可能是恶意服务器, 但你又不得不去使用它们提供的服务, 你时刻都有可能处于监视之中, 却无法自知.