菜单

【澳门金沙app】JavaScript深远之call和apply的模仿完成(转)

2019年4月12日 - 金沙前端

类数组对象

所谓的类数组对象:

负有三个 length 属性和若干索引属性的靶子

举个例子:

var array = [‘name’, ‘age’, ‘sex’]; var arrayLike = { 0: ‘name’, 1:
‘age’, 2: ‘sex’, length: 3 }

1
2
3
4
5
6
7
8
var array = [‘name’, ‘age’, ‘sex’];
 
var arrayLike = {
    0: ‘name’,
    1: ‘age’,
    2: ‘sex’,
    length: 3
}

即使如此,为何叫做类数组对象呢?

那让大家从读写、获取长度、遍历多个地点看看那多少个对象。

模仿实现率先步

那么大家该怎么模拟达成那四个效益啊?

试想当调用 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 是目的的属性名,反正最终也要刨除它,所以起成什么都无所谓。

基于那些思路,大家能够尝尝着去写第3版的 call2 函数:

// 第三版 Function.prototype.call2 = function(context) { //
首先要收获调用call的函数,用this能够获取 context.fn = this;
context.fn(); delete context.fn; } // 测试一下 var foo = { value: 一 };
function bar() { console.log(this.value); } bar.call二(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

刚刚能够打字与印刷 一 哎!是或不是很满面红光!(~ ̄▽ ̄)~

fn 是指标的属性名,反正最后也要刨除它,所以起成什么都不在乎。
据书上说这么些思路,我们能够品尝着去写第1版的 call2 函数:
// 第贰版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.call贰(foo); // 一

JavaScript与ECMAScript的关系?

类数组转对象

在上头的例子中一度关系了一体系数组转数组的格局,再补充多个:

var arrayLike = {0: ‘name’, 1: ‘age’, 2: ‘sex’, length: 3 } // 1. slice
Array.prototype.slice.call(arrayLike); // [“name”, “age”, “sex”] // 2.
splice Array.prototype.splice.call(arrayLike, 0); // [“name”, “age”,
“sex”] // 3. ES6 Array.from Array.from(arrayLike); // [“name”, “age”,
“sex”] // 4. apply Array.prototype.concat.apply([], arrayLike)

1
2
3
4
5
6
7
8
9
var arrayLike = {0: ‘name’, 1: ‘age’, 2: ‘sex’, length: 3 }
// 1. slice
Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"]
// 2. splice
Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"]
// 3. ES6 Array.from
Array.from(arrayLike); // ["name", "age", "sex"]
// 4. apply
Array.prototype.concat.apply([], arrayLike)

那正是说为啥会讲到类数组对象呢?以及类数组有啥样应用吗?

要聊到类数组对象,Arguments 对象就是二个类数组对象。在客户端 JavaScript
中,一些 DOM 方法(document.getElementsByTagName()等)也回到类数组对象。

仿照完毕第二步

最1开端也讲了,call 函数还是能够给定参数执行函数。举个例子:

var foo = { value: 1 }; function bar(name, age) { console.log(name)
console.log(age) console.log(this.value); } bar.call(foo, ‘kevin’, 18);
// kevin // 18 // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call(foo, ‘kevin’, 18);
// kevin
// 18
// 1

在意:传入的参数并不鲜明,那可如何做?

不急,大家能够从 Arguments
对象中取值,取出第3个到终极3个参数,然后放到叁个数组里。

例如那样:

// 以上个例子为例,此时的arguments为: // arguments = { // 0: foo, // 壹:
‘kevin’, // 2: 1八, // length: 三 // } //
因为arguments是类数组对象,所以能够用for循环 var args = []; for(var i
= 1, len = arguments.length; i len; i++) { args.push(‘arguments[‘ + i +
‘]’); } // 执行后 args为 [foo, ‘kevin’, 18]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 以上个例子为例,此时的arguments为:
// arguments = {
//      0: foo,
//      1: ‘kevin’,
//      2: 18,
//      length: 3
// }
// 因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1, len = arguments.length; i  len; i++) {
    args.push(‘arguments[‘ + i + ‘]’);
}
 
// 执行后 args为 [foo, ‘kevin’, 18]

不定长的参数难点消除了,我们跟着要把那个参数数组放到要实践的函数的参数里面去。

// 将数组里的要素作为多少个参数放进函数的形参里 context.fn(args.join(‘,’))
// (O_o)?? // 这么些方法自然是可怜的呐!!!

1
2
3
4
// 将数组里的元素作为多个参数放进函数的形参里
context.fn(args.join(‘,’))
// (O_o)??
// 这个方法肯定是不行的啦!!!

恐怕有人想到用 ES六 的章程,可是 call 是 ES叁 的措施,大家为了模仿达成一个ES三 的艺术,要用到ES陆的不2秘诀,好像……,嗯,也能够啊。可是大家本次用 eval
方法拼成3个函数,类似于如此:

eval(‘context.fn(‘ + args +’)’)

1
eval(‘context.fn(‘ + args +’)’)

此间 args 会自动调用 Array.toString() 那些方法。

于是我们的第2版打败了多个大题材,代码如下:

// 第二版 Function.prototype.call2 = function(context) { context.fn =
this; var args = []; for(var i = 1, len = arguments.length; i len;
i++) { args.push(‘arguments[‘ + i + ‘]’); } eval(‘context.fn(‘ + args
+’)’); delete context.fn; } // 测试一下 var foo = { value: 一 }; function
bar(name, age) { console.log(name) console.log(age)
console.log(this.value); } bar.call贰(foo, ‘kevin’, 1捌); // kevin // 18
// 一

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
// 第二版
Function.prototype.call2 = function(context) {
    context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i  len; i++) {
        args.push(‘arguments[‘ + i + ‘]’);
    }
    eval(‘context.fn(‘ + args +’)’);
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call2(foo, ‘kevin’, 18);
// kevin
// 18
// 1

(๑•̀ㅂ•́)و✧

那一年 this 就对准了 foo,是还是不是相当的粗略吗?
但是这么却给 foo 对象自作者添加了八天性质,那可足够呀!
只是也不用担心,大家用 delete 再删除它不就好了~
就此咱们模拟的手续能够分为:
将函数设为对象的品质
履行该函数
去除该函数

变量赋值

var a = 1;  //window.a = 1;  全局变量
function(){var a = 1;} //只能在函数体内访问到变量a

let a = 1; //window.a ===undefined;
{
let a,b,c;
[a,b,c=3] = [1,2];   // let a = 1; let b = 2; let b =3;
}
{
let a,b,c;
[a,,b,,c] = [1,2,3,4,5,6,7,8,9,10];
console.log(a,b,c); //1,3,5
}
{
let o = {a:1,b:2};
let {a,b} = o;
console.log(a,b);//1,2
}
{
let o = {a:1,b:2};
let {a=2,b} = o;
console.log(a,b);//1,2
}
{
let metaData = {
 number:'1',
 info:[{
name:'chen'
}]
};
let {number:Num,info:[{name:name}]} = metaData;
console.log(Num,name);   // Num:'1',name:'chen'
}
{
    function test(){
         return [1,2,3,4,5,6,7]
     }
  let a;
[...a] = test(); // let a = [1,2,3,4,5,6,7];
}
{
let a = 1; let b = 2;
[a,b] = [b,a];
console.log(a,b)  //变量交换
}
{
let a,b,c;
[a,b,...c] = [1,2,3,4,5,6,7];  // let a = 1;let b = 2; let c = [4,5,6,7];
}
{
let a,b;
({a,b} ={a:1,b:2});
console.log(a,b); // 1,2;
}

callee属性

Arguments 对象的 callee 属性,通过它可以调用函数本人。

讲个闭包经典面试题使用 callee 的缓解办法:

var data = []; for (var i = 0; i 3; i++) { (data[i] = function () {
console.log(arguments.callee.i) }).i = i; } data[0](); data[1]();
data[2](); // 0 // 1 // 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var data = [];
 
for (var i = 0; i  3; i++) {
    (data[i] = function () {
       console.log(arguments.callee.i)
    }).i = i;
}
 
data[0]();
data[1]();
data[2]();
 
// 0
// 1
// 2

接下去讲讲 arguments 对象的多少个注意要点:

JavaScript 深远之call和apply的模仿实现

2017/05/25 · JavaScript
· apply,
call

原版的书文出处: 金沙国际娱乐场官网,冴羽   

长远类别
JavaScript深切系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深远类别测度写10伍篇左右,意在帮大家捋顺JavaScript底层知识,重点讲解如原型、功效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
奥门金沙网站,借使有错误或然不严厉的地方,请务必给予指正,十二分感激。要是喜欢大概具有启发,欢迎star,对小编也是壹种鞭策。

哪些在浏览器中运作JavaScript?

JavaScript 深切之类数组对象与 arguments

2017/05/27 · JavaScript
· arguments

原版的书文出处: 冴羽   

深远连串

JavaScript深远体系目录地址:。

JavaScript深远类别猜测写105篇左右,意在帮我们捋顺JavaScript底层知识,重点教学如原型、成效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难题概念。

假定有不当大概不审慎的地方,请务必给予指正,13分多谢。假如喜欢只怕持有启发,欢迎star,对小编也是1种鞭策。

澳门金沙app,本系列:

  1. JavaScirpt 深刻之从原型到原型链
  2. JavaScript
    深远之词法成效域和动态作用域
  3. JavaScript 深入之实践上下文栈
  4. JavaScript 深切之变量对象
  5. JavaScript 深切之作用域链
  6. JavaScript 深远之从 ECMAScript 规范解读
    this
  7. JavaScript 深远之实践上下文
  8. JavaScript 深刻之闭包
  9. JavaScript 深远之参数按值传递

    1 赞 收藏
    评论

澳门金沙app 1

或是有人想到用 ES6 的措施,但是 call 是 ES三 的艺术,大家为了仿效完毕一个ES三 的不二法门,要用到ES陆的不贰法门,好像……,嗯,也足以啦。不过我们这一次用 eval
方法拼成一个函数,类似于那样:
eval(‘context.fn(‘ + args +’)’)

JavaScript 变量表明进步

console.log(a); //undefind
var a = 1;
//等同如下
var a;
console.log(a);  //undefind
a = 1;

console.log(a); // ReferenceError: a is not defined
let a = 1;

length属性

Arguments对象的length属性,表示实参的长短,举个例证:

function foo(b, c, d){ console.log(“实参的尺寸为:” + arguments.length)
} console.log(“形参的长短为:” + foo.length) foo(一) // 形参的长短为:3
// 实参的长度为:一

1
2
3
4
5
6
7
8
9
10
function foo(b, c, d){
    console.log("实参的长度为:" + arguments.length)
}
 
console.log("形参的长度为:" + foo.length)
 
foo(1)
 
// 形参的长度为:3
// 实参的长度为:1

根本参照

网易难点 不能够接纳call、apply、bind,怎么着用 js 达成 call 恐怕 apply
的功力?

不定长的参数难点消除了,大家随后要把那一个参数数组放到要推行的函数的参数里面去。
//
将数组里的成分作为八个参数放进函数的形参里context.fn(args.join(‘,’))//
(O_o)??// 那几个点子肯定是丰富的啊!!!

区块(块级功能域)

{
var a = 1;
}
console.log(a); // 1

{
let a = 1; const b =1;
}
console.log(a); // ReferenceError: a is not defined
console.log(b); // ReferenceError: a is not defined
{
let a = 1;
let a = 2;
console.log(a) //"SyntaxError: Identifier 'a' has already been declared(同一作用域重复声明一个变量报错)。
}
{
var a = 1;
var a = 2;
console.log(a);//2 var 重复声明同一变量取最后一次声明的赋值。
}

相关文章

发表评论

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

网站地图xml地图