必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

ES6 为我们引入了 let 与 const,举个例子

2019-09-30 05:59 来源:未知

JavaScript 深远之参数按值传递

2017/05/23 · JavaScript · 参数

原稿出处: 冴羽   

ES6 变量证明与赋值:值传递、浅拷贝与深拷贝详解

2017/08/16 · JavaScript · es6

原稿出处: 王下邀月熊   

ES6 变量注解与赋值:值传递、浅拷贝与深拷贝详解回顾于笔者的今世JavaScript 开采:语法基础与施行才能排山倒海小说。本文首先介绍 ES6 中常用的二种变量评释格局,然后研究了 JavaScript 按值传递的风味,最终介绍了复合类型拷贝的技术;风乐趣的可以翻阅下一章节 ES6 变量功用域与升迁:变量的生命周期详解。

初稿出处: 王下邀月熊   

深切精晓JavaScript 参数按值传递,深切精通javascript

定义
ECMAScript中颇有函数的参数都以按值传递的。

怎么着是按值传递呢?

也正是说,把函数外界的值复制给函数内部的参数,就和把值从三个变量复制到另三个变量同样。

按值传递

举个大约的例证:

var value = 1;
function foo(v) {
  v = 2;
  console.log(v); //2
}
foo(value);
console.log(value) // 1

很好精晓,当传递 value 到函数 foo 中,相当于拷贝了一份 value,假诺拷贝的那份叫 _value,函数中期维修改的都是 _value 的值,而不会影响原来的 value 值。

引用传递

拷贝就算很好明白,可是当班值日是贰个犬牙相制的数据结构的时候,拷贝就能够生出品质上的主题素材。

之所以还恐怕有另一种传递格局叫做按援引传递。

所谓按援用传递,正是传递对象的援用,函数内部对参数的别样改变都会默化潜移该指标的值,因为两岸引用的是同贰个对象。

举个例子:

var obj = {
  value: 1
};
function foo(o) {
  o.value = 2;
  console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2

哟,不对啊,连大家的红宝书都说了 ECMAScript 中存有函数的参数都以按值传递的,这怎么能按引用传递成功吗?

而这到底是还是不是引用传递呢?

其两种传递方式

不急,让大家再看个例证:

var obj = {
  value: 1
};
function foo(o) {
  o = 2;
  console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1

一旦 JavaScript 选取的是引用传递,外层的值也会被涂改呐,那怎么又没被改吗?所以的确不是引用传递吗?

那就要讲到其实还或然有第三种传递格局,叫按分享传递。

而分享传递是指,在传递对象的时候,传递对象的援用的别本。

注意: 按援用传递是传递对象的引用,而按分享传递是传递对象的援引的别本!

之所以修改 o.value,能够通过援用找到原值,可是一贯改动o,并不会修改原值。所以第2个和第七个例子其实都以按分享传递。

谈起底,你可以这么通晓:

参数如若是主导项目是按值传递,借使是援用类型按分享传递。

唯独因为拷贝别本也是一种值的正片,所以在海拔中也间接认为是按值传递了。

故此,高程,何人叫您是红宝书嘞!

深切类别

JavaScript深入种类目录地址: 。

JavaScript深切体系猜测写十五篇左右,目的在于帮大家捋顺JavaScript底层知识,器重教学如原型、成效域、奉行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承袭等困难概念。

以上正是本文的全体内容,希望对大家的学习抱有助于,也期待我们多多关照帮客之家。

参数按值传递,深远驾驭javascript 定义 ECMAScript中具有函数的参数都以按值传递的。 什么是按值传递呢? 也正是说,把函...

JavaScript 深切之call和apply的上行下效达成

2017/05/25 · JavaScript · apply, call

原著出处: 冴羽   

定义

在《JavaScript高等程序设计》第三版 4.1.3,讲到传递参数:

ECMAScript中存有函数的参数都以按值传递的。

怎么是按值传递呢?

也正是说,把函数外界的值复制给函数内部的参数,就和把值从一个变量复制到另贰个变量一样。

变量证明与赋值

ES6 为我们引进了 let 与 const 三种新的变量注明关键字,同一时间也引进了块成效域;本文首先介绍 ES6 中常用的三种变量申明格局,然后切磋了 JavaScript 按值传递的天性以及两种的赋值格局,最后介绍了复合类型拷贝的技术。

ES6 变量表明与赋值:值传递、浅拷贝与深拷贝详解归纳于小编的今世JavaScript 开采:语法基础与试行技术洋洋洒洒文章。本文首先介绍 ES6 中常用的二种变量注脚格局,然后商讨了 JavaScript 按值传递的特色,最后介绍了复合类型拷贝的本领;风野趣的可以翻阅下一章节 ES6 变量功能域与升高:变量的生命周期详解。

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 函数实践了

按值传递

举个简易的例证:

var value = 1; function foo(v) { v = 2; console.log(v); //2 } foo(value); console.log(value) // 1

1
2
3
4
5
6
7
var value = 1;
function foo(v) {
    v = 2;
    console.log(v); //2
}
foo(value);
console.log(value) // 1

很好理解,当传递 value 到函数 foo 中,也就是拷贝了一份 value,假使拷贝的那份叫 _value,函数中修改的都是 _value 的值,而不会影响原来的 value 值。

变量评释

在 JavaScript 中,基本的变量评释能够用 var 格局;JavaScript 允许省略 var,直接对未证明的变量赋值。也便是说,var a = 1 与 a = 1,这两条语句的职能同样。可是由于那样的做法很轻松毫不知觉地创建全局变量(特别是在函数内部),所以建议总是采用var 命令注解变量。在 ES6 中,对于变量证明的法子张开了扩展,引进了 let 与 const。var 与 let 多少个首要字创制变量的分别在于, var 注脚的变量效能域是近年来的函数块;而 let 评释的变量作用域是近来的闭合块,往往会低于函数块。另一方面,以 let 关键字创立的变量即使同样被提高到功效域尾部,可是并无法在实质上申明前应用;即使强行使用则会抛出 ReferenceError 非凡。

变量注明与赋值

ES6 为我们引入了 let 与 const 二种新的变量评释关键字,同偶然候也引进了块成效域;本文首先介绍 ES6 中常用的两种变量注解形式,然后切磋了 JavaScript 按值传递的风味以及各类的赋值方式,最终介绍了复合类型拷贝的本事。

依傍达成率先步

这便是说我们该怎么模拟达成那多个职能呢?

试想当调用 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 obj = { value: 1 }; function foo(o) { o.value = 2; console.log(o.value); //2 } foo(obj); console.log(obj.value) // 2

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

哎呀,不对啊,连大家的红宝书都说了 ECMAScript 中有所函数的参数都是按值传递的,那怎么能按援引传递成功吗?

而那毕竟是否引用传递呢?

var

var 是 JavaScript 中基础的变量注明方式之一,其基本语法为:

var x; // Declaration and initialization x = "Hello World"; // Assignment // Or all in one var y = "Hello World";

1
2
3
4
5
var x; // Declaration and initialization
x = "Hello World"; // Assignment
 
// Or all in one
var y = "Hello World";

ECMAScript 6 在此以前我们在 JavaScript 中并未任何的变量注明格局,以 var 证明的变量功效于函数效能域中,若无对号入座的闭合函数效率域,那么该变量会被充作私下认可的全局变量实行拍卖。

function sayHello(){ var hello = "Hello World"; return hello; } console.log(hello);

1
2
3
4
5
function sayHello(){
var hello = "Hello World";
return hello;
}
console.log(hello);

像如上这种调用格局会抛出十分: ReferenceError: hello is not defined,因为 hello 变量只可以成效于 sayHello 函数中,可是若是根据如下先证明全局变量格局再利用时,其就可以平常调用:

var hello = "Hello World"; function sayHello(){ return hello; } console.log(hello);

1
2
3
4
5
var hello = "Hello World";
function sayHello(){
return hello;
}
console.log(hello);

变量申明

在 JavaScript 中,基本的变量申明可以用 var 格局;JavaScript 允许省略 var,直接对未评释的变量赋值。也等于说,var a = 1 与 a = 1,这两条语句的机能等同。可是出于那样的做法很轻便无声无息地开创全局变量(尤其是在函数内部),所以提出总是选拔var 命令注解变量。在 ES6 中,对于变量注脚的艺术举办了扩大,引进了 let 与 const。var 与 let 四个首要字创制变量的差别在于, var 注脚的变量效率域是前段时间的函数块;而 let 表明的变量功能域是这段时间的闭合块,往往会小于函数块。另一方面,以 let 关键字成立的变量即便同样被进级到效果域底部,然则并不能够在实质上证明前使用;如若强行使用则会抛出 ReferenceError 格外。

依傍完成第二步

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

譬喻那样:

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

(๑•̀ㅂ•́)و✧

其三种传递格局

不急,让我们再看个例子:

var obj = { value: 1 }; function foo(o) { o = 2; console.log(o); //2 } foo(obj); console.log(obj.value) // 1

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

即便 JavaScript 接纳的是援用传递,外层的值也会被涂改呐,那怎么又没被改吧?所以的确不是援引传递吗?

那就要讲到其实还有第两种传递情势,叫按分享传递。

而分享传递是指,在传递对象的时候,传递对象的引用的别本。

只顾: 按援引传递是传递对象的援用,而按分享传递是传递对象的引用的别本!

据此修改 o.value,能够通过援引找到原值,不过一贯改动o,并不会修改原值。所以第1个和第多少个例子其实都以按分享传递。

末段,你能够这么精晓:

参数假若是主导项目是按值传递,借使是援用类型按分享传递。

而是因为拷贝别本也是一种值的正片,所以在海拔中也直接感到是按值传递了。

由此,高程,谁叫您是红宝书嘞!

let

在 ECMAScript 6 中大家能够使用 let 关键字打开变量评释:

let x; // Declaration and initialization x = "Hello World"; // Assignment // Or all in one let y = "Hello World";

1
2
3
4
5
let x; // Declaration and initialization
x = "Hello World"; // Assignment
 
// Or all in one
let y = "Hello World";

let 关键字表明的变量是属于块作用域,也正是含有在 {} 之内的机能于。使用 let 关键字的优势在于可以裁减有的时候的失实的可能率,因为其保障了每种变量只可以在细微的作用域内开展访谈。

var name = "Peter"; if(name === "Peter"){ let hello = "Hello Peter"; } else { let hello = "Hi"; } console.log(hello);

1
2
3
4
5
6
7
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
} else {
let hello = "Hi";
}
console.log(hello);

上述代码一样会抛出 ReferenceError: hello is not defined 格外,因为 hello 只好够在闭合的块功效域中实行访谈,大家能够进行如下修改:

var name = "Peter"; if(name === "Peter"){ let hello = "Hello Peter"; console.log(hello); } else { let hello = "Hi"; console.log(hello); }

1
2
3
4
5
6
7
8
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
  console.log(hello);
} else {
let hello = "Hi";
  console.log(hello);
}

笔者们能够动用这种块级成效域的特点来幸免闭包中因为变量保留而产生的主题材料,举个例子如下三种异步代码,使用 var 时老是循环中应用的没有不相同变量;而采纳 let 评释的 i 则会在每回循环时进行不相同的绑定,即每一遍循环中闭包捕获的都以见仁见智的 i 实例:

for(let i = 0;i < 2; i++){ setTimeout(()=>{console.log(`i:${i}`)},0); } for(var j = 0;j < 2; j++){ setTimeout(()=>{console.log(`j:${j}`)},0); } let k = 0; for(k = 0;k < 2; k++){ setTimeout(()=>{console.log(`k:${k}`)},0); } // output i:0 i:1 j:2 j:2 k:2 k:2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for(let i = 0;i < 2; i++){
        setTimeout(()=>{console.log(`i:${i}`)},0);
}
 
for(var j = 0;j < 2; j++){
        setTimeout(()=>{console.log(`j:${j}`)},0);
}
 
let k = 0;
for(k = 0;k < 2; k++){
        setTimeout(()=>{console.log(`k:${k}`)},0);
}
 
// output
i:0
i:1
j:2
j:2
k:2
k:2

var

var 是 JavaScript 中基础的变量声明格局之一,其基本语法为:

var x; // Declaration and initialization x = "Hello World"; // Assignment // Or all in one var y = "Hello World";

1
2
3
4
5
var x; // Declaration and initialization
x = "Hello World"; // Assignment
 
// Or all in one
var y = "Hello World";

ECMAScript 6 从前笔者们在 JavaScript 中并从未任何的变量注解格局,以 var 申明的变量作用于函数功能域中,若无对应的闭合函数功效域,那么该变量会被当作暗中同意的全局变量进行管理。

function sayHello(){ var hello = "Hello World"; return hello; } console.log(hello);

1
2
3
4
5
function sayHello(){
var hello = "Hello World";
return hello;
}
console.log(hello);

像如上这种调用形式会抛出特别: ReferenceError: hello is not defined,因为 hello 变量只可以作用于 sayHello 函数中,可是只要依照如下先注明全局变量方式再使用时,其就能够健康调用:

var hello = "Hello World"; function sayHello(){ return hello; } console.log(hello);

1
2
3
4
5
var hello = "Hello World";
function sayHello(){
return hello;
}
console.log(hello);

宪章完成第三步

模仿代码已经完结 百分之九十,还大概有多个小点要留意:

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

深远类别

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 深刻之闭包

    1 赞 收藏 评论

图片 1

const

const 关键字日常用来常量表明,用 const 关键字注解的常量须求在宣称时开展初步化并且不得以再开展退换,何况 const 关键字阐明的常量被界定于块级功效域中举办寻访。

function f() { { let x; { // okay, block scoped name const x = "sneaky"; // error, const x = "foo"; } // error, already declared in block let x = "inner"; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
function f() {
  {
let x;
    {
      // okay, block scoped name
const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
let x = "inner";
  }
}

JavaScript 中 const 关键字的突显于 C 中设有着一定出入,譬喻下述使用情势在 JavaScript 中正是不利的,而在 C 中则抛出非常:

# JavaScript const numbers = [1, 2, 3, 4, 6] numbers[4] = 5 console.log(numbers[4]) // print 5 # C const int numbers[] = {1, 2, 3, 4, 6}; numbers[4] = 5; // error: read-only variable is not assignable printf("%dn", numbers[4]);

1
2
3
4
5
6
7
8
9
# JavaScript
const numbers = [1, 2, 3, 4, 6]
numbers[4] = 5
console.log(numbers[4]) // print 5
 
# C
const int numbers[] = {1, 2, 3, 4, 6};
numbers[4] = 5; // error: read-only variable is not assignable
printf("%dn", numbers[4]);

从上述相比大家也能够阅览,JavaScript 中 const 限制的永不值不可变性;而是创立了不可变的绑定,即对于某些值的只读引用,何况制止了对于该引用的重赋值,即如下的代码会触发错误:

const numbers = [1, 2, 3, 4, 6] numbers = [7, 8, 9, 10, 11] // error: assignment to constant variable console.log(numbers[4])

1
2
3
const numbers = [1, 2, 3, 4, 6]
numbers = [7, 8, 9, 10, 11] // error: assignment to constant variable
console.log(numbers[4])

咱俩得以参考如下图片精通这种体制,种种变量标志符都会涉及某些寄存变量实际值的物理地址;所谓只读的变量便是该变量标记符无法被另行赋值,而该变量指向的值仍旧可变的。

JavaScript 中存在着所谓的原始类型与复合类型,使用 const 申明的原始类型是值不可变的:

# Example 1 const a = 10 a = a + 1 // error: assignment to constant variable # Example 2 const isTrue = true isTrue = false // error: assignment to constant variable # Example 3 const sLower = 'hello world' const sUpper = sLower.toUpperCase() // create a new string console.log(sLower) // print hello world console.log(sUpper) // print HELLO WORLD

1
2
3
4
5
6
7
8
9
10
11
# Example 1
const a = 10
a = a + 1 // error: assignment to constant variable
# Example 2
const isTrue = true
isTrue = false // error: assignment to constant variable
# Example 3
const sLower = 'hello world'
const sUpper = sLower.toUpperCase() // create a new string
console.log(sLower) // print hello world
console.log(sUpper) // print HELLO WORLD

而假设我们希望将有个别对象同样成为不可变类型,则须求利用 Object.freeze();可是该措施仅对于键值对的 Object 起成效,而无法功能于 Date、Map 与 Set 等门类:

# Example 4 const me = Object.freeze({name: “Jacopo”}) me.age = 28 console.log(me.age) // print undefined # Example 5 const arr = Object.freeze([-1, 1, 2, 3]) arr[0] = 0 console.log(arr[0]) // print -1 # Example 6 const me = Object.freeze({ name: 'Jacopo', pet: { type: 'dog', name: 'Spock' } }) me.pet.name = 'Rocky' me.pet.breed = 'German Shepherd' console.log(me.pet.name) // print Rocky console.log(me.pet.breed) // print German Shepherd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Example 4
const me = Object.freeze({name: “Jacopo”})
me.age = 28
console.log(me.age) // print undefined
# Example 5
const arr = Object.freeze([-1, 1, 2, 3])
arr[0] = 0
console.log(arr[0]) // print -1
# Example 6
const me = Object.freeze({
  name: 'Jacopo',
pet: {
    type: 'dog',
    name: 'Spock'
  }
})
me.pet.name = 'Rocky'
me.pet.breed = 'German Shepherd'
console.log(me.pet.name) // print Rocky
console.log(me.pet.breed) // print German Shepherd

即就是 Object.freeze() 也不得不幸免顶层属性被涂改,而不能够界定对于嵌套属性的改变,这点大家会在下文的浅拷贝与深拷贝部分继续探究。

let

在 ECMAScript 6 中我们能够动用 let 关键字展开变量注明:

let x; // Declaration and initialization x = "Hello World"; // Assignment // Or all in one let y = "Hello World";

1
2
3
4
5
let x; // Declaration and initialization
x = "Hello World"; // Assignment
 
// Or all in one
let y = "Hello World";

let 关键字注明的变量是属于块成效域,相当于包括在 {} 之内的功能于。使用 let 关键字的优势在于能够减少临时的失实的票房价值,因为其担保了每一个变量只可以在小小的效用域内实行访谈。

var name = "Peter"; if(name === "Peter"){ let hello = "Hello Peter"; } else { let hello = "Hi"; } console.log(hello);

1
2
3
4
5
6
7
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
} else {
let hello = "Hi";
}
console.log(hello);

上述代码一样会抛出 ReferenceError: hello is not defined 卓殊,因为 hello 只好够在密封的块成效域中进行访谈,大家可以张开如下修改:

var name = "Peter"; if(name === "Peter"){ let hello = "Hello Peter"; console.log(hello); } else { let hello = "Hi"; console.log(hello); }

1
2
3
4
5
6
7
8
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
  console.log(hello);
} else {
let hello = "Hi";
  console.log(hello);
}

咱们可以运用这种块级功用域的性子来避免闭包中因为变量保留而致使的难题,比如如下三种异步代码,使用 var 时老是循环中选用的都是一律变量;而使用 let 注明的 i 则会在历次循环时张开差异的绑定,即每回循环中闭包捕获的都是不相同的 i 实例:

for(let i = 0;i < 2; i++){ setTimeout(()=>{console.log(`i:${i}`)},0); } for(var j = 0;j < 2; j++){ setTimeout(()=>{console.log(`j:${j}`)},0); } let k = 0; for(k = 0;k < 2; k++){ setTimeout(()=>{console.log(`k:${k}`)},0); } // output i:0 i:1 j:2 j:2 k:2 k:2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for(let i = 0;i < 2; i++){
        setTimeout(()=>{console.log(`i:${i}`)},0);
}
 
for(var j = 0;j < 2; j++){
        setTimeout(()=>{console.log(`j:${j}`)},0);
}
 
let k = 0;
for(k = 0;k < 2; k++){
        setTimeout(()=>{console.log(`k:${k}`)},0);
}
 
// output
i:0
i:1
j:2
j:2
k:2
k:2

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;
}
TAG标签:
版权声明:本文由必威发布于必威-前端,转载请注明出处:ES6 为我们引入了 let 与 const,举个例子