一. 假设没有 this
let person = {name: 'frank',sayHi(){console.log(你好,我叫 + person.name)}}
分析:可以用直接保存了对象地址的变量获取 ‘name’,把这种办法简称为引用
- 问题一:
person 如果改名,sayHi 函数就挂了,sayHi 函数甚至有可能在另一个文件里面,所以我们不希望 sayHi 函数里出现 person 引用
- 问题二:
分析:这里只有类,还没创建对象,因此不可能获取对象的引用class Person{constructor(name){this.name = name // 这里的 this 是 new 强制指定的}sayHi(){console.log(???)}}
二. 解决思路
那么需要一种办法拿到对象,这样才能获取对象的 name 属性
1. 土办法,用参数
对象
let person = {name: 'frank',sayHi(p){console.log('你好,我叫' + p.name)}}person.sayHi(person); //你好,我叫frank
类
class Person{constructor(name){ this.name = name }sayHi(p){console.log(你好,我叫 + p.name)}}let person = new Person('frank');person.sayHi(person); //你好,我叫frank
Python 就用了这种方法
class Person:def init(self, name): # 构造函数self.name = namedef sayHi(self):print('Hi, I am ' + self.name)person = Person('frank')person.sayHi() //Hi, I am frank
特点:每个函数都接受一个额外的 self,这个 self 就是传进来的对象,只不过 Python 会默认传一个传对象
person.sayHi() 等价于 person.sayHi(person),person 就被传给 self 了。
JS 没有模仿 Python 的思路,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 可以通过 this 引用 person
这就引出另一个问题,person.sayHi(),person.sayHi(person) 哪个对
let person = {name: 'frank',sayHi(this){console.log(你好,我叫 + this.name)}}person.sayHi()person.sayHi(person)
省略形式反而对了,完整形式反而是错的?
2. JS 提供两种调用形式解决这种不和谐
小白调用法
let person = {name: 'frank',sayHi(p){console.log('你好,我叫' + p.name)}}person.sayHi(); //会自动把 person 传到函数里,作为 this
大师调用法
let person = {name: 'frank',sayHi(p){console.log('你好,我叫' + p.name)}}person.sayHi.call({name:1}) //1
调用方式
Array.prototype.forEach2 = function(fn){for(let i=0;i<this.length;i++){fn(this[i], i, this)}}
上面的代码 this 是什么?
由于大家使用 forEach2 的时候总是会用 arr.forEach2,所以 arr 就被自动传给 forEach2
this 一定是数组吗 ?不一定,比如:Array.prototype.forEach2.call({0:’a’,1:’b’})
隐式传递
fn(1,2) // 等价于 fn.call(undefined, 1, 2)obj.child.fn(1) // 等价于 obj.child.fn.call(obj.child, 1)
显示传递
call(this,param) this 会被自动转化成对象(JS 的糟粕)
function fn(x,y){console.log(arguments)console.log(this)}fn.call(1); //Number {1}let obj = {};fn.call(obj,123,321) //[123,321] {}
apply(this,arr) 可以以数组的形式传多个值到arguments
function fn(x,y){console.log(arguments)console.log(this)}let obj = {};fn.apply(obj,[1,2,3]) //[1,2,3] {}
bind 绑定 this
一个参数
function fn(x,y){console.log(this.x.y)}let f2 = fn.bind({name: 'frank'}); //f2 是 fn 绑定了 this后的新函数f2() //等价于 f1.call({name: 'frank'})
多个参数
function fn(x,y){console.log(this.x.y)}let f3 = fn.bind({name: 'frank'},10); //f2 是 fn 绑定了 this后的新函数f3() //等价于 f1.call({name: 'frank'},10)
