深入之new的模拟实现,深入之bind的模拟实现

JavaScript 深远之new的模仿完结

2017/05/26 · JavaScript
· new

初稿出处: 冴羽   

已离开简书,原因参见
http://www.jianshu.com/p/0f12350a6b66深入之new的模拟实现,深入之bind的模拟实现。。

JavaScript 深切之bind的停滞不前完成

2017/05/26 · JavaScript
· bind

原稿出处: 冴羽   

JavaScript 深远之call和apply的依样葫芦完结

2017/05/25 · JavaScript
· apply,
call

原著出处: 冴羽   

new

一句话介绍 new:

new
运算符创建1个用户定义的对象类型的实例或持有构造函数的停放对象类型之一

恐怕有点难懂,我们在模拟 new 此前,先看看 new 达成了哪些功用。

举个例子:

// 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(‘凯文’, ’18’);
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
函数一样直接覆盖,所以我们写2个函数,命名为 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() 方法在使用2个钦点的 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
的结果是1个新对象,所以在模仿达成的时候,大家也要成立3个新指标,假若这么些目的叫
obj,因为 obj 会具有 Otaku
构造函数里的性子,想想经典一连的例子,大家得以应用 Otaku.apply(obj,
arguments)来给 obj 添加新的性质。

在 JavaScript 长远种类第三篇中,我们便讲了原型与原型链,大家驾驭实例的
__proto__ 属性会指向构造函数的
prototype,也多亏因为建立起这么的涉嫌,实例能够访问原型上的质量。

明天,我们能够尝尝着写第②版了:

// 第1版代码 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. 用new Object() 的艺术新建了2个对象 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
查看

回去函数的模仿达成

从第陆个特征初叶,大家举个例子:

var foo = { value: 1 }; function bar() { console.log(this.value); } //
重返了3个函数 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 对象自小编添加了叁本品质,那可不行呀!

但是也不用担心,我们用 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 函数:

// 第贰版 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

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

恰巧能够打字与印刷 1 哎!是还是不是很心花怒放!(~ ̄▽ ̄)~

相关文章