一、数据类型
1、值类型:undefined, number, string, boolean,不是对象
2、引用类型:函数、数组、对象、null、new Number(10)都是对象
3、引用类型判断(instanceof):
var fn = function () { };
console.log(fn instanceof Object); // true
4、js中对象:数组是对象,函数是对象,对象还是对象。对象里面的一切都是属性,只有属性,没有方法。那么这样方法如何表示呢?——方法也是一种属性。因为它的属性表示为键值对的形式。对象是属性的集合
二、函数和对象
1、函数可以创建对象,函数本身也是对象
既对象通都是过函数创建的;var obj = { a: 10, b: 20 };其中省略了构造函数的步骤而已。
三、prototype
1、函数的prototype:默认的只有一个叫做constructor的属性,指向这个函数本身。也可以新增属性如
2、prototype的Object:
四、_proto_:
1、为什么函数创建的对象可以调用函数的 属性 :
由于fn.__proto__ === Fn.prototype
这里的"__proto__"成为“隐式原型”---既fn.__proto__也最终指向Object,所以每个对象都有一个__proto__属性,指向创建该对象的函数的prototype。
2、Object.prototype:Object也是对象,但它指向null
3、函数的创建:函数也是对象,对象需要函数创建,所以,函数这个对象是由Function创建出来
既为Function创建函数的过程
4、Function:Function也是对象最终指向本身 既Function是被自身创建的,函数与对象的死循环 到此为止
五、instanceof
1、typeof与instanceof :typeof在判断到引用类型的时候,返回值只有object/function,你不知道它到底是一个object对象,还是数组,还是new Number等等。
所以用到instanceof
2、instanceof 的判断规则::Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。
六、继承和原型链;
1、javascript中的继承是通过原型链来体现的:如
其中f1.b是怎么来的呢?——从Foo.prototype得来,因为f1.__proto__指向的是Foo.prototype既:访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链
2、hasOwnProperty:
区分一个属性到底是基本的还是从原型中找到的 如
而hasOwnProperty的来历是:f1--_proto_--Foo.prototype--_proto_--Object.prototype---------->这也就是 继承
3、自定义函数prototype中的方法:
七、执行上下文环境
1、执行上下文:其实就是js预编译的过程,过程完成三个动作
2、上下文环境的产生:全局是一个环境,之后函数每被调用一次,都会产生一个新的执行上下文环境。
3、*变量和作用域:
*变量的值要在生成该变量所在函数的作用域中找。
把fn赋值给f,调用f(),实际调用的是fn()
八、this
1、在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。
2、在构造函数中:
this-->Foo-->f1
this-->Foo-->window
3、函数作为对象属性时:
this-->function-->obj
this-->function-->onj.fn-->fn1-->window
4、被call和apply调用时:
obj继承fn属性并调用fn;this-->fun-->fn-->obj
5、全局 & 调用普通函数
在全局环境下,this永远是window;
this-->fun f-->f-->fn:fun-->obj.fn-->window
最后:this永远指向调用该函数的对象
九、执行上下文栈、作用域
1、正常来讲处于活动状态的执行上下文环境只有一个,新的上下文环境开始预编译,上一个环境就要出栈销毁
2、作用域:javascript没有块级作用域。所谓“块”,就是大括号“{}”中间的语句。例如if语句:
所以,我们在编写代码的时候,不要在“块”里面声明变量,要在代码的一开始就声明好了。以避免发生歧义。
我们在声明变量时,全局代码要在代码前端声明,函数中要在函数体一开始就声明好。
3、作用域的创建:javascript除了全局作用域之外,只有函数可以创建的作用域。作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的。
4、作用域用处:作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
三个作用域下都声明了“a”这个变量,但是他们不会有冲突。
5、作用域的生命周期
作用域在函数定义时就已经确定了。而不是在函数调用时确定。
作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。
所以,如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值。
十、从*变量到作用域链
1、*变量:在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个*变量。
x要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记
——其实这就是所谓的“静态作用域”。
2、作用域链:就是*变量一步一步寻找变量值,直到全局的过程
十一、闭包
1、闭包的使用情况:函数作为返回值,函数作为参数传递。
2、函数作为返回值
bar函数作为返回值,赋值给f1变量。执行f1(15)时,用到了fn作用域下的max变量的值。
3、函数作为参数传递
fn函数作为一个参数被传递进入另一个函数,赋值给f参数。执行f(15)时,max变量的取值是10,而不是100。
4、闭包:
执行完第17行,fn()调用完成。按理说应该销毁掉fn()的执行上下文环境,但是这里不能这么做。注意,重点来了:因为执行fn()时,返回的是一个函数。函数的特别之处在于可以创建一个独立的作用域。而正巧合的是,返回的这个函数体中,还有一个*变量max要引用fn作用域下的fn()上下文环境中的max。因此,这个max不能被销毁,销毁了之后bar函数中的max就找不到值了。
执行到第18行时,全局上下文环境将变为活动状态,但是fn()上下文环境依然会在执行上下文栈中。另外,执行完第18行,全局上下文环境中的max被赋值为100。
执行到第20行,执行f1(15),即执行bar(15),创建bar(15)上下文环境,由于fn没有销毁,仍然能找到max=10。
所以,使用闭包会增加内容开销。