This:
JavaScript的this老是指向一个对象。javascript而具体指向哪一个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。html
this
的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。java
this
其实是在函数被调用时发生的绑定,它指向什么彻底取决于函数在哪里被调用浏览器在理解
this
是什么❓首先必需要找到"调用位置",而后判断符合那种规则。app当一个函数被调用时,会建立一个"执行上下文环境":函数
- 包含函数在哪里被调用 ( 调用栈 ) 。
- 函数调用方法。
- 传入的参数等信息。
this
就是记录的其中一个属性,会在函数执行的过程当中用到。
Function.prototype.call
和 Function.prototype.apply
调用当函数做为对象的方法被调用时,
this
指向该对象oop
// 当函数做为对象的方法被调用时、this指向该对象 var obj = { a:1, getA: function(){ alert(this === obj);//true alert(this.a);//1 } }
另外一条须要考虑的规则是:this
调用位置是 否有上下文 — "对象" ,或者说prototype
是否被某个对象拥有( 包含 )指针
function foo(){ console.log(this.a); } var obj = { a:2, foo:foo } obj.foo(); ## 1:不管是直接在obj中定义、仍是先定义再添加为引用属性,这个函数严格来讲都不属于obj对象。 ## 2:然而,调用位置会使用obj上下文来引用函数,所以你能够说函数被调用时obj对象"拥有"或者"包含"了它。 ## 3:不管咱们如何称呼这个模式,当foo()被调用时,它的落脚点确实指向obj对象。当函数引用有上下文对象时,"隐式绑定"规则会把函数调用中的"this"绑定到这个上下文对象。由于调用foo()时this被绑定到obj,因此this.a和obj.a是同样的 ## 4:对象属性引用链中,只有最后一层( 最顶层 )会影响到调用位置
最多见的隐式绑定问题:
被"隐式绑定"的函数会丢失绑定对象,也就是说它会应用"默认绑定",从而把this绑定到全局对象或者"undefined"上,取决因而否是"严格模式"
解决办法:使用"显示绑定"的方案
call(...)和apply(…)
的"硬绑定"模式
// 丢失案例一:堆内存地址的引用 function foo(){ console.log(this.a); } var obj = { a:2, foo:foo } var bar = obj.foo; var a = "oops,global"; bar();// oops,global ## 虽然bar是obj.foo的一个引用。 ## 可是实际上,它引用的是foo函数自己,是foo函数在堆内存空间的地址(复制的是指针的指向) ## 本质上:bar() == foo(); ## 所以此时的bar()实际上是一个不带任何修饰的函数调用,所以应用了默认绑定。 // 丢失案例二:很是常见而且很是出乎意料的状况(参数传递) function foo(){ console.log(this.a); } function doFoo(fn){ fn(); } var obj = { a:2, foo:foo } var a = "oops,global"; doFoo(obj.foo); ## 参数传递其实"就是"一种隐式赋值,所以咱们传入函数时也会被隐式赋值。
引用类型:引用类型传递的是指针的方向
function setName(obj){ obj.name = 'aaa'; return obj; } var person = new Object(); person.name = 'bbb'; var newPerson = setName(person); console.log(person.name + ' || ' + newPerson.name);
http://www.cnblogs.com/zareb/p/5699571.html
function setName(obj) { obj.name = 'aaa'; var obj = new Object(); // 若是是按引用传递的,此处传参进来obj应该被从新引用新的内存单元 obj.name = 'ccc'; return obj; } var person = new Object(); person.name = 'bbb'; var newPerson = setName(person); console.log(person.name); console.log(newPerson.name);
当函数不做为对象的属性被调用时,也就是咱们常说的普通函数方式,此时的
this
老是指向全局对象。在浏览器的JavaScript
里,这个全局对象是window
对象。
// 使用普通函数时、其内的this老是指向window // 在代码中,getName()是直接使用不带任何修饰的函数引用进行调用的。所以只能使用"默认绑定",没法应用其余规则。 // 若是是严格模式( strict mode ),那么全局对象将没法使用默认规则,所以this会绑定到"undefined"上 // 案例一: window.name = 'globalName'; var getName = function(){ return this.name; } console.log(getName());//globalName // 案例二:引用getName在堆内存中的地址 window.name = 'globalName'; var myObject = { name:'ntscshen', getName:function(){ return this.name; } } var myName = myObject.getName; console.log(myName()); // 案例三:在事件函数内部、有一个局部的方法。此方法被调用时,方法内部的this指向了window document.getElementById('div1').onclick = function(){ console.log(this.id);// 'div1' //var _this = this;// 简单的解决方案 var callBack = function(){ //console.log(_this.id);// 'div1' console.log(this.id);// 'window' } callBack(); } ## 没当你想要把this和"词法"做用域的查找混合使用时,必定要提醒本身,这是没法实现的。
Function.prototype.call
和 Function.prototype.apply
硬绑定的典型应用场景就是:建立一个包裹函数,传入全部的参数并返回接收到的全部值。
// 案例一: function foo(){ console.log(this.a); } var obj = {a:2} var bar = function(){ foo.call(obj); }; bar(); setTimeout(bar,100); bar.call(window); // 咱们首先建立了函数bar(),并在它的内部手动调用了foo.call(obj),所以强制把foo的this绑定到了obj。不管以后如何调用函数bar,它总会手动在obj上调用foo。这种绑定是一种显示的强制绑定,所以称之为"硬绑定" // 案例二: function foo(){ console.log(this.a,something); return this.a + something; } function bind(fn, obj){ return function(){ return fn.apply(obj, arguments); }; } var obj = {a:2}; var b = bar(3); console.log(b); // 因为硬绑定是一种很是经常使用的模式,因此在ES5中提供了内置的方法Function.prototype.bind,它的用法以下