闰土说JS进阶之变量

前言

前端世界如此喧嚣,能进阶的何其稀少。大家好,你们的闰土哥在沉寂了数月之后又回来了!(此处应有掌声~~~)

前段时间在群里关于“闰土去哪儿了”的话题,让我既欣喜又尴尬。欣喜的是大家还记得我,尴尬的是我竟不知道该如何回复。原因有二,一是我换了家公司继续撸代码,二是那段时间我沉淀了一下自己的技术和生活。闰土这次回来是带着满满的干货想与大家分享,如果你在这里能学到一点点知识,收获一丝丝感悟,那闰土便知足了。(YY:按照惯例,此刻该听到搬小板凳的声音了,嘻嘻~)

正文

开门见山,这次闰土要讲讲JavaScript进阶。废话不多说,先拿变量开刀。

在我们前端日常的JavaScript编码中,总避免不了声明变量。那变量是什么呢?我们前端人员都知道,变量其实就是一个容器,用来存放各种不同的数据类型的值,包括基本类型值和引用类型值。基本类型值有五种,参加过前端面试的人想必都能倒背如流,分别是Undefined、Null、Boolean、Number和String。

定义基本类型值和引用类型值的方式是类似的,就是创建一个变量并为该变量赋值。先来看看下面的栗子:

var person = new Object();

person.name = 'runtu';
console.log(person.name);   // "runtu"

在上面的例子中我们创建了一个对象并将其保存在了变量 person 中。然后,我们为该对象添加了一个名为 name 的属性,并将字符串值“runtu”赋给了这个属性。紧接着,又通过console.log()函数访问了这个新属性。如果person这个对象不被销毁或者这个属性不被删除,那么这个属性将一直存在。

也就是说,对于引用类型的值,我们可以为其添加/修改/删除属性和方法,但是我们不能给基本类型的值添加属性,尽管这样做不会导致任何错误(我们建议不这么写,因为写了也没用 Orz)。

接下来我们再聊聊复制变量值。

先来看看下面的栗子:

var age1 = 26;

var age2 = age1;

在以上代码中,age1中保存的值是26,是基本类型值。当使用age1的值来初始化age2时,age2中也保存了值26,但该值只是age1的一个副本,所以,这两个变量可以参与此后任何操作而不会相互影响。

看完了复制基本类型值,我们再来看下一个栗子:

var person1 = new Object();

var person2 = person1;
person1.name = 'runtu';
console.log(person2.name);  // "runtu"

在这里,变量person1保存了一个对象的新实例。然后这个值被复制到了person2;换句话说,person1和person2都指向同一个对象。这样一来,当为person1添加name属性后,person2也可以访问到这个属性。

到这里,我们就可以适当的总结一下,当一个变量复制另一个变量的引用类型值时,这个值的副本其实是一个指针,而这个指针则指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响到另一个变量。

接下来我们讲讲传递参数,重点来了,该划重点的划下,这是必考题

函数传参,相信很多前端老司机都已经耳熟能详了,可能更多的前端新人小白们还是懵懵懂懂的,这里我说下。在ECMAScript中所有函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样,原理是一样的。

接下来这句话可能有点绕,基本类型值的传递和基本类型变量的复制一样,同样的,引用类型值的传递和引用类型变量的复制是一样的。有不少工作了两三年的前端er在这个点上可能也会感到困惑。为什么呢?这个知识点可能比较晦涩难懂,因为像咱们平时访问变量有按值和按引用这两种方式,而参数只能按值传递。照样举个栗子:

function addSix(num){
    num += 6;

    return num;

}

var count = 20;

var result = addSix(count);

console.log(count);  // 20,没有变化
console.log(result);  // 26(有没有感觉这个数字出现频率较高,嘻嘻~)

这里的函数addSix()有一个参数num,而参数实际上是函数的局部变量。在调用这个函数时,变量count作为参数被传递给函数,于是数值20被复制给参数num。在函数内部,参数num的值被加上了6,但是这一变化不会影响外部的count变量,参数num和变量count素昧平生互不相识。假如num是按引用传递的话,那么变量count的值也将变成30,从而反映函数内部的修改。

当然使用数值等基本类型值来说明按值传递参数比较简单,但如果使用对象,那么问题就不那么浅显易懂了。闰土再举一个栗子:

function setName(obj){
    obj.name = 'runtu';

    obj = new Object();

    obj.name = 'shaonian';

}

var person = new Object();

setName(person);
console.log(person.name);  // runtu

有小白会问:console出来的怎么不是 “shaonian” 呢?

这是一个很经典的问题,你想如果person是按引用传递的,那么person就会被自动修改为指向其name属性值为“shaonian”的新对象。但是,重点来了。当接下来再访问person.name时,显示的值仍然是“runtu”。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

所以,结论就是,所有的函数传参都是按值传递的。(又该划重点了,咳~咳~)

备注:本文参考红宝书,如有雷同,纯属拷贝。

原文发布于微信公众号 - 闰土大叔(running_hacker)

原文发表时间:2017-10-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

怎样写解释器

解释器是比较深入的内容。虽然我试图从最基本的原理讲起,尽量让这篇文章不依赖于其它的知识,但是这篇教程并不是针对函数式编程的入门,所以我假设你已经学会了最基本的 ...

2217
来自专栏CDA数据分析师

Python程序员鲜为人知但你应该知道的16个问题

这篇文章主要介绍了Python程序员代码编写时应该避免的16个“坑”,也可以说成Python程序员代码编写时应该避免的16个问题,需要的朋友可以参考。 1. ...

2047
来自专栏java学习

Java每日一练(2017/7/21)

聊天系统 ●我希望大家积极参与答题!有什么不懂可以加小编微信进行讨论 ★珍惜每一天,拼搏每一天,专心每一天,成功每一 如果你是初学者,或者是自学者!你可以加小编...

3434
来自专栏Crossin的编程教室

【Python 第17课】 类型转换

昨天又被微信后台给坑了,导致有些同学收了2遍消息。希望今天能顺利发成功。。。 #==== 类型转换 ====# python的几种最基本的数据类型,我们已经...

2876
来自专栏C/C++基础

C++11新特性——大括号初始化

虽然C++03提供了多样的对象初始化方式, 但不能提供自定义类型对象的大括号初始化方式,也不能在使用new[]的时候初始化POD 数组。幸好,C++11扩充了大...

692
来自专栏我是攻城师

你不知道的Java的split的小问题

2826
来自专栏Java学习网

Java 8的函数式编程学习

Java 8的函数式编程学习 函数式编程语言是什么? 函数式编程语言的核心是它以处理数据的方式处理代码。这意味着函数应该是第一等级(First-class)的...

2667
来自专栏前端下午茶

JS 原型模式

原型模式(Prototype pattern),用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法。

3661
来自专栏用户2442861的专栏

sizeof小览

http://blog.csdn.net/scythe666/article/details/47012347

841
来自专栏大数据和云计算技术

#算法基础#选择和插入排序

算法是基础,小蓝同学准备些总结一系列算法分享给大家,这是第二篇《选择和插入排序》,非常赞!希望对大家有帮助,大家会喜欢! 系列文章: 由快速排序到分治思想 ...

3426

扫码关注云+社区

领取腾讯云代金券