關(guān)于THIS的幾種情況 :
- 給當(dāng)前元素的某個(gè)事件行為綁定方法隅忿,方法中的THIS是當(dāng)前元素本身「排除:DOM2在IE6~8中基于attachEvent進(jìn)行事件綁定,這樣處理方法中的this->window」
- 方法執(zhí)行征堪,看方法前面是否有“點(diǎn)”瘩缆,有“點(diǎn)”,“點(diǎn)”前面是誰THIS就是誰佃蚜,沒有“點(diǎn)”,THIS是window「嚴(yán)格模式下是undefiend」,特殊例外:
自執(zhí)行函數(shù)中的THIS一般是window/undefined
回調(diào)函數(shù)中的THIS一般是window/undefined「當(dāng)然某些方法中會(huì)做一些特殊的處理」
括號(hào)表達(dá)式有特殊性
........
- 構(gòu)造函數(shù)執(zhí)行咳榜,構(gòu)造函數(shù)體中的THIS是當(dāng)前類的實(shí)例
- 箭頭函數(shù)中沒有THIS「類似的還有塊級(jí)上下文」,所以無論怎樣去執(zhí)行爽锥,怎樣去修改涌韩,都沒有用,如果函數(shù)中出現(xiàn)THIS氯夷,一定是其所在的上級(jí)上下文中的THIS
- 在Function.prototype提供了三個(gè)方法:call/apply/bind臣樱,這三個(gè)方法都是用來強(qiáng)制改變函數(shù)中this指向的「每一個(gè)函數(shù)都是Function的實(shí)例,所以都可以調(diào)取這三個(gè)方法執(zhí)行」
代碼:
"use strict";
let obj = {
name: 'zhufeng',
fn() {
/!* // this -> obj
let self = this;
setTimeout(function () {
// console.log(this);
// this -> window
console.log(self);
}, 1000); *!/
setTimeout(() => {
console.log(this);
// this是上級(jí)上下文中的,也就是obj
}, 1000);
}
}
obj.fn();
call/apply/bind 三者的區(qū)別:
需求:把fn函數(shù)執(zhí)行腮考,并且讓方法中的this是obj雇毫,再并且傳遞10/20分別給x和y形參
"use strict";
window.name = 'window';
const fn = function fn(x, y) {
console.log(this, x + y);
};
let obj = {
name: 'obj'
};
// fn(); //this->undefined Uncaught TypeError: Cannot read property 'name' of undefined
// obj.fn(); //Uncaught TypeError: obj.fn is not a function obj中不存在fn屬性,之間沒有關(guān)聯(lián)
fn.call(obj, 10, 20);
fn.call(); //fn中的this->window/undefined x=undefined y=undefined
fn.call(null/undefined); //this->window & null/undefined x=undefined y=undefined
fn.call(10, 20); //this->10 x=20 y=undefined
fn.apply(obj, [10, 20]);
fn首先作為Function的實(shí)例,基于proto找到Function.prototype.call方法踩蔚,并且把找到的call方法執(zhí)行.
apply和call只有一個(gè)區(qū)別:
call方法在設(shè)定給函數(shù)傳遞的實(shí)參信息的時(shí)候棚放,是要求一個(gè)個(gè)傳遞實(shí)參值;但是apply是要求用戶把所有需要傳遞的實(shí)參信息以數(shù)組/類數(shù)組進(jìn)行管理的馅闽; 雖然要求這樣寫飘蚯,但是內(nèi)部最后處理的時(shí)候馍迄,和call一樣,也是一項(xiàng)項(xiàng)的傳遞給函數(shù)的局骤;
場景一:求一個(gè)數(shù)組中的最大值或者最小值
let arr = [10, 14, 23, 34, 20, 13];
// 1.排序處理 時(shí)間復(fù)雜度稍微高一些「sort內(nèi)部 N^2」
console.log(arr.sort((a, b) => b - a)[0]);
// 2.假設(shè)法 N
let max = arr[0],
i = 1,
len = arr.length,
item;
for (; i < len; i++) {
item = arr[i];
if (item > max) {
max = item;
}
}
console.log(max);
//3.Math.max獲取最大值 推薦
console.log(Math.max(10, 14, 23, 34, 20, 13)); //=>34
console.log(Math.max(arr)); //=>NaN 方法本身是獲取一堆數(shù)字中的最大值攀圈,需要把比較的數(shù)字一項(xiàng)項(xiàng)的傳遞給max方法才可以
// 想把數(shù)組中的每一項(xiàng)分別傳遞給max方法
let max = Math.max(...arr);
console.log(max); //=>34
let max = Math.max.apply(null, arr); //利用apply的機(jī)制「雖然傳遞給apply的是一個(gè)數(shù)組,但是apply內(nèi)部會(huì)把數(shù)組中的每一項(xiàng)分別傳遞給對(duì)應(yīng)的函數(shù)」峦甩;而且Math.max中用不到this赘来,所以this改成誰無所謂,就是占個(gè)位而已凯傲;
console.log(max); //=>34
場景二:任意數(shù)求和「不確定實(shí)參的個(gè)數(shù)犬辰,所以無法基于設(shè)定形參接受」
+ 剩余運(yùn)算符 ES6
+ arguments ES3
const sum = function sum(...params) {
if (params.length === 0) return 0;
// params -> 數(shù)組
return params.reduce((total, item) => total + item, 0);
};
const sum = function sum() {
let params = arguments; // params -> 類數(shù)組「不能直接使用數(shù)組的辦法」
if (params.length === 0) return 0;
// 把類數(shù)組轉(zhuǎn)換為數(shù)組
// + params = Array.from(params); ES6+
// + params = [...params]; ES6+
// + ...
let i = 0,
len = params.length,
arr = [];
for (; i < len; i++) {
arr[arr.length] = params[i]; //<==> arr.push(params[i]);
}
return arr.reduce((total, item) => total + item, 0);
};
Array.prototype.slice = function slice() {
// 模擬的方法
// this -> ary
let i = 0,
len = this.length,
arr = [];
for (; i < len; i++) {
arr[arr.length] = this[i];
}
return arr;
};
// ary.slice()
// ary.slice(0)
// // 數(shù)組的克隆,把原始數(shù)組中的每一項(xiàng)都克隆一份給返回的新數(shù)組「淺克隆」
const sum = function sum() {
let params = arguments;
if (params.length === 0) return 0;
params = [].slice.call(params);
return params.reduce((total, item) => total + item, 0);
};
把類數(shù)組轉(zhuǎn)換為數(shù)組:如果我們能把slice執(zhí)行冰单,并且讓slice中的this是arguments幌缝,這樣就相當(dāng)于在迭代arguments中的每一項(xiàng),把每一項(xiàng)賦值給新的數(shù)組集合 -> 也就是把類數(shù)組轉(zhuǎn)換為數(shù)組
+ 如何讓slice執(zhí)行 Array.prototype.slice() / [].slice() .....
+ 如何改變slice中的this call/apply...
原理:“因?yàn)轭悢?shù)組的結(jié)果和數(shù)組非常的相似”球凰,所以大部分操作數(shù)組的代碼狮腿,也同樣適用于類數(shù)組,在這個(gè)前提下呕诉,我們只需要把實(shí)現(xiàn)好的數(shù)組方法執(zhí)行缘厢,讓方法中的this變?yōu)轭愃平M,就相當(dāng)于類數(shù)組在操作這寫代碼甩挫,實(shí)現(xiàn)了類數(shù)組借用數(shù)組方法的目的贴硫,我們這種操作叫做“鴨子類型”
const sum = function sum() {
let params = arguments;
if (params.length === 0) return 0;
// 不轉(zhuǎn)換了,直接借用即可
return [].reduce.call(params, (total, item) => total + item, 0);
}
const sum = function sum() {
let params = arguments;
// params.__proto__ = Array.prototype; //修改原型鏈的指向 arguments可以直接使用數(shù)組原型上的任何方法
params.reduce = Array.prototype.reduce;
if (params.length === 0) return 0;
return params.reduce((total, item) => total + item, 0);
};
console.log(sum()); //->0
console.log(sum(10)); //->10
console.log(sum(10, 20)); //->30
console.log(sum(10, 20, 30)); //->60