若是想用好这几个方法,须要先了解this被调用方式不一样而致使值不一样的各类状况,而后就会认识到使用这几个方法的缘由在哪里。(能够指定this的值)
全局上下文中this指向全局对象,函数上下文this取决于被调用的方式es6
例:数组
var a = 3 function exp(){ var a = 4 console.log(this.a) } var b = exp() // 输出3
function exp(){ "use strict" return this } console.log(exp() === undefined) // 输出 true
下面分析各个调用场合下this的值app
上面已经写出了这种状况,值得注意的是,咱们每每并不须要this值为window函数
做为方法被调用时,this指向方法所在的对象上
例:this
var exp = { obj: function context() { var text = "hello" return this } } console.log(exp.obj() === exp) var a = exp.obj() console.log(a === exp) var b = exp.obj console.log(b() === window) //true,,注意这里当对象的方法被全局调用后this是b的this,则是window //均输出 true
咱们知道构造函数建立一个对象的过程code
须要注意的地方:构造函数返回一个非对象类型时,建立新对象时并不妨碍this的使用,也会返回新建立的对象。可是当构造函数显示返回一个对象时就会将这个对象赋值给变量,this的使用则无效。对象
function Fn (){ this.obj = function() { return this } } let a = new Fn() console.log(a.obj() === Fn) // false console.log(a.obj() === a) //true let newObj = { name: "小明" } function reObj (){ this.name = "康康" return newObj } let b = new reObj() console.log(b.name) //小明,返回的对象是newObj
进入正题,在这么多变化中随时均可能出错,因此call()、apply()、bind()就提供了一个能够指定this的方式ci
call()作用域
这个方法接受多个参数,第一个参数是指定的this值,剩下的都是调用的函数的参数列表fn.call(this, arg1, arg2, ...);
若是第一个参数须要是对象,若是传入了数字、字符串、布尔值的话this会指向该原始值的自动包装对象字符串
function f(){ console.log(this) console.log(arguments) } f.call() // window f.call({name:'小明'}) // {name: '小明'}, [] f.call({name:'小红'},1) // {name: '小红'}, [1] f.call({name:'康康'},1,2) // {name: '康康'}, [1,2]
apply()
apply() 与call()区别在于第二个参数接受的是一个包含多个参数的数组,对于一些方法须要传入的参数不能使数组,可使用apply()调用函数使其可使用数组做为参数。
var a = [1,2,3,4,5,6,7,8,9] sum.apply(null,a) //将参数a全都传入,它会把参数做为数组传入。 //求数组的最大元素 Math.max.apply(null,[1,2,6]) // 6
不少使用场景均可以被es6里的扩展运算符替代
bind()
bind()方法建立一个新的函数, 当被调用时,将其this关键字设置为提供的值.
this.name = "大牛" let obj = { name: "康康", age: 18, city:"上海" } let newObj = { name: "小明", sayName: function() { console.log(this.name) } } newObj.sayName()// 小明 let a = newObj.sayName.bind(obj) a() //康康 let b = newObj.sayName b() //大牛
箭头函数
这里说一下箭头函数,由于箭头函数没有this,因此会根据做用域链进行寻找this,这也衍生了不少用法,好比在setTimeout里常常出现的上下文(做用域)问题,若是不使用箭头函数,在函数运行时做用域就变成了全局,使用箭头函数会使函数里用到的this绑定在setTimeout的做用域上
var timer = { fn1() { setTimeout(function(){ console.log(this) }, 10) }, fn2() { setTimeout(()=>{ console.log(this) },20) }, fn3: ()=> { setTimeout(()=>{ console.log(this) },30) } } timer.fn1() //window timer.fn2() // timer timer.fn3() //window //第一个在执行时是在全局调用,至关于 fn1.call(undefined) // 第二个使用箭头函数自身没this,使this 指向了timer // 第三个自身没this的状况下,根据箭头函数的规则找到了最外层全局(window)