this关键字是javascript中最复杂的机制之一。它是一个很特别的关键字,被自动定义在全部函数的做用域中。this既不指向函数自己也不指向函数的语法做用域。
this是在函数被调用时发生的绑定,this的绑定和函数声明的位置没有任何关系,它指向什么彻底取决于函数在哪里被调用。
javascript
调用位置:是函数在代码中被调用的位置,而不是声明的位置。
* 默认绑定 * 隐式绑定 * 显式绑定 * new绑定 优先级排序:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
没法应用其它规则时的默认规则
若是使用严格模式(strict mode),则不能将全局对象用于默认绑定,所以this会绑定到undefined。
最经常使用的函数调用类型:独立函数调用。java
function foo(){ console.log(this.a) } var a = 2; foo() //2 >函数调用时应用了this的默认绑定,所以this指向全局对象 'tips: 声明在全局做用域中的变量就是全局对象的同名属性。' //严格模式 example 1 function (){ "use strict"; console.log(this.a) } var a = 2; foo(); //TypeError:this is undefined //严格模式 example 2 function foo(){ console.log(this.a) } var a = 2; (function(){ "use strict"; foo(); //2 })();
隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
当函数引用上下文对象时,对象属性引用链中只有上一层或者说最后一层在调用位置中起做用。es6
//example 1: function foo(){ console.log(this.a) } var obj = { a: 2, foo: foo } obj.foo();//2 //example 2: var obj2 = { a: 42, foo: foo } var obj1 = { a: 2, obj2: obj2 } obj1.obj2.foo();//42
直接指定this的绑定对象称为显式绑定
常见的显式绑定方法有 call()
和 apply()
编程
call和apply的使用方法: function.call(thisArg, arg1, arg2, ...) //thisArg 在 f unction 函数运行时使用的 this 值 //arg1, arg2, ... 指定的参数列表。 func.apply(thisArg, [argsArray]) //thisArg 在 f unc 函数运行时使用的this值, //若是这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。 //argsArray 一个数组或者类数组对象,其中的数组元素将做为单独的参数传给'func'函数, //若是该参数的值为 null 或 undefined,则表示不须要传入任何参数。 两者区别 call()方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组。
function foo(){ console.log(this.a) } var obj={ a: 2 } foo.call(obj); //2 调用foo时强制把它的this绑定到obj上
装箱
:若是你传入了一个原始值(字符串类型、布尔类型或数字类型)来看成this的绑定对象,这个原始值会被转换成它的对象形式(也就是new String(...)、new Boolean(...)或new Number(...))segmentfault
1>硬绑定 //硬绑定--显式的强制绑定 function foo(){ console.log(this.a) } var obj = { a:2 } var bar = function(){ foo.call(obj) } bar(); //2 //硬绑定--硬绑定的使用场景就是建立一个包裹函数,负责接收参数并返回值 function foo(something){ console.log(this.a,something); return this.a + something; } var obj={ a: 2 } var bar=function(){ return foo.apply(obj,arguments) } var b = bar(3); //2 3 console.log(b); //5 //硬绑定--另外一种使用方法是建立一个能够重复使用的辅助函数 function foo(something){ 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 bar = bind(foo,obj); var b = bar(3) //2 3 console.log(b) //5 //因为硬绑定是一种很是经常使用的模式,因此ES5提供了内置的方法Function.prototype.bind function foo(something){ console.log(this.a,something) return this.a+something } var obj={ a:2 } var bar = foo.bind(obj); //bind(...)会返回一个硬编码的新函数,它会把你指定的参数设置为this的上下文并调用原始函数 var b=bar(3); //2 3 console.log(b); //5 bind(...)的功能之一就是能够把除了第一个参数(第一个参数用于绑定this)以外的其余参数都传给下一层的函数 2>API调用的“上下文” 第三方库的许多函数,以及Javascript语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,一般被称为“上下文”(context),其做用和bind(...)同样,确保你的回调函数使用指定的this。
在Javascript中,构造函数只是一些使用new操做符时被调用的函数
。它们并不会属于某个类,也不会实例化一个类。它们只是被new操做符调用的普通函数。实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。
数组
function foo(a){ this.a = a } var bar = new foo(2) console.log(bar); //2
使用new调用函数,或者说发生构造函数调用时,会自动执行下面的操做:
一、建立(或者说构造)一个全新的对象
二、这个新对象会被执行[[Prototype]]链接
三、这个新对象会绑定到函数调用的this
四、若是函数没有返回其余对象,那么new表达式中的函数调用会自动返回这个新对象安全
一、若是你把null或者undefined做为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
一种安全的作法是传入一个特殊对象,把this绑定到这个对象不会对你的程序产生任何反作用。
在Javascript中建立一个空对象最简单的方法都是Object。create(null)。Object。create(null)和{}很像,可是并不会建立Object.prototype这个委托,因此它比{}更空。app
二、有可能建立一个函数的“间接引用”,在这中状况下,调用这个函数会应用默认绑定规则。编程语言
function foo(){ console.log(this.a) } var a =2 var o = { a: 3, foo: foo } var p = { a: 4 } 0.foo(); //3 (p.foo = o.foo)(); //2 >>p.foo = o.foo的返回是目标函数的引用,所以调用位置是foo()而不是p.foo()或者o.foo()
三、软绑定 Function.prototype.softBind函数
if(!Function.prototype.softBind){ Function.prototype.softBind = function(obj){ var fn = this; //捕获全部的 curried 参数 var curried = [].slice.call(arguments,1); var bound = function(){ return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply(curried,arguments) ) } bound.prototype = Object.create(fn.prototype) return bound } }
以前介绍的4条规则能够包含全部正常的函数,可是在es6中介绍了一种没法使用这些规则的特殊函数:箭头函数。
即Currying的音译。Currying是编译原理层面实现多参函数的一个技术。
Currying 为实现多参函数提供了一个递归降解的实现思路——把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数
,在某些编程语言中(如 Haskell),是经过 Currying 技术支持多参函数这一语言特性的。
先找到这个函数的直接调用位置,而后顺序应用下面这4条规则判断this的绑定对象:
文章摘取来源:《你不知道的JavaScript上卷》