目录
优先级:箭头函数创建时的绑定>new构造函数绑定>显示绑定>隐式绑定>默认绑定
1.默认绑定:全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
2.隐式绑定规则:谁调用this就指向谁(作为对象方法调用)
3.显示绑定:直接修改this指向: call apply bind
1.方法里面如果有 写 “use strict“严格模式 : this指向undefined
2. 路人.调用者.方法名() this指向看首先谁调用了他
3.如果方法被赋值给变量出现 “= ”等号 要小心这是普通函数 this指向window
一:this指向问题
优先级:箭头函数创建时的绑定>new构造函数绑定>显示绑定>隐式绑定>默认绑定
1.默认绑定:全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
2.隐式绑定规则:谁调用this就指向谁(作为对象方法调用)
3.显示绑定:直接修改this指向: call apply bind
<script>
function b(){
console.log(this.age)
}
let a = {age:18}
b.call(a)
b.apply(a)
b.bind(a)()
</script>
①基本用法
-
b.call(a,参数,参数2,等等) 将b的this指向a
-
b.apply(a,[参数,参数2,等等])
-
b.bind(a,参数1,参数2,等等)()
-
当被指向的是 undefined和null时 指向window;当被指向数字1时指向Number,字符串'123'指向String;...依次类推
-
"use strict" 严格模式下,当被指向的是 undefined和null时 就是指向undefined和null
②区别
- 传递参数的方法不同
- bind不是立即执行的,首次调用返回的是一个方法,后面要加()进行立即执行操作
③特殊的使用场景:
- 只能用apply的情况:Math.max.apply(null,a)
let a = [1,2,8,9,321]
console.log(Math.max(1,2,8,9,321)) // 321
// 出现问题 : 括号里面不能直接传递数组
console.log(Math.max(a)) // NaN
// 解决方法 : 用apply 当 bind指向null时,this指向为window
console.log(Math.max.apply(null,a)) // 321
- 只能用bind的情况(因为bind不是立即执行函数,调用bind只回返回一个方法)
<body>
<button id="btn1">点击按钮1输出按钮2</button>
<button id="btn2">修改了按钮指向</button>
<script>
let btn1 = document.getElementById('btn1')
let btn2 = document.getElementById('btn2')
btn1.onclick = function(){
console.log(this.id)
}.bind(btn2)
</script>
</body>
4.new构造函数中this指向构造函数的实例
①当函数没有返回值 return 时
②当函数有返回值 return 时
- 如果return的值是基本数据类型的话,则忽略return,直接返回实例化的对象
- 如果return的值是引用类型的话,则不再返回实例化的对象,而是直接返回return返回的引用类型的值。
<script>
function jiBen(){
this.name = '返回基本数据类型,'
return 111
}
function yinYong(){
this.name = '返回引用数据类型,'
return [1,2,3,4,5]
}
console.log(new jiBen()) // jiBen {name: '返回基本数据类型,'}
console.log(new yinYong()) // [1, 2, 3, 4, 5]
</script>
二:this指向练习及注意事项
1.方法里面如果有 写 “use strict“严格模式 : this指向undefined
2. 路人.调用者.方法名() this指向看首先谁调用了他
3.如果方法被赋值给变量出现 “= ”等号 要小心这是普通函数 this指向window
三:手写new参考链接
1.思考new做了什么?
①创建一个空的对象
②将空对象的原型,指向于构造函数的原型
③将空对象作为构造函数的上下文(改变this指向)
④对构造函数有返回值的处理判断
- 如果return的值是基本数据类型的话,则忽略return,直接返回实例化的对象
- 如果return的值是引用类型的话,则不再返回实例化的对象,而是直接返回return返回的引用类型的值。
下述代码是new做了什么
<script>
function fn(){
this.name = 'this应该是实例化对象,而不是window'
console.log(this) //3. this指向 window
}
console.log(new fn()) //1.结果返回了的就是一个 fn 空对象
console.log(new fn().__proto__ === fn.prototype) //2.实例化对象的隐式原型等于构造函数的显示原型
fn() //3.没new过的构造函数:this指向 window 我们应该改成指向为 实例化对象
</script>
我们要写出一个方法:这个方法return的结果是构造函数的实例化对象
2.下述 手写new
<script>
function fn(){
this.name = '自定义new方法'
return 111
}
function myNew(fn,...args){
let obj = {} //1. 创建一个空对象
// obj.__prototype = fn.prototype
// 2. 将空对象的原型,指向构造函数的原型
Object.setPrototypeOf(obj,fn.prototype) //这种写法和上面的是有区别的
// 3. 将空对象作为构造函数的上下文(改变this指向)
var res = fn.apply(obj,args)
// 4. 对构造函数有返回值的处理判断
return res instanceof Object ? res : obj
}
console.log(myNew(fn))
</script>
四:手写call 参考链接
<script>
let a = {name:'羊'}
let b = function(x,y){
console.log(this)
console.log(x+y) //30
}
Function.prototype.call = function(a,...args){
// 被传入的值如果不是 null 或 undefined a为a;如果是则为window(直接指向window)
var a = a || window
// 创造一个独一无二的属性b
let b = Symbol('b')
// 这个this应该为调用call方法的对象b;让 b 成为 a 的一个属性
a.b = this
// res保存执行的结果
let res = a.b(...args)
// 删掉 仿造的 b 属性
delete a.b
return res
}
b.call(a,10,20)
// 将b的this指向a
</script>
五:手写apply
- apply和call不同的就是参数形式,apply是数组,所以直接用args表示,call用..args
<script>
let a = {name:'羊'}
let b = function(x,y){
console.log(this)
console.log(x+y) //30
}
//apply和call不同的就是参数形式,apply是数组,所以直接用args表示,call用..args
Function.prototype.call = function(a,args){
var a = a || window
let b = Symbol('b')
a.b = this
let res = a.b(...args)
delete a.b
return res
}
b.call(a,[10,20])
</script>