调用时机:函数调用时机不同,结果不同
arguments是一个包含所有参数的伪数组
argument和this是每个函数都有,除了箭头函数
如果不给任何条件,this默认指向window
如果你传的这个this不是对象,那么js会自动帮你封装成对象,比如1,new Number(1)
- 如果不加use strict,js会尽量把你传的东西变成对象,传1变成对象1,传string变成对象string,传undefined会变成全局变量window
function fn(){
console.log(arguments)
console.log(this)
}
//如何传arguments
//调用fn即可传arguments
//fn(1,2,3)那么arguments就是[1,2,3]伪数组
//如何传this
//目前可以用fn.call(xxx,1,2,3)传this和arguments,call传的xxx就是this,只不过xxx会被自动转化成对象
//而且xxx会被自动转化成对象
function f() {
console.log(this);
console.log(arguments)
}
f.call(1,2,3,4) //1就是this,2,3,4就是arguments
- this是隐藏参数
- arguments是普通参数
- this是参数(此结论是个人见解)
假设没有this
let person = {
name: 'frank',
sayHi(){
console.log(`你好,我叫`+person.name)
}
}
//分析
//我们可以用直接保存了对象地址的变量获取'name'
//我们把这种方法简称为引用(如果一个变量保存了一个对象的地址,这就是引用)
//Python代码
person = Person('frank')
person.sayHi()
特点:
//每个函数都接受一个额外的self
//这个self就是传进来的对象,只不过Python会偷偷帮你传对象
//person.sayHi()等价于person.sayHi(person)
//person就被传给self了
JS在每个函数里加了this
- 用this获取那个对象
let person = {
name: 'frank',
sayHi(~~this~~) {
console.log(`你好,我叫`+this.name)
}
}
//person.sayHi()相当于person.sayHi(person),然后person被传给this了(person是个地址),这样,每个函数就能用this获取一个未知对象的引用了
person.sayHi()会隐式地把person作为this传给sayHi,方便sayHi获取person对应的对象
总结:
- 我们想让函数获取对象的引用,但是并不想通过变量名做到
- Python通过额外的self参数做到,JS通过额外的this做到:person.sayHi()会把person自动传给sayHi,sayHi可以通过this引用person
let person = {
name: 'mx',
sayHi(){
console.log(this.name)
}
}
person.sayHi.call({name:1})//1
person.sayHi.call({name:'jack'})//jack
//可以得出,把函数放到对象上面,函数和对象没有任何关系,它们只是恰好出现在一起而已
//person.sayHi.call(person)等价于person.sayHi() //mx
//person.sayHi()这种写法隐藏了太多细节
//所有的函数调用必须用大师写法:person.sayHi.call(person)
function add(x,y){
return x+y
}
add.call(undefined,1,2) //3
//Array.prototype.forEach用到了this
//this的值是在call的时候才能确定的
//forEach的源代码
Array.prototype.forEach2 = function(fn){
for(let i=0;i<this.length;i++) {
fn(this[i],i)
}
}
array.forEach2.call(array,(item)=>console.log(item)) //显示this
//等价于array.forEach2((item)=>console.log(item)),隐式this
Array.prototype.forEach.call({0:'a',length:1},(item)=>console.log(item)) //a
this的两种使用方法
//隐式传递
fn(1,2) //等价于fn.call(undefined,1,2)
obj.child.fn(1) //等价于obj.child.fn.call(obj.child,1)
//显示传递
fn.call(undefined,1,2)
fn.apply(undefined,[1,2]) //apply后面的参数需要用数组的形式表示
绑定this
- 使用.bind可以让this不被改变
function f1(p1,p2) {
console.log(this,p1,p2)
}
let f2 = f1.bind({name:'mx'}) //把f1的this给绑起来,{name:'mx'}这个就是this
// 那么f2就是f1绑定了this之后的新函数
f2() //等价于f1.call({name:'mx'})
- .bind还可以绑定其他参数
let f3 = f1.bind({name:'mx'},'hi') //hi对应p1
f3() //等价于f1.call({name:'frank'},hi),this和p1已经绑死了
箭头函数
没有arguments和this
- 里面的this就是外面的this
console.log(this) //window
let fn = ()=>console.log(this)
fn() // window
- 就算你加call都没有用
fn.call({name:'mx'})//window
默认的this是window
立即执行函数
!function (){
var a=2
console.log(a)
}()
//新版js造局部变量
{
let a = 2
console.log(a)
}
this面试题
6个6面试题
let i
for(i=0;i<6;i++) {
setTimeout(()=>console.log(i),1000)
}
//setTimeout(fn,1000) 1000ms后,尽快执行fn
//一秒钟后打印6个6,因为函数执行时遇到外部变量会去读取其最新值
//函数它里面的变量,只会在它执行的时候去计算,执行之前它看都不看这里面有什么变量
解决办法:
for(let i=0;i<6;i++) {
setTimeout(()=>console.log(i),1000)
}
资料来源:饥人谷