前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >javascript高级程序设计(4-5)章笔记

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

作者头像
空空云
发布2018-09-27 11:58:36
4330
发布2018-09-27 11:58:36
举报
文章被收录于专栏:大前端_Web

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://cloud.tencent.com/developer/article/1347593

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

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

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

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

代码语言:javascript
复制
//基本类型值没问题
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来释放引用——俗称解除引用。适用于大多数全局变量和全局对象的属性,局部变量会在他们离开执行环境时自动解除引用。

代码语言:javascript
复制
//执行完毕,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页)】

安全的类型检测

代码语言:javascript
复制
var isArray = value instanceof Array;

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

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

代码语言:javascript
复制
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类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

代码语言:javascript
复制
//函数是对象,函数名是指针
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),并使其在执行任何代码之前可用,至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。

  • 作为值的函数
代码语言:javascript
复制
        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()函数的值。

基本包装类型

代码语言:javascript
复制
var s1 = 'some text';
var s2 = s1.substring(2);

上述可以解析成三个步骤

1.创建String类型的一个实例;

2.在实例上调用指定的方法;

3.销毁这个实例

执行代码类似如下:

代码语言:javascript
复制
var s1 = new String('some text');
var s2 = s1.substring(2);
s1 = null;

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

小结

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年04月24日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4.变量 作用域和内存问题
    • ECMAScript中所有函数的参数都是按值传递的(不区分基本类型和引用类型)
      • 执行环境及作用域
        • 垃圾收集
          • 管理内存
            • 小结
            • 5.引用类型
              • 安全的类型检测
                • Function类型
                  • 基本包装类型
                    • 小结
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档