xml地图|网站地图|网站标签 [设为首页] [加入收藏]
变量声明与赋值,框架报告
分类:web前端

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

2017/08/16 · JavaScript · es6

原文出处: 王下邀月熊   

ES6 变量声明与赋值:值传递、浅拷贝与深拷贝详解归纳于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章。本文首先介绍 ES6 中常用的三种变量声明方式,然后讨论了 JavaScript 按值传递的特性,最后介绍了复合类型拷贝的技巧;有兴趣的可以阅读下一章节 ES6 变量作用域与提升:变量的生命周期详解。

npm 发布 2017 JavaScript 框架报告:React 占主导地位

2018/01/11 · JavaScript · 框架

原文出处: 开源中国/局长   

图片 1

图片 2

npm 的联合创始人兼首席运营官 Laurie Voss 近日发布了 2018 年的第一个 JavaScript 现状报告,这一系列报告包含三部分,将会提供 JavaScript 发展趋势和实践的完整回顾。第一部分讲述了 2017 前端框架的现状,第二部分将讲述 React 的生态系统,第三部分将对后端框架进行讲述。目前,第二和第三部分尚未发布。

Laurie Voss 说,JavaScript 社区在编程语言史上以前所未有的速度增长着,npm 中的包也随之增长。npm 作为开发者分发和发现 JavaScript 代码的中心枢纽,我们可以看到应用程序开发者编写代码以及他们使用工具的趋势。

一起看看 2017 JavaScript 前端框架的回顾吧。

主要的前端框架

图片 3

报告显示,相对于所有 npm 中的包下载量,React 的使用量增长了 500%。移动、桌面应用程序和 Web 开发都在使用 React。对 React 而言,作为它的性能改进直接替代品,Preact 也有 145% 的增长。

图片 4

Preact 作为独立开发的 React 的替代品,赢得了很多开发者的关注,但总体使用率还是比较低。然而,它的增长率是令人印象深刻的,所以有可能在未来几年成为一支主力军。

图片 5

此外,npm 还发现 Ember 已经卷土重来。这个框架曾被许多大公司所使用,例如微软、Netflix 和 Salesforce。在 2016 年人气下降之后,去年下载量增长了 45%。

图片 6

虽然 Angular 持续受欢迎,但整体来看没有明显的增长,而且预计未来的增长也不大。根据 npm 的说法,Angular 的下载量占 npm 包下载量的 0.008% 左右,但依赖 Google 的巨大资源和持续支持意味着它可以坚持下去。

图片 7

尽管 Vue 与 Ember 和 Angular 的受欢迎程度相同,但该报告预测,与其他工具相比,它的增长速度要快得多,预计在 2018 年它将超过其他两个的受欢迎程度。

图片 8

对于老牌框架 Backbone,在 5 年前占主导地位的它自此以来,就一直在急剧下降,但由于现有项目的长期“保质期”,开发者还未能完全抛弃它,基本上仍有每月 75 万次的下载量。

图片 9

2017 前端框架的增长情况

图片 10

该图显示了 2016 年 10 月至 2017 年 10 月这 12 个月期间框架的受欢迎程度及其增长情况。总体情况很明显:

  • Preact 受众最小,但增长最快
  • Vue 的增长速度也非常快,受欢迎程度与 Ember,Angular 和 Backbone 旗鼓相当
  • Ember 在过去的 12 个月里越来越受欢迎
  • Angular 和 Backbone 的增长度都下降了
  • jQuery 仍然非常受欢迎,但增长越来越少
  • React 不仅十分受欢迎,而且还增长迅速

npm 表示,他们不建议每个人都应该使用最流行的框架,毕竟有很多指标可帮助您决定该使用哪个框架,而且不同框架在范围和应用上也有很大的不同。与您的应用程序紧密匹配的框架在这份报告中甚至可能都不会被提及,但它仍然是您最完美的框架。

最后,报告显示 Webpack 现在是构建 Web 应用程序的主要方式。npm 计划在本月晚些时候发布来自 React 生态系统的更多发现,以及对后端框架的分析。请保持关注。

1 赞 1 收藏 评论

图片 11

学习BFC

2015/08/21 · CSS · BFC

原文出处: elcarim的博客   

BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。要明白BFC到底是什么,首先来看看什么是视觉格式化模型。

变量声明与赋值

ES6 为我们引入了 let 与 const 两种新的变量声明关键字,同时也引入了块作用域;本文首先介绍 ES6 中常用的三种变量声明方式,然后讨论了 JavaScript 按值传递的特性以及多种的赋值方式,最后介绍了复合类型拷贝的技巧。

视觉格式化模型

视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制,它也是CSS中的一个概念。

视觉格式化模型定义了盒(Box)的生成,盒主要包括了块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)以及一些实验性的盒(未来可能添加到规范中)。盒的类型由display属性决定。

变量声明

在 JavaScript 中,基本的变量声明可以用 var 方式;JavaScript 允许省略 var,直接对未声明的变量赋值。也就是说,var a = 1 与 a = 1,这两条语句的效果相同。但是由于这样的做法很容易不知不觉地创建全局变量(尤其是在函数内部),所以建议总是使用 var 命令声明变量。在 ES6 中,对于变量声明的方式进行了扩展,引入了 let 与 const。var 与 let 两个关键字创建变量的区别在于, var 声明的变量作用域是最近的函数块;而 let 声明的变量作用域是最近的闭合块,往往会小于函数块。另一方面,以 let 关键字创建的变量虽然同样被提升到作用域头部,但是并不能在实际声明前使用;如果强行使用则会抛出 ReferenceError 异常。

块盒(block box)

块盒有以下特性:

  • 当元素的CSS属性displayblocklist-item或 table时,它是块级元素 block-level;
  • 视觉上呈现为块,竖直排列;
  • 块级盒参与(块格式化上下文);
  • 每个块级元素至少生成一个块级盒,称为主要块级盒(principal block-level box)。一些元素,比如<li>,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。

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

行内盒(inline box)

  • 当元素的CSS属性display的计算值为inlineinline-blockinline-table时,称它为行内级元素;
  • 视觉上它将内容与其它行内级元素排列为多行;典型的如段落内容,有文本(可以有多种格式譬如着重),或图片,都是行内级元素;
  • 行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文(inline formatting context)。同时参与生成行内格式化上下文的行内级盒称为行内盒(inline boxes)。所有display:inline的非替换元素生成的盒是行内盒;
  • 不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。这些盒由可替换行内元素,或 display 值为 inline-block 或inline-table 的元素生成,不能拆分成多个盒;

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

匿名盒(anonymous box)

匿名盒也有份匿名块盒与匿名行内盒,因为匿名盒没有名字,不能利用选择器来选择它们,所以它们的所有属性都为inherit或初始默认值;

如下面例子,会创键匿名块盒来包含毗邻的行内级盒:

XHTML

<div> Some inline text <p>followed by a paragraph</p> followed by more inline text. </div>

1
2
3
4
5
<div>
    Some inline text
    <p>followed by a paragraph</p>
    followed by more inline text.
</div>

图片 12

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() 也只能防止顶层属性被修改,而无法限制对于嵌套属性的修改,这一点我们会在下文的浅拷贝与深拷贝部分继续讨论。

三个定位方案

在定位的时候,浏览器就会根据元素的盒类型和上下文对这些元素进行定位,可以说盒就是定位的基本单位。定位时,有三种定位方案,分别是常规流,浮动已经绝对定位。

变量赋值

常规流(Normal flow)

  • 在常规流中,盒一个接着一个排列;
  • 块级格式化上下文里面, 它们竖着排列;
  • 行内格式化上下文里面, 它们横着排列;
  • positionstaticrelative,并且floatnone时会触发常规流;
  • 对于静态定位(static positioning),position: static盒的位置是常规流布局里的位置
  • 对于相对定位(relative positioning),position: relative,盒偏移位置由这些属性定义topbottomleftandright即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。

按值传递

JavaScript 中永远是按值传递(pass-by-value),只不过当我们传递的是某个对象的引用时,这里的值指的是对象的引用。按值传递中函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。而按引用传递(pass-by-reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。我们首先看下 C 中按值传递与引用传递的区别:

void Modify(int p, int * q) { p = 27; // 按值传递 - p是实参a的副本, 只有p被修改 *q = 27; // q是b的引用,q和b都被修改 } int main() { int a = 1; int b = 1; Modify(a, &b); // a 按值传递, b 按引用传递, // a 未变化, b 改变了 return(0); }

1
2
3
4
5
6
7
8
9
10
11
12
13
void Modify(int p, int * q)
{
    p = 27; // 按值传递 - p是实参a的副本, 只有p被修改
    *q = 27; // q是b的引用,q和b都被修改
}
int main()
{
int a = 1;
int b = 1;
    Modify(a, &b);   // a 按值传递, b 按引用传递,
                     // a 未变化, b 改变了
return(0);
}

而在 JavaScript 中,对比例子如下:

function changeStuff(a, b, c) { a = a * 10; b.item = "changed"; c = {item: "changed"}; } var num = 10; var obj1 = {item: "unchanged"}; var obj2 = {item: "unchanged"}; changeStuff(num, obj1, obj2); console.log(num); console.log(obj1.item); console.log(obj2.item); // 输出结果 10 changed unchanged

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}
 
var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
 
changeStuff(num, obj1, obj2);
 
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);
 
// 输出结果
10
changed
unchanged

JavaScript 按值传递就表现于在内部修改了 c 的值但是并不会影响到外部的 obj2 变量。如果我们更深入地来理解这个问题,JavaScript 对于对象的传递则是按共享传递的(pass-by-sharing,也叫按对象传递、按对象共享传递)。最早由Barbara Liskov. 在1974年的GLU语言中提出;该求值策略被用于Python、Java、Ruby、JS等多种语言。该策略的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。按共享传递的直接表现就是上述代码中的 obj1,当我们在函数内修改了 b 指向的对象的属性值时,我们使用 obj1 来访问相同的变量时同样会得到变化后的值。

浮动(Floats)

  • 盒称为浮动盒(floating boxes);
  • 它位于当前行的开头或末尾;
  • 导致常规流环绕在它的周边,除非设置 clear 属性;

连续赋值

JavaScript 中是支持变量的连续赋值,即譬如:

var a=b=1;

1
var a=b=1;

但是在连续赋值中,会发生引用保留,可以考虑如下情景:

var a = {n:1}; a.x = a = {n:2}; alert(a.x); // --> undefined

1
2
3
var a = {n:1};  
a.x = a = {n:2};  
alert(a.x); // --> undefined  

为了解释上述问题,我们引入一个新的变量:

var a = {n:1}; var b = a; // 持有a,以回查 a.x = a = {n:2}; alert(a.x);// --> undefined alert(b.x);// --> [object Object]

1
2
3
4
5
var a = {n:1};  
var b = a; // 持有a,以回查  
a.x = a = {n:2};  
alert(a.x);// --> undefined  
alert(b.x);// --> [object Object]  

实际上在连续赋值中,值是直接赋予给变量指向的内存地址:

a.x = a = {n:2} │ │ {n:1}<──┘ └─>{n:2}

1
2
3
a.x  =  a  = {n:2}
              │      │
      {n:1}<──┘      └─>{n:2}

绝对定位(Absolute positioning)

  • 绝对定位方案,盒从常规流中被移除,不影响常规流的布局;
  • 它的定位相对于它的包含块,相关CSS属性:topbottomleftright
  • 如果元素的属性positionabsolutefixed,它是绝对定位元素;
  • 对于position: absolute,元素定位将相对于最近的一个relativefixedabsolute的父元素,如果没有则相对于body

本文由澳门新葡亰手机版发布于web前端,转载请注明出处:变量声明与赋值,框架报告

上一篇:代码保护,不要再问我跨域的问题了 下一篇:从数组和对象中提取数据的优雅方法,的网站都
猜你喜欢
热门排行
精彩图文