在ES6之前,函数内部的this是由该函数的调用方式决定的,跟大小写和书写位置无关
# 函数调用
直接调用函数时函数内部中的this指向window
let age = 18
let name = '张三'
let p = {
age: 15,
name: '李四',
say:function(){
console.log(this.age, this.name)
}
}
let f1 = p.say;
f1() // 输出:18 张三
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 方法调用
通过对象里的方法调用函数,函数内部中的this指向调用该方法的对象
let age = 18
let name = '张三'
let p = {
age: 15,
name: '李四',
say:function(){
console.log(this.age, this.name)
}
}
p.say() // 输出:15 李四
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 构造函数调用
通过new关键字来调用函数即为构造函数调用方式,函数内部的this指向该构造函数的实例
对象的属性查找规则
- 首先查看本身有没有length属性
- 如果本身没有该属性,那么去它的原型对象中查找
- 如果原型对象中没有,那么就去原型对象的原型对象中查找,最终一直找到根对象(Object.prototype)
- 最终都没有找到的话,我们认为该对象并没有该属性,如果获取该属性的值:undefined
let age = 18
let name = '张三'
let p = {
age: 15,
name: '李四',
say:function(){
console.log(this.age, this.name)
}
}
let s1 = new p.say()
// 输出:undefined undefined
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 上下文方式调用
上下文方式调用有三种:call、apply、bind
call方法的第一个参数决定了函数内部this的值
- 如果是一个对象类型,那么函数内部的this指向该对象
- 如果是undefined、null,那么函数内部的this指向window
- 如果是数字,那么函数内部的this指向对应的Number构造函数的实例
- 如果是字符串,那么函数内部的this指向对应的String构造函数的实例
- 如果是布尔值,那么函数内部的this指向对应的Boolean构造函数的实例
function fn() { console.log(this) } fn.call([1,3,5]) fn.call({ age: 20, height: 1000 }) fn.call(1) // this --> new Number(1) fn.call("abc") // this --> new String("abc") fn.call(true) // this --> new Boolean(false) fn.call(null) // this --> window fn.call(undefined) // this --> window
1
2
3
4
5
6
7
8
9
10call和apply都可以改变函数内部的this的值但是传参的形式不同
function toString(a,b,c){ console.log(a + " " + b + " " + c); } toString.call(null,1,3,5) // 输出 1 3 5 toString.apply(null,[1,3,5]) // 输出 1 3 5
1
2
3
4
5bind方法执行之后会产生一个新函数,这个新函数里面的逻辑和原来还是一样的,唯一的不同是this的指向被改变了、
function write() { console.log(this.poem) } let writePoem = write.bind({ poem: '唐诗' }) writePoem()
1
2
3
4
5手动实现bind
// bind方法放在函数的原型中 Function.prototype.bind = function () { var self = this, // 保存原函数即fn context = [].shift.call(arguments), // 保存需要绑定的this上下文 args = [].slice.call(arguments); // 剩余的参数转为数组 return function () { // 返回一个新函数 console.log(context, args, [].slice.call(arguments)) // 输出 {age:18} , [1, 2, 3] , [4, 5, 6] self.apply(context,[].concat.call(args, [].slice.call(arguments))); } } function fn(){ console.log(arguments); // 输出的Arguments包含 1, 2, 3, 4, 5, 6 } var _f1=fn.bind({age:18}, 1, 2, 3) _f1(4,5,6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17