this:关键字
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁。
情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,严格模式下指向undefined。
function a(){ var user = "白白"; console.log(this.user); //undefined console.log(this); //Window } a();
情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
var o = {
user:"白白",
fn:function(){
console.log(this.user); //白白
}
}
o.fn();
情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象。
var o = { user:"白白", fn:function(){ console.log(this.user); //白白 } } window.o.fn();
情况4:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window。
当this碰到return时:
若return的是基本类型或者null时,this指向函数的实例;
但若return对象时,this指向这个对象。
作用域:
储存变量的良好规则,之后可以方便的找到这些变量。
负责收集并维护所以声明的变量组成的一系列查询,并实施一套非常严格的规则,确定当前执行的带卡对这些变量的访问权限。
ES5中只有全局和函数作用域,无块级作用域(ES6新,let,const有关)。
作用域链:
作用域链 即:一变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。过程如下:
· 任何在执行上下文时刻的作用域都由作用域链来实现
· 在一个函数被定义的时候, 会将它定义时刻的scope chain链接到这个函数对象的[[scope]]属性
提升:
函数和变量声明都会被提升(var),但函数首先会被提升,然后是变量。
var getName = function(){
console.log(2);
}
function getName() {
console.log(1);
}
getName(); //2
foo(); //function 函数先被提升,所以取到了函数
var foo;
function foo(){
console.log("function");
}
foo = function(){
console.log("foo = ");
}
foo(); //foo = ,但在函数之后foo()被foo = 覆盖
将变量声明提升到它所在的作用域的最开始。
1.函数体内同名的局部变量或参数的优先级高于全局
2.不用var的均为全局变量,无论在哪里
3.只有函数声明才存在函数提升
闭包:
闭包就是能够读取其他函数内部变量的函数。
如果某个函数被他的父函数之外的一个变量引用,就会形成闭包。
作用:
一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
闭包的作用,就是保存自己私有的变量,通过提供的接口(方法)给外部使用,但外部不能直接访问该变量。
缺点:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
例子(使用闭包):
var test=(function(){ var a=0; return function(){ ++a console.info(a); } })() test();// 1 test();// 2 test();// 3
例子(不使用闭包):
var test=function(){ var a=0; ++a console.info(a); } test();// 1 test();// 1 test();// 1
上面例子形成了闭包,函数被全局调用,函数第一次执行完后,作用域没有被回收机制销毁,所以变量a也被保存下来了,每次调用test,执行后a都会自加1。如果没有形成闭包,每次调用test,执行后a都会销毁染后重新创建,执行结果都为1.
闭包的应用:
1)结果缓存:
我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。
2)封装:
使函数内部的变量外部不可直接访问。
3)实现类和继承:
我们定义一个函数,它就像一个类,我们new一个该函数对象,访问它的方法。
4)ajax的闭包:
需要一个能长期保存下来的变量来确定前一个ajax请求是否完成。
设置一个变量长期存储在内存中,判断当前是否在处理ajax请求。(在处理中判断修改变量的值)
原型,原型链
javascript中一切皆对象,每个对象都有一个__proto_ 属性(由浏览器自动创建),该属性指向它原型。当一个对象在查找一个属性的时,自身没有就会根据__proto__ 向它的原型进行查找,如果都没有,直到查到Object.prototype._proto_为null,这样也就形成了原型链。
那prototype又是什么?!我们知道可以通过构造函数来创造一个类,prototype的作用就是,让类的属性可以被继承。所以只有构造函数才会有prototype这个属性。
实例对象的__proto__指向构造函数.prototype,构造函数.prototype.constructor指向构造函数本身,构造函数.prototype的__proto__指向Object的prototype,Object的prototype的__proto__指向null
判断原型的方法:
instanceof和type of
instanceof用来测试一个对象在其原型链中是否存在一个构造函数的prototype属性。
A(要检测的对象) instance B(某个构造函数) 实现:
var L = A.__proto__; //从A的__proto__向上找
var R = B.prototype;//从A的__proto__向上找
if(L == R){
return ture; //能找到就返回ture
}
type of:
一个值使用typeof操作符会返回下列字符串:
1.Undefinde
2.Functon 如果值是函数
3.Number
4.String
5.Boolean
6.Object 如果值是对象或null