javascript高级程序设计(4-5)章笔记

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/51234909

之前看过一遍js高程,有些基础还不牢固,单身狗周末又没地方去,开始重新撸一遍JS高程,写点笔记,防止以后忘了!

4.变量 作用域和内存问题

ECMAScript中所有函数的参数都是按值传递的(不区分基本类型和引用类型)

引用类型是按引用传递的,函数的参数全部按值传递,有点蒙逼,看代码

//基本类型值没问题
function add(num) {
    num += 10;
    return num;
}
var count =20 ;
console.log(add(count));//30

//看不出来
/*高程给的解释:在这个函数内部,obj和person引用的是同一个对象。
 *换句话说,即使这个对象是按值传递的,obj也会按引用来方位同一个对象*/
function setName (obj) {
    obj.name = 'kenny';
}
var person = new Object();
setName(person); // 'kenny'

//函数内部重新定义obj对象
function setName (obj) {
    obj.name = 'kenny';
    obj = new Object();
    obj.name = 'gaga';
}
var person = new Object();
setName(person); // 'kenny'

高程:函数内部重写obj时,这个变量引用的就是一个局部对象,而局部对象会在函数执行完毕后立即被销毁。个人理解就是函数作用域,外部环境无法访问内部的私有变量 ,包括arguments,其实相当于参数被重新定义成对象,但是外部的对象未变化,所以是按值传递,即对象的深度复制。

执行环境及作用域

1.每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中, 虽然无法访问此对象,但js解析器会在后台使用它,(chorme 控制台js断点的时候,当前作用定义的变量和函数都能在当前执行环境查看,soga)。

2.每个函数都有自己的执行环境 ,当执行流进入一个函数时,函数的环境就会给推入一个环境栈中(后进先出)。当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。每个环境多都可以向上搜索作用域链,以查询变量和函数名,(访问局部变量比访问全局变量要快,javascript引擎在优化标识符查村做的很ok,可以忽略不计)。

垃圾收集

标记清除(大部分浏览器以此来实现)和引用计数

管理内存

一旦数据不再引用,最好通过将其设置为null来释放引用——俗称解除引用。适用于大多数全局变量和全局对象的属性,局部变量会在他们离开执行环境时自动解除引用。

//执行完毕,person函数内的对象会自动销毁,
function person (name) {
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
}
var gloablPerson = person('kenny');
gloablPerson = null;

解除值的引用不会马上自动回收该值所占用的内存,是让值脱离执行环境,以便垃圾收集器下次运行将其回收。

小结

  • 基本类型值占据固定大小的空间,因此保存在栈中,引用类型的值是对象,保存在堆内存中。
  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量指向同一个对象。
  • 每次进入一个新的执行环境,都会创建一个用于搜索变量和函数的作用域链

5.引用类型

对象字面量 通过对象字面量定义对象时,实际上不会调用Object构造函数(Firefox2及更早版本会),即不会调用new实例化对象。【ES3之前的正则字面量存在bug,循环test某个字符串,一次为真一次为假,ES5已修正(P105页)】

安全的类型检测

var isArray = value instanceof Array;

以上代码要返回true就,value必须是数组,而且还必须与Array构造函数在同个全局作用域中,(切记,Array是window的属性),如果value在另个frame定义的数组,那么以上代码就会返回false。

在任何值上调用Object原声的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串,由于原生数组的构造函数与全局作用域无关,因此toString()就能保证返回一致的值。

function isArray(value) {
    return Object.prototype.toString.call(value) === '[object Array]';
}
function isFunction(value) {
    return Object.prototype.toString.call(value) === '[object Function]';
}
function isRegExp(value) {
    return Object.prototype.toString.call(value) === '[object RegExp]';
}

在Web开发中能够区分原生与非原生javascript对象非常重要,这样才能确切知道某个对象到底有哪些功能,但是Object.prototype.toString()本身也能被重写。

Function类型

每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

//函数是对象,函数名是指针
function sum(num1, num2) {
    return num1 + num2;
}
console.log(sum(10,10)); //20
var anotherSum = sum; //使用不带圆括号的函数名是访问函数指针,而非调用函数
console.log(anotherSum(10,10)); //20
sum = null; //设置其他值也一样
console.log(anotherSum(10, 10))//20

so要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号。

  • 函数声明与函数表达式

js解析器会率先读取函数声明(function declaration hosting),并使其在执行任何代码之前可用,至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。

  • 作为值的函数
        function createComparisonFunction(propertyName) {

            return function(object1, object2){
                var value1 = object1[propertyName];
                var value2 = object2[propertyName];

                if (value1 < value2){
                    return -1;
                } else if (value1 > value2){
                    return 1;
                } else {
                    return 0;
                }
            };
        }

        var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];

        data.sort(createComparisonFunction("name"));
        alert(data[0].name);  //Nicholas

        data.sort(createComparisonFunction("age"));
        alert(data[0].name);  //Zachary     
  • 函数内部属性

函数内部有两个特殊对象:arguments和this,arguments.callee指向拥有arguments对象的函数(ES6已弃用)。

this引用的是函数据以执行的环境对象,即函数调用,蝴蝶书上讲过有四种调用模式 1.方法调用模式,this指向当前方法的对象; 2.函数调用模式,this被绑定到全局对象,客户端即window; 3.构造器调用模式,this被绑定到实例化的新对象上; 4.apply/call调用模式,第一个参数都是要被绑定给this,第二个参数apply是数组,call([thisObj[,arg1[, arg2[, [,.argN]]]]])。

  • 函数属性和方法

每个函数都包含两个属性: length(函数希望接收的命名参数的个数) 和 prototype。

对于ECMAScript中的引用类型而言,prototype是保存她们所有实例方法的真正所在。在ES5中,prototype属性是不可枚举的,(非原生的prototype属性可枚举,即人为添加上去的,在google测试过)因此使用for-in无法发现。

ES5还定义了一个方法: bind()。这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

基本包装类型

var s1 = 'some text';
var s2 = s1.substring(2);

上述可以解析成三个步骤 1.创建String类型的一个实例; 2.在实例上调用指定的方法; 3.销毁这个实例 执行代码类似如下:

var s1 = new String('some text');
var s2 = s1.substring(2);
s1 = null;

引用类型与基本包装类型的主要区别就是对象的生存期。使用new操作符创建的引用类型实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型,则只存在于一行代码的执行瞬间,然后理解被销毁。

小结

在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和Math。在大多数ECMAScript视线中都不能直接访问Global对象;不过WEB浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。Math对象提供了很多属性和方法,用于辅助完成复杂的数学计算。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我的技术专栏

Java锁机制(一)synchronized

1614
来自专栏阿凯的Excel

Python读书笔记12(IF语句应用)

今天和大家分享的是所有函数、所有编程的基础,判断! IF语句! IF语句肯定是进行判断,为真怎样,为假如何。 那这个真假就是某个条件是否满足,和Python相...

3709
来自专栏技术总结

正则表达式,看我就懂

不管你学的是什么语言,Java,iOS,安卓,都需要用到正则表达式,又因为正则表达式相通(每种语言几乎一样),所以在哪种语言学会正则,都可以用到其他语言中,下面...

925
来自专栏java学习

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

每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?_...

35416
来自专栏一“技”之长

Swift专题讲解十八——异常处理 原

        代码的运行很多时候并不会完全按照程序员的设想进行,编写代码时进行可控的异常处理机制是十分必要的。通常,对于一个特定的操作,程序员可以定义一个继承...

702
来自专栏惨绿少年

AWK常用技巧

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确...

1884
来自专栏宏伦工作室

全栈 - 4 Python 先学会基本语法

2577
来自专栏pangguoming

理解js中的new

new 操作符 在有上面的基础概念的介绍之后,在加上new操作符,我们就能完成传统面向对象的class + new的方式创建对象,在Javascript中,我们...

3964
来自专栏菜鸟计划

javascript 基本概念

一、在HTML中使用javascript 1.直接是用<script></script>标签。 2.外部引入 <script type="javascript"...

2623
来自专栏锦小年的博客

python学习笔记4.2-python高级之迭代器

迭代是Python中最强有力的特性之一,同时对编程人员来说,也是最难理解的一种用法。其实从高层次来看,迭代就是一种处理序列中元素的方式。通过自定义迭代对象可以...

21010

扫码关注云+社区

领取腾讯云代金券