函数的内部属性,this引用的是函数据以执行的环境对象。也就是说函数的this会指向调用函数的执行环境。数组
function a(){ return this } console.log( a() === window) //true
函数的 this 关键字在 JavaScript 中的表现略有不一样,此外,在严格模式和非严格模式之间也会有一些差异。闭包
function a(){ 'use strict' return this } console.log( a() === undefined) //true
this作为函数的关键字,指向函数的调用对象。app
大体的指向总结概括为能够分为如下几种:dom
var name = 'window'; function a(){ return this.name } a() ==='window' //true
var obj = { name:'obj', sayName:function(){ return this.name } } console.log( obj.sayName() === 'obj') //true //稍微改动一下;添加下面代码。 var sayName = obj.sayName; console.log( sayName() === 'obj') //false //此时,sayName函数里的this指向了window。 这里须要明白一点,函数名仅仅是一个包含指针的变量,函数是复杂数据类型,因此函数名就只是一个指针,指向堆中的内存地址!因此sayName此时只是复制了指针地址,因此,上面代码改写成下面就很清晰了。 var sayName = function(){ return this.name } var obj = { name:'obj', sayName:sayName } console.log( obj.sayName() === 'obj') //true console.log( sayName() === 'obj') //false
var container3 = document.getElementById('container3') container3.onclick = function(){ //指向节点自己 console.log(this) //<div id="container3">container3</div> }
function A(name){ this.name = name; this.sayName = function(){ console.log(this.name)//指向实例对象 } } var a = new A('aa'); a.sayName(); //aa
var name = 'window' var obj = { name:'obj', fn:function(){ (function (){ console.log(this.name) })() } } obj.fn() //window 普通函数,因为闭包函数是window执行的,因此this指向window; 箭头函数的this指向函数建立时的做用域。 var name = 'window' var obj = { name:'obj', fn:function(){ (()=>{ //改为箭头函数 console.log(this.name) })() } } obj.fn() 改为箭头函数,后能够看出建立时的做用域是obj.fn函数执行是的做用域,也就是obj
js提供了一些能够改变函数执行做用域的方法。由于普通函数若是经过上面的写法来改变this执行时上下文,写法就太过于麻烦。函数
apply:
fn.apply(thisObj,数组参数)
定义:应用某一个对象的一个方法,用另外一个对象替换当前对象
说明:若是参数不是数组类型的,则会报一个TypeError错误。this
call:
fn.call(thisObj, arg1, arg2, argN)
apply与call的惟一区别就是接收参数的格式不一样。prototype
bind:
fn.bind(thisObj, arg1, arg2, argN)
bind()方法建立一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其他的参数将做为新函数的参数供调用时使用。指针
apply的实现: Function.prototype.myApply= function(context){ context.fn = this;//1.将函数挂载到传入的对象 var arg = [...arguments].splice(1)[0];//2.取参数 if(!Array.isArray(arg)) { throw new Error('apply的第二个参数必须是数组') //3.限制参数类型为数组 } context.fn(arg) //4.执行对象的方法 delete context.fn; //5.移除对象的方法 } var obj = { name:'obj' } function sayName(arr){ console.log(this.name,arr) } sayName.myApply(obj,[1,2,3]) //obj [1, 2, 3]
call实现:与apply的惟一区别就是参数格式不一样 Function.prototype.myCall= function(context){ context.fn = this;//1.将函数挂载到传入的对象 var arg = [...arguments].splice(1);//2.取参数 context.fn(...arg) //3.执行对象的方法 delete context.fn; //4.移除对象的方法 } var obj = { name:'obj1' } function sayName(){ console.log(this.name,...arguments) } sayName.myCall(obj,1,2,3,5) //obj1 1,2,3,5
bind在mdn上的实现: Function.prototype.myBind = function(oThis){ if(typeof this !== 'function'){ throw new TypeError('被绑定的对象须要是函数') } var self = this var args = [].slice.call(arguments, 1) fBound = function(){ //this instanceof fBound === true时,说明返回的fBound被当作new的构造函数调用 return self.apply(this instanceof fBound ? this : oThis, args.concat([].slice.call(arguments))) } var func = function(){} //维护原型关系 if(this.prototype){ func.prototype = this.prototype } //使fBound.prototype是func的实例,返回的fBound若做为new的构造函数,新对象的__proto__就是func的实例 fBound.prototype = new func() return fBound }