this 关键字
- this指向什么和书写的位置没有关系,和调用方式有关系
- this 是在产生EC时动态绑定的
绑定规则
- 默认绑定 普通函数
- 独立函数调用,可以理解成函数没有被绑定到某个对象上
- 独立函数调用, 函数内部的this指向window
var obj = {name:'boo',fn:function(){console.log(this)}}
var fn = obj.fn
fn() //this → window //独立函数调用
- 隐式绑定 对象的方法
- 通过某个对象进行调用,也就是调用位置是通过某个对象发起的函数调用
- this指向调用者
var obj = {name:'boo',fn:function(){console.log(this)}}
obj.fn() //this → obj
- 显示绑定 函数也是对象
- 函数也是一个对象, 对象是属性的无序集合
- call
- 显示绑定
- 让函数执行 //fn.call(obj)
- call 传参:从第二个参起, 传递的参数就会传递给函数
- apply 和call一样 参数格式不一样 以数组方式传递
function gn(num1,num2){console.log(num1+num2)} let obj = {name:'bool'} gn.call(obj,100,200) gn.apply(obj,[100,200])
- bind
- 显示绑定
- 也可以传参
- 但是函数不会执行
- 返回一个绑定this的新函数
function gn(num1,num2){console.log(this,num1+num2)} let obj = {name:'bool'} var bfn = fn.bind(obj,100,200) bfn() // this 已经指向了obj
- 扩展
function gn(){console.log(this)} gn.call('Hello') //会把Hello包装成一个对象 gn.call(undefined) // 实际上是绑定到window上 gn.call(null) //window gn.call(NaN) // 包装成一个Number对象
- new绑定 函数也是一个类 构造函数/构造器
- 通常情况下 首字母大写
function Person(){ // new 做了什么 // 1. 在函数内部创建了一个对象 // 2. 把函数内部的this绑定到对象上 // 3. 函数执行 // 4. 返回这个对象(new完后,肯定得到一个对象) } // new一个类 得到一个对象 new 是一个运算符 let p1 = new Person() console.log(p1)
内置函数
- 定时器中的this是 window
setTimeout(function(){
console.log(this) // window
},1000)
- 事件监听
<button id='btn'>click</button>
let btn = document.getElementById('btn')
btn.onclick = function(){
//监听器中的this表示事件源
console,log(this) // <button id='btn'>click</button>
}
- 内置方法 forEach map
绑定优先级
默认绑定(独立函数) < 隐式绑定(对象.) < 显示绑定(call,apply,bind)
隐式绑定(对象.) < new绑定
bind绑定 < new绑定
new不能和call apply 比较 call apply函数已经执行 返回值不是一个对象
箭头函数
- 如果形参 小括号可以省略
- 如果函数体中 只有一条语句 {} / return 都可以省略
- 如果返回只有一个对象 如果省略return和{}对象的{}会当成函数的{}
- 如果没有形参 小括号不能省略
let foo = (num1)=>{return{num*2}
let foo = num1=>{return num*2} //省略小括号
let foo = num1=> num*2 //省略return 和{}
let foo = num1=>{return{a:666}} // 如果省略return和{}对象的{}会当成函数的{}
let foo = num1 => ({a:666})
箭头函数中的this
- 箭头函数中的this 需要往上找一层
let gn = function(){console.log(this);}
let fn = ()=>console.log(this)
let obj = {name:'boo'}
gn.call(obj) //{name: 'boo'}
fn.call(obj) //window
fn.call(undefined) //window
- IIFE中的this表示window 前面加分号避免代码执行时产生错误
- 立即执行函数前面都要写个分号 养成习惯
;(function(){console.log(this)})() // window
;(()=>{console.log(this)})() // window
练习题
var num = 10;
var obj = {
num: 20
// 返回一个函数作为obj的属性
}
obj.fn = (function (num) { //传入实参 20
this.num = num * 6; // 这里this指向window--IIFE中的this 此时全局中num变成60
num++; // 在自己EC中找 就是传入的实参变量20 num--21
console.log(num); // 打印21
return function (n) {
this.num += n; // 独立函数调用this指向window num60 -- 65
num++; //在自己EC中找,没找到去函数声明位置的父级EC中找 21--22
console.log(num) //22
}
})(obj.num) //obj.num为20
var fn = obj.fn; // 这里把对象的fn地址赋值给fn 没有调用
fn(5) // 这里调用 独立函数调用 this指向window
console.log(window.num); //65