新聞中心
在課程 連接你、我、他 —— this 中我們學(xué)習(xí)了 this,最后留了一個(gè)問(wèn)題,如何修改 this 的指向,今天一起學(xué)習(xí)。

創(chuàng)新互聯(lián)公司是一家專業(yè)提供雙陽(yáng)企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、H5頁(yè)面制作、小程序制作等業(yè)務(wù)。10年已為雙陽(yáng)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
修改 this 的指向可通過(guò) apply、call、bind 這三個(gè)函數(shù)中的任意一個(gè)實(shí)現(xiàn)。那這三個(gè)函數(shù)是誰(shuí)的方法呢?
在 MDN 中我查到了:
這張圖說(shuō)明了這 3 個(gè)函數(shù)是 Function prototype 的方法,也就是說(shuō)「每個(gè)函數(shù)都有著三個(gè)方法」。當(dāng)定義一個(gè)函數(shù),這個(gè)函數(shù)默認(rèn)包含這三個(gè)方法。
我們感受一下 Vue.js 中關(guān)于 apply、call 和 bind 的使用:
apply 的應(yīng)用:
- function once (fn) {
- var called = false;
- return function () {
- if (!called) {
- called = true;
- fn.apply(this, arguments);
- }
- }
- }
call 的應(yīng)用:
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- function hasOwn (obj, key) {
- return hasOwnProperty.call(obj, key)
- }
bind的應(yīng)用:
- function polyfillBind (fn, ctx) {
- function boundFn (a) {
- var l = arguments.length;
- return l
- ? l > 1
- ? fn.apply(ctx, arguments)
- : fn.call(ctx, a)
- : fn.call(ctx)
- }
- boundFn._length = fn.length;
- return boundFn
- }
- function nativeBind (fn, ctx) {
- return fn.bind(ctx)
- }
- var bind = Function.prototype.bind
- ? nativeBind
- : polyfillBind;
你可能看不懂上面的用法,下面我們一一拋開(kāi)謎底。
當(dāng)一個(gè)新事物的出現(xiàn),總是有目的的,那么 apply、call 和 bind 的出現(xiàn)是為了解決什么問(wèn)題呢?它們?yōu)槭裁词呛瘮?shù)的方法呢?為什么不是其它對(duì)象的方法。
通過(guò) apply、call 可以自定義 this 調(diào)用某個(gè)函數(shù),比如定義一個(gè)全局函數(shù)(嚴(yán)格模式):
- 'use strict';
- function gFun(name, age) {
- console.log(this);
- }
這個(gè)函數(shù)可以通過(guò)下面 5 種方式調(diào)用,也就是說(shuō)通過(guò) apply、call、bind 可以調(diào)用一個(gè)函數(shù) F,其中「函數(shù) F 執(zhí)行上下文中的 this 可以在調(diào)用時(shí)指定」:
1.直接調(diào)用:
- gFun('suyan', 20); // this 為 undefined
2.通過(guò) this 調(diào)用:
- this.gFun('suyan', 20); // this 為 window
3.通過(guò) apply 調(diào)用,把所有的參數(shù)組合成一個(gè)數(shù)組作為 apply 的參數(shù):
- gFun.apply(this, ['suyan', 20]); // this 為 window
4.通過(guò) call 調(diào)用,參數(shù)通過(guò)逗號(hào)分割,這是與 apply 調(diào)用的區(qū)別:
- gFun.call(this, 'suyan', 20); // this 為 window
5.通過(guò) bind 調(diào)用,會(huì)返回一個(gè)原函數(shù)的拷貝,并擁有指定的 this和參數(shù):
- let bGFun = gFun.bind(this, 'suyan', 20);
- bGFun(); // this 為 window
我們一起看一些例子:
例1、setTimeOut 的使用:
- const time = {
- second: 1,
- afterOneSecond() {
- setTimeout(function () {
- this.second += 1;
- console.log(this.second);
- }, 1000);
- }
- };
- time.afterOneSecond();
上面這段代碼執(zhí)行后,第 6 行代碼的打印結(jié)果是 NaN,在連接你、我、他 —— this 這節(jié)課程中我們有提到過(guò) this 設(shè)計(jì)的一個(gè)弊端是不能繼承。其實(shí)可以通過(guò) bind 改造一下這個(gè)函數(shù):
- const time = {
- second: 1,
- afterOneSecond() {
- setTimeout(this.timeInvoke.bind(this), 1000);
- },
- timeInvoke() {
- this.second += 1;
- console.log(this.second);
- }
- };
- time.afterOneSecond();
函數(shù) timeInvoke 通過(guò) bind 綁定 this,并返回一個(gè)新的函數(shù),執(zhí)行結(jié)果為 2。bind 好像具有「暫存」的功能,把當(dāng)前的 this 暫存起來(lái)。
例 2、函數(shù)調(diào)用
- const person = {
- name: 'suyan',
- age: 20,
- showName(pre) {
- return pre + '-' + this.name;
- },
- update(name, age) {
- this.name = name;
- this.age = age;
- }
- };
- function generateName(fun) {
- let name = fun();
- console.log('showName = ', name);
- }
- generateName(person.showName);
執(zhí)行上面代碼會(huì)報(bào)錯(cuò),因?yàn)?showName 中的 this 為 undefined:
可以通過(guò) bind 「暫存 this」:
- const person = {
- name: 'suyan',
- age: 20,
- showName(pre) {
- return pre + '-' + this.name;
- },
- update(name, age) {
- this.name = name;
- this.age = age;
- }
- };
- function generateName(fun) {
- let name = fun();
- console.log('showName = ', name);
- }
- // 指定 this 為 person 對(duì)象
- let bindShowName = person.showName.bind(person, '前端小課');
- generateName(bindShowName);
例 3、構(gòu)造函數(shù),通過(guò) call 來(lái)調(diào)用某個(gè)函數(shù),替換 this。
- function Product(name, price) {
- this.name = name;
- this.price = price;
- }
- function Food(name, price) {
- // 調(diào)用 Product 函數(shù)
- Product.call(this, name, price);
- this.catagory = 'food';
- }
- let food = new Food('包子', 1);
- console.log(food.name); // 包子
例 4、調(diào)用匿名函數(shù)
- const animals = [
- {
- name: 'King'
- },
- {
- name: 'Fail'
- }
- ];
- for (let i = 0; i < animals.length; i++) {
- (function (i) {
- // 可以直接使用 this
- this.print = function () {
- console.log('#' + i + ' ' + this.name);
- };
- this.print();
- }).call(animals[i], i);
- }
結(jié)果為:
回頭再看看課程開(kāi)始之前 Vue 中關(guān)于 apply、call 和 bind 的應(yīng)用,是不是能看懂了?
分享題目:函數(shù)中的 this 不止有 72 變
地址分享:http://m.5511xx.com/article/dhiiode.html


咨詢
建站咨詢
