为什么要有this
this 让函数可以自动引用合适的上下文对象
使用它可以减少传参,让代码更加优雅
function identify(context) {
return context.name, toUpperCase()//转化为大写
}
function speak(context) {
var gretting = 'Hello,I am' + indentify(context)
console.log(gretting)
}
var me = {
name: 'Tom'
}
speak(me)
function identify() {
return this.name, toUpperCase()//转化为大写
}
function speak() {
var gretting = 'Hello,I am' + indentify.call(this)//此处使用了显性绑定,后面会讲
console.log(gretting)
}
var me = {
name: 'Tom'
}
speak.call(me)
this
- this 是一个代词,在js中永远代表某一个域,且this只存在域中才有意义(全局作用域,函数作用域,块级作用域)
- this在浏览器全局下指向的是window
在编译软件中代表的是node的全局global
在浏览器中是window
this的指向:
-
默认绑定: 规则: 函数独立调用时,触发,this指向window
-
隐式绑定: 规则: 当一个函数被引用(函数被某一个对象拥有且触发且调用),this指向该上下文对象
-
隐式丢失: 规则: 当函数的应用有一连串上下文对象,this指向最近的上下文对象
-
显式绑定: 规则: call apply bind 显示的将函数的 this 绑定到一个对象上
-
new绑定: 规则:this指向实例对象 当一个函数存在return且返回的是一个引用类型的数据,new返回引用类型
默认绑定
函数独立调用时,触发,this指向window
function foo() {
let person = {
name: "amei",
age: 18
}
console.log(this);//它是foo函数域中的,不一定代表函数体
}
foo();//在全局中调用,this指向全局
function bar() {
let person = {
name: "管总",
age: 18
}
foo()//在函数中调用,this还是指向全局
}
bar();
独立调用 函数是什么
独立调用函数是指一个函数以普通的方式直接调用,而不是作为对象的方法调用 方法调用 ,也不是通过 call、apply 或 bind 等方法绑定上下文调用 显式绑定。后面两种方法会讲
隐式绑定
当一个函数被引用(函数被某一个对象拥有且触发且调用),this指向该上下文对象
function foo() {
console.log(this)
}
const obj = {
a: 1,
foo: foo//----------------------这这种方法是方法调用,会让this指向obj这个对象
}
obj.foo()//
方法调用是什么
让一个对象拥有这个函数
隐式绑定丢失
当函数的应用有一连串上下文对象,this指向最近的上下文对象
const obj2 = {
a: 2,
obj: obj
}
obj2.obj.foo()-------此处foo指向obj,不指向obj2
显式绑定
call apply bind 显示的将函数的 this 绑定到一个对象上
call,apply,bind是构造函数Function的现式原型(proto)上的一个方法,当函数被创建的时候会把它的显式原型赋给这个函数的隐式原型__proto__(函数也是对象,也会有隐式原型和显式原型),然后函数就可以调用它了。(看不懂去看原型和原型链)
function foo() {
console.log(this.a)
}
var obj = {
a: 1
}
foo()
foo.call(obj)
call apply bind他们三个作用差不多,只是传参的方法不一样
function foo(a,b) {
console.log(this.a+a+b)
}
var obj = {
a: 1
}
foo()
foo.call(obj,2,3)//---------------call此处传的参数是散的
function foo(a,b) {
console.log(this.a+a+b)
}
var obj = {
a: 1
}
foo()
foo.apply(obj,[1,2])//------------apply与call不同,接受参数用数组
function foo(a, b) {
console.log(this.a + a + b)
}
var obj = {
a: 1
}
foo()
let bar = foo.bind(obj, 2, 3)//-------与call一样零散接受参数,但返回函数体
bar()
let bar = foo.bind(obj, 2)//----------与call一样零散接受参数,并返回函数体
bar(1)//没有采集完参数会在函数体里
new
- 创建一个空对象obj
- 将构造函数里的this指向obj
- 正常运行构造函数里的代码
- obj的隐式原型等于构造函数的显示原型
- 返回obj
类似于:
function Person() {
// let obj = {
// name: '阿炜',
// age: 18
// }
// Person.call(obj)
// obj.__proto__=Person.prototype
// return Person() instanceof Object? Person():obj----此处如果函数返回引用对象,则不返回值
this.name = '阿炜'
this.age = 18
return 123
}
let p = new Person()
console.log(p)//不会return基础类型,会返回应勇类型
箭头函数
箭头函数没有this,写在了箭头函数中的this也是它外层非箭头函数的
function foo(){
let bar =function(){
let baz =()=>{
console.log(this);
}
baz()----------------------此处的baz没有this,它的this会默认指向外层的非箭头函数,所有指向bar
}
}
foo()
箭头函数不能作为构造函数使用
//错误代码
let Foo = () => {
this.name = '廖总'
}
let foo = new Foo()
显式绑定call的原理和代码实现
call的原理
让函数被实例对象拥有,然后执行函数,把函数的this绑定到实例对象上(使用了this的隐式调用方法) 然后删除该函数
function foo(x) {
console.log(this.a, x);
return 123
}
const obj = {
a: 1
//b:foo-----------------让这个实例对象拥有这个函数
}
foo.call(obj, 2)
Function.prototype.myCall=function(...args){//不会的回去看看ES6的传参解决办法
//步骤:
//1,将foo引用到obj上
//2,调用foo
//3,移除obj上的foo
const context=args[0]
const arg=args.slice(1)//这是数组上的方法切成[2,3,4]
context.fn=this//函数被foo引用,this指向foo
const res=context.fn(...arg)//这是Es6里的方法...arg会把arg解构,变成2,3,4此处调用该函数。|| 让它执行,如果该函数返回值,接受它的return值,再去把它的return值返回
delete context.fn
return res//返回函数的值,要不然会把函数返回值的功能搞没
}
foo.myCall(obj,2)
结语
this面试官经常问,this非常重要
然后写文章容易,给我个赞谢谢!!!!!!