关于this的几种情况以及call、apply的区别使用

关于THIS的几种情况 :

  • 给当前元素的某个事件行为绑定方法,方法中的THIS是当前元素本身「排除:DOM2在IE6~8中基于attachEvent进行事件绑定,这样处理方法中的this->window」
  • 方法执行,看方法前面是否有“点”,有“点”,“点”前面是谁THIS就是谁,没有“点”,THIS是window「严格模式下是undefiend」,特殊例外:

自执行函数中的THIS一般是window/undefined
回调函数中的THIS一般是window/undefined「当然某些方法中会做一些特殊的处理」
括号表达式有特殊性
........

  • 构造函数执行,构造函数体中的THIS是当前类的实例
  • 箭头函数中没有THIS「类似的还有块级上下文」,所以无论怎样去执行,怎样去修改,都没有用,如果函数中出现THIS,一定是其所在的上级上下文中的THIS
  • 在Function.prototype提供了三个方法:call/apply/bind,这三个方法都是用来强制改变函数中this指向的「每一个函数都是Function的实例,所以都可以调取这三个方法执行」

代码:

"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是上级上下文中的,也就是obj
        }, 1000);
    }
}
obj.fn();

call/apply/bind 三者的区别:

需求:把fn函数执行,并且让方法中的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属性,之间没有关联


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的实例,基于proto找到Function.prototype.call方法,并且把找到的call方法执行.


apply和call只有一个区别:

call方法在设定给函数传递的实参信息的时候,是要求一个个传递实参值;但是apply是要求用户把所有需要传递的实参信息以数组/类数组进行管理的; 虽然要求这样写,但是内部最后处理的时候,和call一样,也是一项项的传递给函数的;

场景一:求一个数组中的最大值或者最小值

let arr = [10, 14, 23, 34, 20, 13];

// 1.排序处理 时间复杂度稍微高一些「sort内部 N^2」
console.log(arr.sort((a, b) => b - a)[0]); 
// 2.假设法  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  方法本身是获取一堆数字中的最大值,需要把比较的数字一项项的传递给max方法才可以

// 想把数组中的每一项分别传递给max方法
let max = Math.max(...arr);
console.log(max); //=>34

let max = Math.max.apply(null, arr); //利用apply的机制「虽然传递给apply的是一个数组,但是apply内部会把数组中的每一项分别传递给对应的函数」;而且Math.max中用不到this,所以this改成谁无所谓,就是占个位而已;
console.log(max); //=>34

场景二:任意数求和「不确定实参的个数,所以无法基于设定形参接受」

  + 剩余运算符 ES6
  + arguments ES3
const sum = function sum(...params) {
    if (params.length === 0) return 0;
    // params -> 数组
    return params.reduce((total, item) => total + item, 0);
}; 
const sum = function sum() {
    let params = arguments; // params -> 类数组「不能直接使用数组的办法」
    if (params.length === 0) return 0;
    // 把类数组转换为数组
    //   + 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)
// // 数组的克隆,把原始数组中的每一项都克隆一份给返回的新数组「浅克隆」

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);
};

把类数组转换为数组:如果我们能把slice执行,并且让slice中的this是arguments,这样就相当于在迭代arguments中的每一项,把每一项赋值给新的数组集合 -> 也就是把类数组转换为数组
+ 如何让slice执行 Array.prototype.slice() / [].slice() .....
+ 如何改变slice中的this call/apply...

原理:“因为类数组的结果和数组非常的相似”,所以大部分操作数组的代码,也同样适用于类数组,在这个前提下,我们只需要把实现好的数组方法执行,让方法中的this变为类似组,就相当于类数组在操作这写代码,实现了类数组借用数组方法的目的,我们这种操作叫做“鸭子类型”


 const sum = function sum() {
    let params = arguments;
    if (params.length === 0) return 0;
    // 不转换了,直接借用即可
    return [].reduce.call(params, (total, item) => total + item, 0);
}


const sum = function sum() {
    let params = arguments;
    // params.__proto__ = Array.prototype; //修改原型链的指向  arguments可以直接使用数组原型上的任何方法
    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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容