淘先锋技术网

首页 1 2 3 4 5 6 7

tips : 本博客示例部分引用至
http://developer.51cto.com/art/200907/136245.htm
http://coolshell.cn/articles/6731.html

js this 指针绑定

对于学过c++的同学,对象方法定义时,并不会显示定义this作为参数,但是在调用时,编译器会默认将this 传入本方法,而此时this指向的是当前实例【对象】

#include <iostream>
using namespace std;

class Person{   

    public  string name;
    private int age;

    public Person(string name,int age) {
        this.name = name;
        this.age = age;
    }

    public void setAge(int age) {
          this.age= age;
    }

    public void sayHellow(){
           cout<< this.name << "say hellow to you" << endl;
    }
 };

python 类的定义,显示指定this参数,但调用类方法时,有编译器默认绑定this 指向当前实例

class people:  

    name = ''
    __age = Null

    def __init__(self,name,age):  
        self.name = name 
        self.__age = age;

    def speak(self):  
        print("%s is %d years" %(self.name,self.__age))  

对于JS这种脚本语言也不例外,函数或者对象方法 被定义时,并不存在this变量,只有函数或对象方法被调用时,this作为参数隐性的传入,这样以来,当前谁调用该函数或对象方法 this指针就指向谁

var name = "Kevin Yang";  
function sayHi(){  
    alert("你好,我的名字叫" + this.name);  
}  
sayHi(); 

此时,sayHi()方法被执行,在js中所有变量,对象,函数都默认归属于window对象,
换句话说,执行sayHi()函数,其实是在执行window对象下sayHi()对象方法 标准写法 window.sayHi() ,只不过window一般可以省略
也就是说 执行sayHi()时,默认将当前对象window传入【将this绑定到window对象】

var name = "Kevin Yang";  
function sayHi(){  
   alert("你好,我的名字叫" + this.name);  
}  
var person = {};  
person.sayHello = sayHi;  
person.sayHello()

此时sayHi()函数引用, 被赋值给person对象的sayHellow属性,当执行sayHello时,当前对象是person,所以this执行person,但是person对象中没有name属性,所以undefined

function sayHi(){  
   alert("当前点击的元素是" + this.tagName);  
}      
<input name="btnTest" type="button" value="点击我" onclick="sayHi()">

当按钮被点击时,实际上执行的是下面代码

document.getElementById("btnTest").onclick = function(){  
    sayHi();  
}  

此时的sayHi()实际上还是 执行widowl.sayHi()所以 sayHi()函数中 this指向的是window对象
可以改进如下:

function sayHi(el){  
   alert("当前点击的元素是" + el.tagName);  
}  

<input name="btnTest" type="button" value="点击我" onclick="sayHi(this)">

改进后执行过程如下:

document.getElementById("btnTest").onclick = function(){  
   sayHi(this);  
}  

临时变量导致的this指针丢失

var Utility = {  
    decode : function(str){  
         return unescape(str);  
    },  
    getCookie : function(key){  
         var value = "i%27m%20a%20cookie";  
         return this.decode(value);  
    }  
};  
alert(Utility.getCookie("identity")) 
var getCookFunc = Utility.getCookie;
alert(getCookFunc("identity")) 

当Utility对象下getCookie方法 赋值给全局变量 getCookFunc后,执行getCookFun()实际上是 window.getCookFun() ,当前对象是window,所以调用getCookFun时,window被默认传入【this指向window对象】


tips : 详细参加本博客参考文档材料,见博客尾部

闭包

闭包使得函数内容定义的局部变量可以被外部访问到
使得局部函数内部的局部变量在函数执行完成后可以继续存在
在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

function greeting(name) {
    var text = 'Hello ' + name; // local variable
    // 每次调用时,产生闭包,并返回内部函数对象给调用者
    return function() { alert(text); }
}
var sayHello=greeting("Closure");
sayHello()  // 通过闭包访问到了局部变量text

当在一个循环中赋值函数时,这些函数将绑定同样的闭包

function buildList(list) {
    var result = [];
    for (var i = ; i < list.length; i++) {
        var item = 'item' + list[i];
        result.push( function() {alert(item + ' ' + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([,,]);
    // using j only to help prevent confusion - could use i
    for (var j = ; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

buildList()函数执行完成后,buildList函数内容定义的局部变量item , i 并没有销毁,因为buildList函数内部定义了匿名函数,并将匿名函数引用压入result列表中,最后返回result列表,赋值给testList函数内部定义的局部变量 fnlist ,
匿名函数【闭包】依赖父函数对象【buildList】,所以只要匿名函数引用还存在,垃圾回收机制就不会销毁buildList函数对象,buildList函数内部定义的局部变量也就依然存在于内存中。
当buildList函数内for循环执行完成后,i=4, item=’item’ + list[3]; 所以当循环执行闭包时,读取的变量i都是4,变量item都是’item’ + list[3]


参考:
http://coolshell.cn/articles/6731.html
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
https://zh.wikipedia.org/wiki/TypeScript
http://bonsaiden.github.io/JavaScript-Garden/zh/#function.closures