深入之bind的模拟实现,深入之call和apply的模拟实现

深入之bind的模拟实现,深入之call和apply的模拟实现。JavaScript 深切之new的模仿达成

2017/05/26 · JavaScript
· new

初稿出处: 冴羽   

已离开简书,原因参见
http://www.jianshu.com/p/0f12350a6b66。

JavaScript 深刻之bind的因循古板完成

2017/05/26 · JavaScript
· bind

初稿出处: 冴羽   

JavaScript 深远之call和apply的画虎不成反类犬完结

2017/05/25 · JavaScript
· apply,
call

原稿出处: 冴羽   

new

一句话介绍 new:

new
运算符成立2个用户定义的对象类型的实例或具有构造函数的放权对象类型之1

兴许有点难懂,我们在模拟 new 以前,先看看 new 完毕了什么职能。

举个例证:

// Otaku 御宅族,简称宅 function Otaku (name, age) { this.name = name;
this.age = age; this.habit = ‘加梅斯’; } //
因为不够锻练的原委,身体强度令人焦虑 Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () { console.log(‘I am ‘ +
this.name); } var person = new Otaku(‘凯文’, ‘1八’);
console.log(person.name) // 凯文 console.log(person.habit) // Gamesconsole.log(person.strength) // 60 person.sayYourName(); // I am 凯文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Otaku 御宅族,简称宅
function Otaku (name, age) {
    this.name = name;
    this.age = age;
 
    this.habit = ‘Games’;
}
 
// 因为缺乏锻炼的缘故,身体强度让人担忧
Otaku.prototype.strength = 60;
 
Otaku.prototype.sayYourName = function () {
    console.log(‘I am ‘ + this.name);
}
 
var person = new Otaku(‘Kevin’, ’18’);
 
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
 
person.sayYourName(); // I am Kevin

从那么些例子中,大家能够阅览,实例 person 能够:

  1. 做客到 Otaku 构造函数里的质量
  2. 走访到 Otaku.prototype 中的属性

接下去,我们得以品味着模拟一下了。

因为 new 是重点字,所以不或许像 bind
函数1样直接覆盖,所以大家写二个函数,命名称叫 objectFactory,来效仿 new
的效劳。用的时候是那样的:

function Otaku () { …… } // 使用 new var person = new Otaku(……); // 使用
objectFactory var person = objectFactory(Otaku, ……)

1
2
3
4
5
6
7
8
function Otaku () {
    ……
}
 
// 使用 new
var person = new Otaku(……);
// 使用 objectFactory
var person = objectFactory(Otaku, ……)

虽卑不足道,但也要有本人的态度。

bind

一句话介绍 bind:

bind() 方法会创造二个新函数。当以此新函数被调用时,bind()
的第三个参数将作为它运维时的
this,之后的壹种类参数将会在传递的实参前流传作为它的参数。(来自于 MDN
)

透过我们能够率先得出 bind 函数的两个性状:

  1. 回来一个函数
  2. 能够流传参数

call

一句话介绍 call:

call() 方法在行使二个内定的 this
值和多少个内定的参数值的前提下调用某些函数或格局。

举个例证:

var foo = { value: 1 }; function bar() { console.log(this.value); }
bar.call(foo); // 1

1
2
3
4
5
6
7
8
9
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call(foo); // 1

小心两点:

  1. call 改变了 this 的指向,指向到 foo
  2. bar 函数执行了

始发实现

分析:

因为 new
的结果是一个新目的,所以在模拟达成的时候,大家也要身无寸铁一个新对象,假若这些目的叫
obj,因为 obj 会具有 Otaku
构造函数里的习性,想想经典再而三的例子,大家得以选拔 Otaku.apply(obj,
arguments)来给 obj 添加新的品质。

在 JavaScript 深刻体系第3篇中,大家便讲了原型与原型链,大家知晓实例的
__proto__ 属性会指向构造函数的
prototype,也多亏因为建立起这么的涉嫌,实例能够访问原型上的性质。

今昔,大家得以尝尝着写第三版了:

// 第一版代码 function objectFactory() { var obj = new Object(),
Constructor = [].shift.call(arguments); obj.__proto__ =
Constructor.prototype; Constructor.apply(obj, arguments); return obj; };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 第一版代码
function objectFactory() {
 
    var obj = new Object(),
 
    Constructor = [].shift.call(arguments);
 
    obj.__proto__ = Constructor.prototype;
 
    Constructor.apply(obj, arguments);
 
    return obj;
 
};

在那1版中,大家:

  1. 用new Object() 的方法新建了3个指标 obj
  2. 取出第二个参数,正是我们要传播的构造函数。其它因为 shift
    会修改原数组,所以 arguments 会被去除第一个参数
  3. 将 obj 的原型指向构造函数,那样 obj 就足以访问到构造函数原型中的属性
  4. 动用 apply,改变构造函数 this 的指向到新建的靶子,那样 obj
    就能够访问到构造函数中的属性
  5. 返回 obj

愈多关于:

原型与原型链,可以看《JavaScript深远之从原型到原型链》

apply,可以看《JavaScript深刻之call和apply的效仿落成》

经典三番五次,能够看《JavaScript浓厚之继续》

复制以下的代码,到浏览器中,大家能够做一下测试:

function Otaku (name, age) { this.name = name; this.age = age;
this.habit = ‘Games’; } Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () { console.log(‘I am ‘ +
this.name); } function objectFactory() { var obj = new Object(),
Constructor = [].shift.call(arguments); obj.__proto__ =
Constructor.prototype; Constructor.apply(obj, arguments); return obj; };
var person = objectFactory(Otaku, ‘Kevin’, ’18’)
console.log(person.name) // Kevin console.log(person.habit) // Games
console.log(person.strength) // 60 person.sayYourName(); // I am Kevin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Otaku (name, age) {
    this.name = name;
    this.age = age;
 
    this.habit = ‘Games’;
}
 
Otaku.prototype.strength = 60;
 
Otaku.prototype.sayYourName = function () {
    console.log(‘I am ‘ + this.name);
}
 
function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj, arguments);
    return obj;
};
 
var person = objectFactory(Otaku, ‘Kevin’, ’18’)
 
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
 
person.sayYourName(); // I am Kevin

[]~( ̄▽ ̄)~**

小说能够在自家的 Github
https://github.com/mqyqingfeng/Blog
查看

回去函数的效仿实现

从第11个特点伊始,大家举个例子:

var foo = { value: 1 }; function bar() { console.log(this.value); } //
再次来到了三个函数 var bindFoo = bar.bind(foo); bindFoo(); // 1

1
2
3
4
5
6
7
8
9
10
11
12
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
// 返回了一个函数
var bindFoo = bar.bind(foo);
 
bindFoo(); // 1

有关钦赐 this 的针对,我们能够使用 call 也许 apply 实现,关于 call 和
apply
的效仿实现,可以查阅《JavaScript深切之call和apply的效仿完结》。大家来写第壹版的代码:

// 第一版 Function.prototype.bind2 = function (context) { var self =
this; return function () { self.apply(context); } }

1
2
3
4
5
6
7
8
// 第一版
Function.prototype.bind2 = function (context) {
    var self = this;
    return function () {
        self.apply(context);
    }
 
}

依样画葫芦完毕率先步

那正是说大家该怎么模拟达成那四个作用呢?

试想当调用 call 的时候,把 foo 对象改造成如下:

var foo = { value: 1, bar: function() { console.log(this.value) } };
foo.bar(); // 1

1
2
3
4
5
6
7
8
var foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
};
 
foo.bar(); // 1

其近期候 this 就本着了 foo,是或不是相当的粗略吗?

只是如此却给 foo 对象自作者添加了3个属性,那可不行呀!

唯独也不用担心,大家用 delete 再删除它不就好了~

为此大家模拟的步调能够分为:

  1. 将函数设为对象的习性
  2. 实践该函数
  3. 删去该函数

上述个例子为例,就是:

// 第一步 foo.fn = bar // 第二步 foo.fn() // 第三步 delete foo.fn

1
2
3
4
5
6
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn

fn 是目的的属性名,反正最后也要去除它,所以起成怎样都无所谓。

据说这么些思路,我们能够品尝着去写第叁版的 call2 函数:

// 第3版 Function.prototype.call二 = function(context) { //
首先要收获调用call的函数,用this可以博得 context.fn = this;
context.fn(); delete context.fn; } // 测试一下 var foo = { value: 一 };
function bar() { console.log(this.value); } bar.call2(foo); // 壹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 第一版
Function.prototype.call2 = function(context) {
    // 首先要获取调用call的函数,用this可以获取
    context.fn = this;
    context.fn();
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call2(foo); // 1

恰好能够打字与印刷 一 哎!是还是不是很春风得意!(~ ̄▽ ̄)~

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图