this是啥
- 函数在被调用时会创建执行上下文,this是一个内部对象,只能在函数内部使用,总指向调用它的对象。
- 谁把它执行的「在哪创建&在哪执行都没有必然的关系」this指向谁。
this的绑定规则
- 函数执行,看方法前面是否有“点”,没有“点”,this是window「严格模式下是undefined」,有“点”,“点”前面是谁this就是谁
const fn = function fn() {
console.log(this);
};
let obj = {
name: 'OBJ',
fn: fn
};
fn(); // 默认绑定 window
obj.fn(); // 隐式绑定 obj
- 显式绑定->基于Function.prototype上的call/apply/bind修改this指向。
fn.call(obj) // obj - new绑定,构造函数体中的this是当前类的实例。
function People() {
this.name = 'Tom';
this.age = 2;
console.log(this); // People {name: 'Tom', age: 2}
}
let f = new People;
- 箭头函数没有this,箭头函数中的this指向最近的外层作用域中的this所指对象,一层层往外找,直到有this的定义。
let demo = {
name: 'DEMO',
fn() {
console.log(this);//demo
setTimeout(function () {
console.log(this); //window
}, 1000);
setTimeout(() => {
console.log(this); //demo
}, 1000);
}
};
demo.fn();
- 给当前元素的某个事件行为绑定方法,当事件行为触发,方法中的this是当前元素本身「排除attachEvent」
优先级
new绑定优先级 > 显式绑定优先级 > 隐式绑定优先级 > 默认绑定优先级,箭头函数
改变this的指向
call
原理:利用点机制,给CONTEXT设置一个属性,属性值一定是我们要执行的函数。
func函数基于__proto__找到Function.prototype.call,把call方法执行
在call方法内部「call执行的时候」 call(context->obj,...params->[10,20])
- 把func中的this改为obj
- 并且把params接收的值当做实参传递给func函数
- 并且让func函数立即执行 func.call(obj, 10, 20); func.apply(obj, [10, 20]);
Function.prototype.mycall= function call(context,...params){
// 原理 obj.xxx = func ;obj.xxx(...params)
// 判断context是否为空
context = context || window
let func = this //this 为当前函数
// 声明唯一属性,避免与context的属性冲突
let key =Symbol('属性值')
context[key] = func
// 调用函数返回结果
const res = context[key](...params)
delete context[key]
return res
}
// 调试
const fn = function fn(b) {
let name = 'QQ'
console.log(this);
return this.name + b
};
let obj = {
name: 'OBJ',
fn: fn
};
console.log(fn.mycall(obj,"hello"))
//输出
//{name: 'OBJ', fn: ƒ, Symbol(属性值): ƒ}
//OBJhello
注意:对象的属性名在不同情况下如何取值
- 如果属性名称是常量(固定值),获取对应对象的属性值的方式有:
对象.属性名称
对象[属性名称]
二、如果属性名称是一个变量(不固定值),获取属性值方式只能是:
对象[属性名称] 传进去的属性名称是一个变量
apply
与call区别:传递的参数不同,apply传递的是一个数组
数组合并
let a = [1,2,3]
let b = [4,5,6]
a.push.apply(a,b)
//a->(6) [1, 2, 3, 4, 5, 6]
//b->(3) [4, 5, 6]
bind
区别: func函数基于__proto__找到Function.prototype.bind,把bind方法执行
在bind方法内部
- 和call/apply的区别:并没有把func立即执行
- 把传递进来的obj/10/20等(上下文,参数)信息存储起来「闭包」
- 执行bind返回一个新的函数 例如:proxy,把proxy函数绑定给元素的事件,当事件触发执行的是返回的proxy函数,在proxy内部,再去把func执行,把this和值都改变为之前存储的
Function.prototype.Mybind = function bind(context,...params){
context = context || window
let func = this
return function(...args){
// 执行方法并改变this
return func.apply(context, [...params,...args,]);
}
}
let value = "window"
function fun(bindParams,funParam){
return this.value + bindParams+funParam
}
let obj = {
value: "点击"
}
// 这两参数都是传给fun
let bindFun = fun.Mybind(obj,"bind参数")
console.log(bindFun('fun参数'))
//点击bind参数fun参数
类数组
无法使用数组方法
1. 函数里面的参数对象arguments;
2. 用getElementsByTagName/ClassName/Name获得的HTMLCollection;
3. 用querySelector获得的 NodeList。
转化为数组
#### array.form()
#### 扩展运算符...
#### 利用Array.prototype.slice
Array.prototype.slice.call(arguments)/[].slice.call(arguments)