数据类型
- 值类型 boolean undefined string number
- 引用类型 Object null function array
类型判断
值类型 typeof
引用类型 instanceof
1 | var fn = function(){} |
对象
Tip:一切引用类型都是对象,对象是属性的集合
对象是通过函数创建的:1
var object = {a: 1, b:1} // 语法糖
真实情况:1
2
3
4
5var object = new Object();
object.a = 1;
object.b = 1;
console.log(typof Object) // function
原型 prototype
函数是一种对象,每个函数都有一个默认的属性:prototype
这个prototype的值是一个对象(属性的集合), 默认只有一个constructor的属性,指向这个函数本身
1 | var Fn = function(){} |
Fn是一个函数,fn是通过Fn new出来的,这样fn对象就可以访问Fn.prototype中的属性
(问:不new就访问不了?是,但是为什么要new?是不是相当于类和类的实例)
__proto__是隐式属性,这个属性引用了创建这个对象的函数的prototype, 即:1
fn.__proto__ === Fn.prototype
每个函数都有一个prototype原型,每个对象都有一个__proto__隐式原型
(javascript 不希望开发者用到这个proto)
每个对象都有一个__proto__属性,指向创建该对象的函数的prototype
Object.prototype 的__proto__指向null
1 | var o = new Foo(); |
JavaScript 实际上执行的是:
1 | var o = new Object(); |
instanceof
Instanceof 查找规则
Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。
Instanceof的判断规则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false
Instanceof 表达的是一种继承关系,或者原型链的结构1
2
3
4
5
6
7
8
9
10
11
12
function Fn(){}
var fn = new Fn()
fn.a = 10
Fn.prototype.a = 100
Fn.prototype.b = 200
console.log(fn.a)
console.log(fn.b)
fn是通过Fn new过来的,a是fn的基本属性,b从Fn.prototype得来,因为fn.__proto__指向是Foo.prototype
原型链
访问一个对象属性时,先从基本属性上查找,如果没有再沿着__proto__这条链往上找,这就是原型链
判断一个属性是基本属性还是从原型链上查找的,用hasOwnProperty
对象的方法都可以通过prototype扩展
上下文环境
Javascript准备工作:
变量、函数表达式 => 变量的声明,默认赋值为undefined (后期在执行过程中赋值)
this => 赋值 this无论哪个情况都有值,至于值是什么,跟上下文环境有关
函数声明 => 赋值
函数体的执行上下文需要附加
参数 =》 赋值
arguments => 赋值
自由变量的取值作用域 => 赋值
Javascript 在执行一段代码前都会进行一些准备工作来生成执行上下文,这个代码段分三种情况:全局环境,函数体,eval
代码段就是一段文本形式的代码1
2
3
4
5
6
7
8
9
10// 全局:
<script>
alert('123')
</script>
// eval:
eval("alert('123')")
// function :
var fn =new Function("x", "console.log(x)")
函数每被调用一次,都会产生一个新的执行上下文环境
函数在定义的时候(不是调用的时候),就已经确定了函数内部自由变量的作用域
自由变量:
在A作用域中使用的变量x,却没有在A作用域中声明(其他作用域中声明的),对于A作用域来说,x就是一个自由变量。
1 | var a = 10 |
执行上下文环境通俗定义:在执行代码之前,把将要用到的所有的变量都事先拿出来,有的直接赋值,有的先用undefined占个空
js在代码执行过程中,会有数不清的函数调用,每个函数调用会产生多个上下文环境,这么多的上下文环境需要管理,销毁而释放内存(上下文环境执行栈)
this
this在函数中到底取何值,是在函数真正被调用的时候确定的,函数定义的时候确定不了,因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。
this取值一共分四种情况:
构造函数
构造函数是用来new对象的函数,第一个字母大写1
2
3
4
5
6
7function Foo() {
this.name = "test"
console.log(this)
}
var fn = new Foo()
fn.name // test
以上this为即将new出来的对象的
但是如果直接把Foo作为函数调用,this就是window
函数作为对象的一个属性
如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数的this指向该对象。1
2
3
4
5
6
7
8var obj = {
x: 10,
fn: function() {
console.log(this, this.x)
}
}
ojb.fn() // this指向obj对象
如果不是作为obj被调用1
2
3var fn1 = obj.fn
fn1()
那么this就是指向window,this.x为undefined
函数使用call apply调用
当用call apply调用时,this指向被传入的对象1
2
3
4
5
6
7
8
9
10var obj = {
x: 10
}
var fn = function() {
console.log(this)
console.log(this.x)
}
fn.call(obj)
全局&调用普通函数
console.log(this === window) true
普通函数在调用时,其中的this也都是window
执行上下文栈
1 | 执行上下文栈 |
代码段:1
2
3
4
5
6
7
8
9
10
11
12
13
14var a = 10,
fn,
bar = function(x) {
var b = 5
fn(x + b) // 进入fn全局上下文环境
}
fn = function(y) {
var c = 5
console.log(y+c)
}
bar(10)// 进入bar上下文环境
在执行代码之前将创建全局上下文环境
作用域
Js没有块级作用域,就是{}中间的语句 例如if for这些
所以要一开始声明变量 避免歧义
JS除了全局作用域外,只有函数可以创建的作用域
作用域在函数定义的时候就已经确定,而不是调用的时候。(同一个作用域有不同的上下文执行环境)(this取值是函数调用的时候确定的)
如果要查找一个作用域下某个变量的值,就需要找到这个作用域下对应的执行上下文环境,再在其中寻找变量的值
自由变量的取值要到创建这个变量的环境去取,而不是调用(静态作用域)。
如果在全局没找到,则未定义。如果是函数作用域,则去创建该函数的作用域去找
闭包
两种应用情况:
1,函数作为返回值
1 | function fn(){ |
2, 函数作为参数1
2
3
4
5
6
7
8
9
10
11
12
13var max = 10;
var fn = function (x){
if (x > max) {
console.log(x)
}
}
(function(f){
var max = 100
f(15)
})(fn)
// max取值为10 (去创建这个函数的作用域取值)
普通函数别调用完之后,其执行上下文环境将被销毁,其中的变量也会被同时销毁。但是在闭包中,其上下文执行环境不会被销毁
作用域和上下文执行环境:
作用域在函数定义的时候就已经确定,一个函数只有一个作用域,但是随着被调用的不同,会有多种上下文环境
参考学习
学习自:http://www.cnblogs.com/wangfupeng1988/p/3977924.html
注:这个非常不错,墙裂推荐学习