this三种指向
this 环境对象: 谁调用我,我就指向谁
普通函数:函数名() this指向window
构造函数: new 函数名() this指向new创建的实例对象
对象方法: 对象名.方法名() this指向对象
小技巧 * 调用的时候没有点没有new就是window,有new就是实例,有点就是左边的对象
调用时如果内部还有其他函数调用,看作用域.
示例如下:
function fn() {
console.log(this)
}
// 普通函数
fn() //window
// 构造函数
new fn() // new创建的实例对象
let obj = {
name: '张三',
age: fn
}
//对象方法:obj对象
obj.age() // obj
let obj1 = {
name1: '李四',
eat: function () {
//1级链
console.log(this)
function fn1() {
//2级链
console.log(this) //window
}
fn1()
}
}
let eat = obj1.eat
obj1.eat() // obj window
eat() //window window
new eat() // eat{} window
这个时候我们就会发现他们有共同的特点: this的指向无法动态修改
示例如下:
function fn(){
//三种执行模式this无法动态修改
this = {age:18};
console.log(this);
}
fn()//会报错
如果想要修改this我们也有三种方式
上下文调用
函数上下文模式 作用: 可以动态修改函数中的this
示例代码如下:
/* 上下文模式 */
function fn(a, b) {
console.log(this);
console.log(a + b);
};
//a. 函数名.call(修改的this,arg1,arg2…………)
//应用场景: 适用于函数原本形参 <= 1
fn(10, 20); //this:window
fn.call({
age: 18
}, 100, 200); //this:object
//b. 函数名.apply(修改的this,[数组或伪数组])
//应用场景: 适用于函数原本形参 >=2
fn.apply({
age: 88
}, [20, 30]); //this:object
//c. 函数名.bind(修改的this,arg1,arg2…………)
//特点:这个函数不会立即执行,而是返回一个修改this之后的新函数
//应用场景 : 事件处理函数,定时器
let newFn = fn.bind({
name: '小张'
});
newFn(50, 60); //this:object
函数名.call()
应用:万能检测数据类型
语法 :
Object.prototype.toString.call(数据)
示例代码如下:
<script>
/*
1. typeof检测数据类型: typeof 数据
* 有两种数据类型无法检测,得到'object' : 数组 和 null
2.万能检测数据类型方法
Object.prototype.toString.call(数据)
* 得到一个固定格式字符串: [object 数据类型]
*/
let num = 10
let str = 'abc'
let bol = true
let und = undefined
let nul = null
let arr = [10, 20, 30]
let fn = function () {}
let obj = { name: '张三' }
// console.log(typeof num)//'number'
// console.log(typeof str)//'string'
// console.log(typeof bol)//'boolean'
// console.log(typeof und)//'undefined'
// console.log(typeof nul)//'object'
// console.log(typeof arr)//'object'
// console.log(typeof fn)//'function'
// console.log(typeof obj)//'object'
console.log( Object.prototype.toString.call(num) )//['object Number']
console.log( Object.prototype.toString.call(str) )//['object String']
console.log( Object.prototype.toString.call(bol) )//['object Boolean']
console.log( Object.prototype.toString.call(und) )//['object Undefined']
console.log( Object.prototype.toString.call(nul) )//['object Null']
console.log( Object.prototype.toString.call(arr) )//['object Array']
console.log( Object.prototype.toString.call(fn) )//['object Function']
console.log( Object.prototype.toString.call(obj) )//['object Object']
</script>
函数名.apply()
应用 : 伪数组转成真数组
示例代码如下:
<script>
/*
伪数组 : 拥有数组三要素,但是没有数组的api
伪数组本质是一个对象
*/
let obj = {
0: 'a',
1: 'b',
2: 'c',
3: 'd',
length: 4
};
console.log(obj)
console.log(obj[0])
//需求:伪数组转成真数组 (希望伪数组也可以调用数组的api)
//以前方式:通过apply
let arr = []
arr.push.apply(arr, obj)
console.log(arr)
/* 1.slice 可以查询数组,默认情况下不传参这个方法会得到一个空数组
2.但是伪数组由于原型不是Array,所以无法调用slice
3.slice方法存储在哪里,Array.prototype */
obj = Array.prototype.slice.call(obj)
console.log(obj)
//最新方式: Array.from(伪数组) 重点掌握
let arr1 = Array.from(obj)
console.log(arr1)
</script>
应用 :求数组最大值
示例代码如下:
<script>
// 需求:求数组最大值
let arr = [100, 20, 66, 88, 90]
//1.擂台思想/js基础
let max = arr[0]
for (let i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i]
}
}
console.log(max)
//2.Math.max(数字1,数字2,数字3,…………)
// let max = Math.max(arr[0],arr[1],arr[2],arr[3],arr[4]);
//这里没有必要修改this,借助apply可以自动遍历数组传参
let max1 = Math.max.apply(Math, arr)
console.log(max1)
//3.ES6最新方式 和apply类似,也会遍历数组,然后逐一传参
let max2 = Math.max(...arr)
console.log(max2)
</script>
函数名.bind()
特点:这个函数不会立即执行,而是返回一个修改this之后的新函数
应用场景 : 事件处理函数,定时器
示例代码如下:
// 定时器:一段代码间隔事件执行 setTimeout(一段代码,间隔时间)
//1 具名函数
let test = function () {
console.log('我是具名函数');
console.log(this);
};
let newTest = test.bind({
name: '张三'
})
setTimeout(newTest, 3000);
//2 匿名函数
setTimeout(function () {
console.log('我是定时器中的函数');
console.log(this);
}.bind({
name: '李四'
}), 2000);
call apply 和bind三者的区别
相同点: 作用一致,修改函数this的指向
不同点:
传参方式不同:call是按照顺序传参,apply是数组/伪数组传参
执行机制不同:call和apply会立即执行函数,bind得到修改this的新函数之后