js(this指向)
- 先说函数function(){}
- 函数是根基(很重要)。
- 隐式参数:arguments | this;
- arguments是js处理函数参数传入的一种方案:“like Array”类数组的存在,用来存放函数传进来的参数,具有length属性,可以用for循环来遍历。: 实例
{ '0': 1, '1': 2, '2': '我就是', '3': 'sa', '4': 32, '5': 'dsad' }
- this:函数上下文,参数this会关联到一个对象,关联的对象会根据函数的调用方式不同有差别。
- 函数调用方式
- 做为函数调用
- 作为方法调用
- 作为构造器
- 经由函数apply()和call()
- 作为函数:
- this指向全局的上下文,即window对象。
- 在严格模式下,this指向undefined。
//函数定义形式
function ninXia() {
return this;
}
//函数表达式
var ninXia=function(){
return this;
}
//立即执行函数
(function(){})();
ninXia() //window
- 作为方法:
- 当函数作为对象的属性被调用时就叫做方法。this指向new出来的对象实例。(当一个函数作为方法被调用时,这个对象就成为了这个函数的上下文,并在此函数中可以通过this访问到该对象)
let a = {
name: "sususu",
};
a.console = function() {
console.log(this.name)
}
a.console()
//函数上下文的产生,并不由函数的定义来决定,而是由函数的调用来决定
let a={
name:"sususu",
method: creep
};
let b={
name:"aaaaa",
method:creep
}
console.log(a.method());
console.log(b.method());
function creep(){
return this;
}
//{ name: 'sususu', method: [Function: creep] }a对象实例
//{ name: 'aaaaa', method: [Function: creep] }b对象实例
- 作为构造器
- 历程:
- 一个新的空对象被new 出来
- 这个对象被传递给这个构造器作为this参数,也就是说这个对象是这个构造器函数的上下文
- 如果没有显式的return一个对象的语句,这个新的对象将被隐式的return,并成为这个构造器的值。
- 构造函数的目的:创建一个新对象,并进行初始化设置,然后将其作为构造函数的返回值。
- 历程:
function Aaa(aa) {
this.a = aa;
this.console = function() {
console.log(this.a);
}
}
let btn1 = new Aaa("sss");
let btn2 = new Aaa("ppp");
btn1.console();//sss
btn2.console();//ppp
let whatever=Aaa();
whatever() //this转换为window
//在这里属性被附在了window上,并且window会被return并存储在whatever中
- apply()和 call()可以指定任何对象作为函数的上下文(即this)。
- apply(用于作为上下文的对象,[参数数组]);
- call (用于作为上下文的对象,arguments list);
- 每个函数中都存在这两个方法。
- 在回调函数中的应用:
function forEach(list, callback) {
for (let i = 0; i < list.length; i++) {
callback.call(list[i], i);
}
}
list = ["tao", "liang", "gong", "lan"];
forEach(list, function(index) {
console.log(index);
console.log(this);
})
//输出
0
[String: 'tao'] //typeof this===object 'true'
1
[String: 'liang']
2
[String: 'gong']
3
[String: 'lan']
7.解决函数上下文(this)的问题
- call和apply显示指定this上下文
- 箭头函数
- bind方法
- 箭头函数绕过函数上下文
- 箭头函数没有单独的this值
- 箭头函数的this与声明时的上下文相同
//es6
function foo() {
setTimeout(() => {
console.log(this)
}, 1000)
}
//es5
function foo() {
var _this = this;
setTimeout(function() {
console.log(_this);
}, 1000)
}
foo() //window
new foo() //foo{}
- 额外插一道面试题:
//使用箭头函数
class Animal {
constructor(type) {
this.type = type
}
say(text) {
setTimeout(() => {
console.log(this);
console.log(`${this.type}say${text}`)
}, 1000)
}
}
var type = 'window';
const ANIMAL = new Animal('animal');//Animal { type: 'animal' }
ANIMAL.say('hi')//animalsayhi
//不使用箭头函数,闭包情况
class Animal {
constructor(type) {
this.type = type
}
say(text) {
setTimeout(function() {
console.log(this);
console.log(`${this.type} say ${text}`)
}, 1000)
}
}
var type = 'window';
const ANIMAL = new Animal('animal');
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: //Window, …}
ANIMAL.say('hi')//windowsayhi
- bind方法
- 在f()函数上调用此方法,并传入一个对象作为参数,将会返回一个新函数,(以函数调用方式)调用新函数将把f()作为传入对象的方法来调用(指示this指向),传入的参数都将传入原始函数f().
function foo(y) {
return this.a + y
}
var obj = {
a: 1
}
var newFoo = foo.bind(obj);
console.log(newFoo(2));//3
- bind()函数传入的实参中除了第一个,其他将依次绑定至this。
function foo(x) {
this.a=x;
}
var obj = {
a: 1
}
var newFoo = foo.bind(obj, 2);
console.log(obj.a)//2