JavaScript深刻之call和apply的模拟已毕,深刻之call和apply的上行下效落成

JavaScript 长远之类数组对象与 arguments

2017/05/27 · JavaScript
· arguments

JavaScript深刻之call和apply的模拟已毕,深刻之call和apply的上行下效落成。原稿出处: 冴羽   

JavaScript 深切之call和apply的模拟完成

2017/05/25 · JavaScript
· apply,
call

原文出处: 冴羽   

透过call和apply的模拟完毕,带您揭秘call和apply改变this的面目

JavaScript之父:Brendan Eich 。

-基本语法:借鉴了C语言和Java语言。
-数据结构:借鉴了Java,包涵将值分成原始值和目的两大类。

  • 函数的用法:借鉴了Scheme和Awk语言,将函数当成第一等平民,引入闭包。
  • 原型继承模型:借鉴了Self语言。
  • 正则表明式:借鉴了Perl语言。
  • 字符串和数组处理:借鉴了Python语言。

类数组对象

所谓的类数组对象:

不无一个 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

一句话介绍 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 函数执行了

call
一句话介绍 call:
call() 方法在利用一个点名的 this
值和多少个指定的参数值的前提下调用某个函数或方法。

JavaScript与ECMAScript的关系?
  • ECMAScript规定了浏览器脚本语言的正规化。
  • ECMAScript是JavaScript的规格。

读写

console.log(array[0]); // name console.log(arrayLike[0]); // name
array[0] = ‘new name’; arrayLike[0] = ‘new name’;

1
2
3
4
5
console.log(array[0]); // name
console.log(arrayLike[0]); // name
 
array[0] = ‘new name’;
arrayLike[0] = ‘new name’;

模仿完毕率先步

那么大家该怎么模拟完成这八个效益呢?

试想当调用 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 哎!是还是不是很喜笑颜开!(~ ̄▽ ̄)~

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

什么在浏览器中运作JavaScript?
  • <script> console.log(‘运行JS’) </script>
  • <script src=’./*’> </script>

长度

console.log(array.length); // 3 console.log(arrayLike.length); // 3

1
2
console.log(array.length); // 3
console.log(arrayLike.length); // 3

萧规曹随完毕第二步

最一初始也讲了,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
对象中取值,取出第三个到终极一个参数,然后放到一个数组里。

例如那样:

// 以上个例证为例,此时的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]

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)??
// 这个方法肯定是不行的啦!!!

或者有人想到用 ES6 的方法,可是 call 是 ES3 的法子,大家为了模仿落成一个
ES3 的办法,要用到ES6的办法,好像……,嗯,也足以啊。不过我们本次用 eval
方法拼成一个函数,类似于如此:

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

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

那里 args 会自动调用 Array.toString() 那几个法子。

就此大家的第二版克制了八个大题目,代码如下:

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

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

(๑•̀ㅂ•́)و✧

只顾两点:
call 改变了 this 的指向,指向到 foo
bar 函数执行了

JavaScript 声明变量
  • var a;
  • let a;

遍历

for(var i = 0, len = array.length; i len; i++) { …… } for(var i = 0, len
= arrayLike.length; i len; i++) { …… }

1
2
3
4
5
6
for(var i = 0, len = array.length; i  len; i++) {
   ……
}
for(var i = 0, len = arrayLike.length; i  len; i++) {
    ……
}

是否很像?

那类数组对象足以选用数组的法门吧?比如:

arrayLike.push(‘4’);

1
arrayLike.push(‘4’);

可是上述代码会报错: arrayLike.push is not a function

因此究竟仍旧类数组呐……

依傍完毕第三步

模仿代码已经达成 80%,还有八个小点要专注:

1.this 参数可以传 null,当为 null 的时候,视为指向 window

举个例子:

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

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

即使这一个事例本身不利用 call,结果依然仍旧一样。

2.函数是足以有再次来到值的!

举个例子:

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

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

然而都很好解决,让大家一贯看第三版也就是最终一版的代码:

// 第三版 Function.prototype.call2 = function (context) { var context =
context || window; context.fn = this; var args = []; for(var i = 1,
len = arguments.length; i len; i++) { args.push(‘arguments[‘ + i +
‘]’); } var result = eval(‘context.fn(‘ + args +’)’); delete context.fn
return result; } // 测试一下 var value = 2; var obj = { value: 1 }
function bar(name, age) { console.log(this.value); return { value:
this.value, name: name, age: age } } bar.call(null); // 2
console.log(bar.call2(obj, ‘kevin’, 18)); // 1 // Object { // value: 1,
// name: ‘kevin’, // age: 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 第三版
Function.prototype.call2 = function (context) {
    var context = context || window;
    context.fn = this;
 
    var args = [];
    for(var i = 1, len = arguments.length; i  len; i++) {
        args.push(‘arguments[‘ + i + ‘]’);
    }
 
    var result = eval(‘context.fn(‘ + args +’)’);
 
    delete context.fn
    return result;
}
 
// 测试一下
var value = 2;
 
var obj = {
    value: 1
}
 
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
bar.call(null); // 2
 
console.log(bar.call2(obj, ‘kevin’, 18));
// 1
// Object {
//    value: 1,
//    name: ‘kevin’,
//    age: 18
// }

到此,大家做到了 call 的效仿已毕,给协调一个赞 b( ̄▽ ̄)d

仿照达成率先步
那就是说大家该怎么模拟落成那四个功用啊?
试想当调用 call 的时候,把 foo 对象改造成如下:
var foo = { value: 1, bar: function() { console.log(this.value)
}};foo.bar(); // 1

变量赋值
  • ES5

var a = 1;  //window.a = 1;  全局变量
function(){var a = 1;} //只能在函数体内访问到变量a
  • ES6新增结构赋值

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

调用数组方法

一旦类数组就是随便的想用数组的点子怎么做吧?

既然如此不能直接调用,大家可以用 Function.call 直接调用:

var arrayLike = {0: ‘name’, 1: ‘age’, 2: ‘sex’, length: 3 }
Array.prototype.join.call(arrayLike, ‘&’); // name&age&sex
Array.prototype.slice.call(arrayLike, 0); // [“name”, “age”, “sex”] //
slice可以成功类数组转数组 Array.prototype.map.call(arrayLike,
function(item){ return item.toUpperCase(); }); // [“NAME”, “AGE”,
“SEX”]

1
2
3
4
5
6
7
8
9
10
11
var arrayLike = {0: ‘name’, 1: ‘age’, 2: ‘sex’, length: 3 }
 
Array.prototype.join.call(arrayLike, ‘&’); // name&age&sex
 
Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"]
// slice可以做到类数组转数组
 
Array.prototype.map.call(arrayLike, function(item){
    return item.toUpperCase();
});
// ["NAME", "AGE", "SEX"]

apply的模拟达成

apply 的达成跟 call 类似,在那里一向给代码,代码来自于天涯论坛 @郑航的贯彻:

Function.prototype.apply = function (context, arr) { var context =
Object(context) || window; context.fn = this; var result; if (!arr) {
result = context.fn(); } else { var args = []; for (var i = 0, len =
arr.length; i len; i++) { args.push(‘arr[‘ + i + ‘]’); } result =
eval(‘context.fn(‘ + args + ‘)’) } delete context.fn return result; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;
 
    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i  len; i++) {
            args.push(‘arr[‘ + i + ‘]’);
        }
        result = eval(‘context.fn(‘ + args + ‘)’)
    }
 
    delete context.fn
    return result;
}

其一时候 this 就针对了 foo,是还是不是很简短吗?
而是这么却给 foo 对象自我添加了一个属性,这可那些啊!
可是也不用担心,我们用 delete 再删除它不就好了~
从而大家模拟的步子可以分成:
将函数设为对象的性能
实施该函数
剔除该函数

JavaScript 变量表明升高
  • ES5

console.log(a); //undefind
var a = 1;
//等同如下
var a;
console.log(a);  //undefind
a = 1;
  • ES6:let声明变量不升级

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

类数组转对象

在上边的事例中一度涉嫌了一连串数组转数组的措施,再补偿三个:

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()等)也回到类数组对象。

最主要参考

腾讯网问题 无法应用call、apply、bind,怎么着用 js 完结 call 或者 apply
的效用?

如上个例子为例,就是:
// 第一步foo.fn = bar// 第二步foo.fn()// 第三步delete foo.fn

标识符
  • 概念:识别具体目的的一个名称(大小写敏感),如变量名,函数名。
  • 规则:
    • 首个字符,可是任意Unicode字母,以及美金符号($),和下划线(_)。
    • 第三个字符以及背后的字符,除了Unicode,美金符号以及下划线,还足以是数字0-9。
  • 保留字和重点字不可能看做标识符(如:var 、class、false、true)。

Arguments对象

接下去重点讲讲 Arguments 对象。

Arguments
对象只定义在函数体中,包含了函数的参数和任何属性。在函数体中,arguments
指代该函数的 Arguments 对象。

举个例子:

function foo(name, age, sex) { console.log(arguments); } foo(‘name’,
‘age’, ‘sex’)

1
2
3
4
5
function foo(name, age, sex) {
    console.log(arguments);
}
 
foo(‘name’, ‘age’, ‘sex’)

打印结果如下:

亚洲必赢官网 1

咱俩得以观察除了类数组的索引属性和length属性之外,还有一个callee属性,接下去我们一个一个介绍。

深深种类

JavaScript长远连串目录地址:。

JavaScript长远体系估算写十五篇左右,目的在于帮大家捋顺JavaScript底层知识,重点教学如原型、效能域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。

比方有荒唐或者不谨慎的地点,请务必给予指正,万分谢谢。如若喜欢依旧持有启发,欢迎star,对小编也是一种鞭策。

本系列:

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

    1 赞 收藏
    评论

亚洲必赢官网 2

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

注释
  • 单行:/那是注释/。
  • 多行:/*那是注释*/。

length属性

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

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

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

刚巧可以打印 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

区块(块级功用域)
  • ES5:不设有块级效用域

{
var a = 1;
}
console.log(a); // 1
  • ES6:使用let、const注明变量或常量(存在块级成效域)

{
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 重复声明同一变量取最后一次声明的赋值。
}

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 对象的多少个注意要点:

只顾:传入的参数并不确定,那可肿么办?
不急,大家得以从 Arguments
对象中取值,取出第一个到结尾一个参数,然后放到一个数组里。
比如说那样:
// 以上个例证为例,此时的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]

标准化语句
  • if语句

if(true){
console.log('我被执行了')
}else{
console.log('我永远不会被执行')
}
  • switch语句

var f = 'apple';
if(f ==='banana'){
console.log('banana')
}else if(f==='apple'){
console.log('apple')
}
//多个if(){}else if{}嵌套时使用switch语句
switch(f){
case 'banana' : console.log('banana');
break;
case 'apple':console.log('apple');
break;
default: console.log('default');
}
  • 岁首运算符

    – expression ? do(true): do(false);

 let a = false;
 let b = a ? 1:2;
 console.log(b) // 2;
}```

- while循环语句
 - 

{
let i = 0;
while(i<10){
console.log(i); //0~9
i++;
}
}
{
let i = 11;
do{
console.log(i);
i–;
}while(i<10);
}

- for循环语句

for(let i=0;i<100;i++){
console.log(i);//0~99
}

- break和continue关键字

{
for(let i=0;i<10;i++){

if(i>=5){break;}   
 console.log(i); //0~4

}
}
{
for(let i=0; i<10;i++){
if(i<=5){continue;}
console.log(i);// 6~9
}
}

##### 数据类型
- 数值(number)
- 字符串(string)
- 布尔值(boolean) 
 - 5个假值(null,undefined,0,'',NaN)
- undefined
- null
- 对象(object)
  - 数组(Array)  是一种对象
  - 函数(Function) 是一种对象
  - 普通对象  

##### 类型转换

{
let number = 1;
let string = number+”;
console.log(typeof string,string) //string,”1″
}
{
let number = 1;
let bool =!number;
console.log(typeof bool,bool) //boolean,false
}
{
let string = ‘123’;
//let number = string -0;
let number = +string;
console.log(typeof number,number) //number,123
}
{
let string = ‘hello’;
let number = string – 0;
console.log(typeof number,number) //NaN;
}
{
let bool = true;
let number = bool -0;
//let number = !bool -0; number, 0
console.log(typeof number,number) //number,1
}

- ##### 字符串方法以及遍历
  - ES5

//遍历
{
let string = “hello”;
for(let i = 0;i<string.length;i++){

console.log(string[i])

}
}
//method
{
let str = ‘hello’;
let newStr = str.substring(1,2); // [start,end)
console.log(str); // ‘hello’
console.log(newStr) // ‘e’
}
{
let str = ‘world’;
let newStr = str.substr(1,2); //start, deleteCount
console.log(str); // ‘world’
console.log(newStr) // ‘or’
}

- ES6

{
let string = “world”;
for(let i of string){
console.log(i)
}
}

 ##### 声明对象以及读写属性、遍历对象
- Obejct是一种无序的集合
 - ES5

{
let o = {
name:’小花’,
age:18,
skill: function(){console.log(‘say’)}
};
/*let o = new Object({
name:’小花’
}) */
console.log(o.name); //”小花”
o.name = ‘小草’;
console.log(o[‘name’]);//”小草”
console.log(‘name’ in o); //true
delete o.name; //o = {};
}
{
let o = {
name:’小草’,
age:18
}
for(let i in o){
console.log(i); //name,age
console.log(o[i]); //小草,18
}
}

 - ES6

{
let name = ‘xiaohua’,age = 16;
let o = {
name,
age,
skill(){
console.log(‘say’)
}
}
console.log(o.skill())
}
{
let a = ‘b’;
let es5_obj = {
a:’c’,
b:’c’
}
let es6_obj ={
[a]:’c’ //key可以用变量
}
console.log(es5_obj,es6_obj);
}

##### 声明数组、遍历数组
- Array是一种有序的集合

- 数组的一些方法
  - ES5

{
let array = [1,2,3,[4,5,6],{5:”6″,6:”7″,7:”8″}]; //申明数组
console.log(array);
console.log(array.length);//5;
for(let i = 0; i<array.length;i++){
console.log(i,”-“,array[i]);
}
array.push(9,10,11,[12,13,14],{name:”array”});
console.log(array);
array.pop();
console.log(array.length);
}
{
let arr = [2,3,1,4,5];
arr.sort();
console.log(arr);//[1,2,3,4,5]
arr.sort(function(a,b){return a<b});
console.log(arr);//[5,4,3,2,1]
}
{
let arr = [1,2,3,4,5];
let deleteArr = arr.splice(0,2,0,1,2);//array.splice(start, deleteCount,
item1, item2, …)
console.log(arr);
console.log(deleteArr);
}
{
let arr = [1,2,3,4];
let arrStr = arr.join(‘–‘);
console.log(arr);
console.log(arrStr);
let newArrStr = arrStr.split(‘–‘);
console.log(newArrStr);
}

  - ES6

{ //将伪数组转换成数组
function arg(){
argArray = Array.from(arguments,(item)=> item2);
//Array.from(arrayLike[, mapFn[, thisArg]])
console.log(argArray)
}
/

argArray = Array.from(arguments);
argArray.forEach(function(item){console.log(item)})
*/
arg(1,2,3,4,5)
}
{ //填充数组
let array = [1,2,3,4,5]亚洲必赢官网,; //arr.fill(value) arr.fill(value, start)
arr.fill(value, start, end)
newArray = array.fill(0);
console.log(newArray);
console.log(array);
console.log(array.fill(9,0,3));
console.log(array);
}
{ //遍历数组
let array = [1,2,3,4,5];
for(let i of array){
console.log(i) //1,2,3,4,5
}
for(let i of array.keys()){
console.log(i)//0,1,2,3,4
}
for(let [i,v] of array.entries()){
console.log(i,v)
}
console.log(array.find((item)=>item>3));
//查找知足条件,只回去首个
console.log(array.findIndex(item=>item>3));
{
let array = [1,2,3,4,5];
console.log(array.includes(1,0))//arr.includes(searchElement, fromIndex)
//是还是不是包涵
}
}

##### 声明函数,函数提升,arguments及...rest,length属性,闭包,同步V.S.异步
 - ES5

// var say = function(){}; 只会升高var say
function say(x){ //提高整个函数
console.log(x);
console.log(arguments)
//将传入所有实参生成一个伪数组,其实是一个key为有序下标的对象
return x //使函数具有重返值
}
say(‘hello’); //传入实参
console.log(say.length);//行参个数
var c =say(‘hello’); //重返值赋予变量c
console.log(c);
{ //立刻执行函数 防止全局污染
!function(){
var a = 1;
console.log(a)
}();
!function(){
var a = 2;
console.log(a)
}();
}
{ //闭包
function f1(){
var a = 1;
function f2(){
a++;
console.log(a)
}
return f2;
}

let result = f1();
result();
}
{//同步
console.log(1);
console.log(2);
console.log(3);
}
{//异步
console.log(1);
setTimeout(function(){
console.log(2);
},3000)
console.log(3);
}

 - ES6

{ //ES6存在块及成效域,不需求利用匿名函数来幸免全局污染
let a =1 ;
console.log(a);
}
{
let a = 2;
console.log(a);
}
{
function say(x,y = ‘world’){ //行参默许值
console.log(x,y);
}
say(‘hello’);
}
{
let say = (…arg)=>{
console.log(arg);
for(let i of arg){
console.log(i);
}
console.log(typeof arg.push) //那是一个真数组,和arguments分歧
}
say(‘hello’,’world’);
}
{
let x = ‘china’;
let say = (x,y = x)=>{
console.log(x,y);
}
say(‘hello’);//”hello hello”
}
{
let x = ‘china’;
let say = (z,y = x)=>{ //变量效能域,和上一个例子相比
console.log(z,y);
}
say(‘hello’);//”hello china”
}
{
let say = (x)=> x ;//此处要是加{}就不会有重临值
/*
var say = function(x){
return x
}
*/
let result = say(100);
console.log(result)
}
{ //函数作为再次来到值,函数作为参数的例子
let qux= ()=> (callback)=> callback();
let result = qux();
console.log(result);
result(()=>{console.log(“执行了”)})
}

类、原型、继承(面向对象)
  - ES5

{
function Person(name,age,gender){
this.name = name;
this.age =age;
this.gender = gender;
}
Person.prototype.born = function(){
console.log(‘born’)
}
function Man(){
Person.apply(this,arguments)
this.sex = ‘male’
}
let empty = function(){};
empty.prototype = Person.prototype;
Man.prototype = new empty();
console.log(Man.prototype.constructor = Man);
var man1 = new Man(‘张三’,18,’male’);
console.log(man1)
}
{
var name,age,gender;
var Person = {
name:name,
age:age,
gender:gender,
born:function(){console.log(‘born’)}
}
var Man = Object.create(Person);
Man.sex = ‘male’;
console.log(Man)
}

  - ES6 

{//ES6 类
class Person{
constructor(name=’张三’,age= 18,gender=’male’){
this.name = name;
this.age =age;
this.gender = gender;
};
born(){
console.log(‘born’)
};
die(){
console.log(‘die’)
}
}
console.log(new Person)
class Man extends Person{//类的存续
constructor(){
super();
this.sex = ‘Man’
}
}
let man1 = new Man()
console.log(man1)
console.log(man1.born())
}

##### 标准库
 - Array
 - String
 - Number
 - Function
 - Boolean
 - Math(console.dir(Math)  )
  - Math.PI;              //3.141592653589793
  - Math.SQRT2;      //1.4142135623730951
  -Math.pow();
  -Math.sqrt(); 
  - Math.random()*50+50 ;// 50~100之间的伪随机数
 - Date
  - new Date() 
    - 
       ```
{
let date = new Date();
  console.log(date);//Sat Jun 03 2017 01:27:41 GMT+0800 (CST)
  console.log(date.getFullYear())  //2017
  console.log(date.getMonth()) // 5   0~11个月
  console.log(date.getDate())  //3    
  console.log(date.getDay())  //6 星期日为0,星期一为1。
  console.log(date.getHours());
  console.log(date.getMinutes())
  console.log(date.getSeconds())
}
  • toLocaleString()

  • Promise

{
  function breakfast(callback){
     console.log('吃早饭');
     callback&&callback();
  }
  function lunch(){
     console.log('吃午饭');
  }
  console.log(breakfast(lunch))
}
{
  let breakfast = function(){
    console.log('吃早饭');
    return new Promise(function(resolve,reject){
      resolve();
    })
  } 
  let lunch = function(){
    console.log('吃午饭');
    return new Promise(function(resolve,reject){
     resolve();
    })
  }
  let dinner = function(){
    console.log('吃晚饭')
  }
 breakfast().then(lunch).then(dinner)
}

arguments 和相应参数的绑定

function foo(name, age, sex, hobbit) { console.log(name,
arguments[0]); // name name // 改变形参 name = ‘new name’;
console.log(name, arguments[0]); // new name new name // 改变arguments
arguments[1] = ‘new age’; console.log(age, arguments[1]); // new age
new age // 测试未传入的是否会绑定 console.log(sex); // undefined sex =
‘new sex’; console.log(sex, arguments[2]); // new sex undefined
arguments[3] = ‘new hobbit’; console.log(hobbit, arguments[3]); //
undefined new hobbit } foo(‘name’, ‘age’)

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 foo(name, age, sex, hobbit) {
 
    console.log(name, arguments[0]); // name name
 
    // 改变形参
    name = ‘new name’;
 
    console.log(name, arguments[0]); // new name new name
 
    // 改变arguments
    arguments[1] = ‘new age’;
 
    console.log(age, arguments[1]); // new age new age
 
    // 测试未传入的是否会绑定
    console.log(sex); // undefined
 
    sex = ‘new sex’;
 
    console.log(sex, arguments[2]); // new sex undefined
 
    arguments[3] = ‘new hobbit’;
 
    console.log(hobbit, arguments[3]); // undefined new hobbit
 
}
 
foo(‘name’, ‘age’)

传扬的参数,实参和 arguments 的值会共享,当没有传来时,实参预 arguments
值不会共享

除去,以上是在非严俊格局下,若是是在从严情势下,实参和 arguments
是不会共享的。

不定长的参数问题一举成功了,大家跟着要把这一个参数数组放到要履行的函数的参数里面去。
//
将数组里的因素作为多个参数放进函数的形参里context.fn(args.join(‘,’))//
(O_o)??// 这几个方法自然是万分的啦!!!

传递参数

将参数从一个函数传递到另一个函数

// 使用 apply 将 foo 的参数传递给 bar function foo() { bar.apply(this,
arguments); } function bar(a, b, c) { console.log(a, b, c); } foo(1, 2,
3)

1
2
3
4
5
6
7
8
9
// 使用 apply 将 foo 的参数传递给 bar
function foo() {
    bar.apply(this, arguments);
}
function bar(a, b, c) {
   console.log(a, b, c);
}
 
foo(1, 2, 3)

想必有人想到用 ES6 的法门,然则 call 是 ES3 的章程,我们为了仿效完毕一个
ES3 的措施,要用到ES6的措施,好像……,嗯,也足以啦。不过大家这一次用 eval
方法拼成一个函数,类似于如此:
eval(‘context.fn(‘ + args +’)’)

强大的ES6

选取ES6的 … 运算符,咱们可以轻松转成数组。

function func(…arguments) { console.log(arguments); // [1, 2, 3] }
func(1, 2, 3);

1
2
3
4
5
function func(…arguments) {
    console.log(arguments); // [1, 2, 3]
}
 
func(1, 2, 3);

此地 args 会自动调用 Array.toString() 那个点子。
之所以大家的第二版克制了多个大问题,代码如下:
// 第二版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

应用

arguments的施用其实过多,在下个连串,也就是 JavaScript
专题种类中,我们会在 jQuery 的 extend 完毕、函数柯里化、递归等境况看见
arguments 的身影。这篇作品就不现实举行了。

设若要计算这个情况的话,暂时能想到的席卷:

  1. 参数不定长
  2. 函数柯里化
  3. 递归调用
  4. 函数重载

欢迎留言回复。

(๑•̀ㅂ•́)و✧
依傍完结第三步
模仿代码已经已毕 80%,还有多个小点要留心:
1.this 参数可以传 null,当为 null 的时候,视为指向 window
举个例子:
var value = 1;function bar() { console.log(this.value);}bar.call(null);
// 1

深远连串

JavaScript深刻连串目录地址:。

JavaScript深切连串推断写十五篇左右,意在帮大家捋顺JavaScript底层知识,重点讲解如原型、功能域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难处概念。

假诺有错误或者不行事极为谨慎的地点,请务必给予指正,卓殊谢谢。要是喜欢照旧具有启发,欢迎star,对作者也是一种鞭策。

  1. JavaScirpt 深切之从原型到原型链
  2. JavaScript
    长远之词法成效域和动态功用域
  3. JavaScript 深远之实施上下文栈
  4. JavaScript 长远之变量对象
  5. JavaScript 深刻之效果域链
  6. JavaScript 深切之从 ECMAScript 规范解读
    this
  7. JavaScript 深入之实践上下文
  8. JavaScript 浓密之闭包
  9. JavaScript 深切之参数按值传递
  10. JavaScript
    深刻之call和apply的效仿完结
  11. JavaScript 深刻之bind的画虎类犬完成
  12. JavaScript 长远之new的效仿完毕

    1 赞 2 收藏
    评论

亚洲必赢官网 3

即使那一个例子本身不应用 call,结果如故依然一样。
2.函数是足以有重回值的!
举个例证:
var obj = { value: 1}function bar(name, age) { return { value:
this.value, name: name, age: age }}console.log(bar.call(obj, ‘kevin’,
18));// Object {// value: 1,// name: ‘kevin’,// age: 18// }

而是都很好解决,让大家直接看第三版也就是终极一版的代码:
// 第三版Function.prototype.call2 = function (context) { var context =
context || window; context.fn = this; var args = []; for(var i = 1,
len = arguments.length; i < len; i++) { args.push(‘arguments[‘ + i +
‘]’); } var result = eval(‘context.fn(‘ + args +’)’); delete context.fn
return result;}// 测试一下var value = 2;var obj = { value: 1}function
bar(name, age) { console.log(this.value); return { value: this.value,
name: name, age: age }}bar.call(null); // 2console.log(bar.call2(obj,
‘kevin’, 18));// 1// Object {// value: 1,// name: ‘kevin’,// age: 18// }

到此,我们做到了 call 的效仿完成,给协调一个赞 b( ̄▽ ̄)d
apply的模仿达成
apply 的贯彻跟 call 类似,在此处一向给代码,代码来自于腾讯网@郑航的已毕:
Function.prototype.apply = function (context, arr) { var context =
Object(context) || window; context.fn = this; var result; if (!arr) {
result = context.fn(); } else { var args = []; for (var i = 0, len =
arr.length; i < len; i++) { args.push(‘arr[‘ + i + ‘]’); } result =
eval(‘context.fn(‘ + args + ‘)’) } delete context.fn return result;}

长远体系
JavaScript深刻种类目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript长远连串估算写十五篇左右,意在帮我们捋顺JavaScript底层知识,重点讲解如原型、功效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。
假诺有错误或者不小心的地点,请务必给予指正,格外感谢。假设喜欢依旧有所启发,欢迎star,对作者也是一种鞭策。

网站地图xml地图