变量类型和计算

强制类型转换

字符串拼接

`100 + '1' = '101'`

==运算符

1
2
3
100 == '100' // true
0 == '' // true
null == undefined // true

if语句

1
2
3
4
5
6
7
8
9
10
11
12
var a = true
if (a) {
//执行
}
var b = 100
if (b) {
//执行
}
var c = ''
if(c) {
//不执行
}

逻辑运算符

1
2
3
console.log(10 && 0) //0
console.log('' || 'abc') //'abc'
console.log(window.abc)

何时使用 === 和 ==

只有这种情况用==

1
2
3
4
if (obj.a == null) {
// 这里相当于 obj.a === null || obj.a === undefined, 简写形式
// 这是jquery源码推荐的写法
}

原型和原型链

1
2
3
4
5
6
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {};
fn.a = 100;

console.log(obj.__proto__ === Object.prototype) // true

obj的隐式原型 指向 Object的显式原型,因为obj从Object继承而来

遍历对象忽略原型

1
2
3
4
5
6
7
8
var item
for (item in f) {
// 高游览器已经在for in 中屏蔽了来自原型的属性
// 但是这里建议还是加上这个判断,保证程序的健壮性
if (f.hasOwnProperty(item)) {
console.log(item)
}
}

intanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

1
2
3
4
5
6
7
8
9
10
11
12
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// expected output: true

console.log(auto instanceof Object);
// expected output: true

原型链例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Elem(id) {
this.elem = document.getElementById(id)
}

Elem.prototype.html = function (val) {
var elem = this.elem
if(val) {
elem.innerHTML = val
return this
} else {
return elem.innerHTML
}
}

Elem.prototype.on = function (type, fn) {
var elem = this.elem
elem.addEventListener(type, fn)
return this
}

var div1 = new Elem('detail-page');

执行上下文

1
2
3
4
5
6
7
8
9
console.log(a)
var a = 100

fn('zhangsan')
function fn(name) {
age = 20
console.log(name, age)
var age
}
  • 范围: 一段<script>或者一个函数
  • 全局: 变量定义,函数声明
  • 函数: 变量定义,函数申明,this,arguments
    ps: 注意’函数声明’和’函数表达式’的区别

this

先搞明白一个很重要的概念 ———— this的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 ———— 因为this是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子

1
2
3
4
5
6
7
8
9
10
var a = {
name: 'A',
fn: function () {
console.log(this.name)
}
}
a.fn() // this === a
a.fn.call({name: 'B'}) // this === {name: 'B'}
var fn1 = a.fn
fn1() // this === window

this执行会有不同,主要集中在这几个场景中

  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • 用于call apply bind

前两种情况咱们之前都介绍过了,这里只是统一的提出来,汇总一下,不再详细讲了。这里主要说第三种

1
2
3
4
5
function fn() {
console.log(this)
}
fn() // window
fn.call({a:100}) // {a:100} 和 call 同理的还有 apply bind

作用域和闭包

  • 自由变量
  • 作用域链,即自由变量的查找
  • 闭包的两个场景

作用域

作为有 JS 基础的同学,你应该了解 JS 没有块级作用域。例如

1
2
3
4
if (true) {
var name = 'zhangsan'
}
console.log(name)

从上面的例子可以体会到作用域的概念,作用域就是一个独立的地盘,让变量不会外泄、暴露出去。上面的name就被暴露出去了,因此,JS 没有块级作用域,只有全局作用域和函数作用域

1
2
3
4
5
6
7
var a = 100
function fn() {
var a = 200
console.log('fn', a)
}
console.log('global', a)
fn()

全局作用域就是最外层的作用域,如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么他们就全部都在全局作用域中。这样的坏处就是很容易装车。

1
2
3
4
5
// 张三写的代码中
var data = {a:100}

// 李四写的代码中
var data = {x:true}

这就是为何 jquery zepto 等库的源码,所有的代码都会放在(function(){....})()中。因为放在里面的所有变量,都不会被外泄和暴露,不会污染到外面,不会对其他的库或者 JS 脚本造成影响。这是函数作用域的一个体现。

作用域链

首先认识一下什么叫做自由变量。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为自由变量。自由变量如何得到 ———— 向父级作用域寻找。

1
2
3
4
5
6
7
var a = 100
function fn() {
var b = 200
console.log(a)
console.log(b)
}
fn()

如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链

1
2
3
4
5
6
7
8
9
10
11
12
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a)
console.log(b)
console.log(c)
}
F2()
}
F1()

闭包

直接看一个例子

1
2
3
4
5
6
7
8
9
function F1() {
var a = 100
return function () {
console.log(a)
}
}
var f1 = F1()
var a = 200
f1()

自由变量将从作用域链中去寻找,但是依据的是函数定义时的作用域链,而不是函数执行时,以上这个例子就是闭包。闭包主要有两个应用场景:

  • 函数作为返回值,上面的例子就是
  • 函数作为参数传递,看以下例子
1
2
3
4
5
6
7
8
9
10
11
12
function F1() {
var a = 100
return function () {
console.log(a)
}
}
function F2(f1) {
var a = 200
console.log(f1())
}
var f1 = F1()
F2(f1)

XMLHttpRequest

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

跨域

服务器端设置http header

1
2
3
4
5
6
7
response.setHeader("Access-Control-Allow-Origin","http://a.com, http://b.com");
response.setHeader("Access-Control-Allow-Headers","X-Requested-With");
response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");

//接收跨域cookies
response.setHeader("Access-Control-Allow-Credentials", "true");