JavaScript高级程序设计读书笔记(持续更新)

本文深入探讨了JavaScript中变量的基本类型与引用类型的区别,详细介绍了变量赋值、作用域和内存管理等内容,并对数组与函数类型进行了全面解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第四章.变量、作用域和内存问题

4.1基本类型和引用类型的值

  • 基本类型值指的是简单的数据段,而引用类型值指那些可能有多个值构成的对象,注意是对象;
  • 以下两段代码说明了只能给引用类型值动态地添加属性,以便将来使用。
var person = new Object();
person.name = "Chaney";
alert(person.name);    //Chaney
//错误的对比演示
var name = "Chaney";
name.age = 27 ;
alert(name.age);    //undefined
  • 1.基本类型值的赋值,从一个变量向另一个变量复制基本类型的值,会在变量对象上创建新值,再把新值复制到新变量分配的位置上,两变量是完全独立的,相互之间不受影响;
    2.引用类型值得赋值,复制操作结束后,两个变量是引用了同一个对象,因此改变其中一个变量,就会影响到另一个变量;
  • ECMAScript中所有函数的参数都是按值传递的,
//换句话说,即使person这个变量是按值传递的,obj也会按引用来访问同一个对象,因此函数内部为obj添加name属性后,函数外部的person也会有反映。
function setName(obj){
        obj.name="Chaney";
    }
    var person= new Object();
    setName(person);
    alert(person.name); //"Chaney"
//即使函数内部修改了参数的值,但原始的引用仍然保持不变。实际上当在函数内部重写obj时,这个变量引用的就是一个局部对象了,这个局部对象会在函数执行完毕后会立即被销毁;
function setName(obj){
        obj.name="Chaney";
        obj=new object();
        obj.name ="Bobo";
    }
    var person= new Object();
    setName(person);
    alert(person.name); //"Chaney"
  • 如果变量的值是一个对象或者null,则typeof操作符会返回”object”;
  • 想知道某对象是什么类型的对象,就需要用到instanceof
alert(person instanceof Object);    //变量person是Object吗?
alert(colors instanceof Array);    //变量colors 是Array吗?
alert(pattern instanceof RegExp);    //变量pattern 是RegExp吗?

4.2执行环境及作用域

  • 没有块级作用域,对于JavaScript来说,有for语句创建的变量i即使在for循环执行结束后,也依旧会存在于循环外部的执行环境中。(if语句同理)
  • 变量声明,如果在函数内部的变量声明中没有用var,也会变成全局变量,添加到全局环境(不推荐使用)。但,在严格模式下,初始化未经声明的变量会导致错误
  • 查询标识符
//首先,搜索getColor()的变量对象中是否包含名为color的标识符,没有找到的情况下,搜索到下一个变量对象(即全局环境的变量对象),最后找到了名为color的标识符
//变量声明提升:如果在函数内部访问了一个在他后面定义的变量,会把这个变量的声明提升,提升到函数最前面不会提升赋值
var color="blue";
function getColor(){
   return color;
}
alert(getColor());    //"blue"

第五章.引用类型

5.2Array类型

  • 如果设置某个值的索引超过了数组现有项数,数组就会自动增加到该索引值加1的长度
  • 数组的length属性很有特点,它不是只读的,通过设置这个属性,可以从数组的末尾移除项或想数组中添加新项
//移除最后一项
var colors=["red","blue","green"];    //length为3的数组
colors.length=2;
alert(colors[2]);    //undefined
//在最后增加一项
var colors=["red","blue","green"];    //length为3的数组
colors.length=4;
alert(colors[3]);    //undefined
  • 检测数组,Array.isArray( )方法,就是确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的
if(Array.isArray(value) ){
    //对于数组执行某些操作
}
  • 所有对象都具有toLocaleString( )、toString( )和valueOf( ),默认情况下都会以逗号分隔的字符串形式返回数组项,如果使用join( )则可以使用不同的分隔符来创建这个字符串
  • 栈方法:
    1.push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后的数组的长度
    2.pop()方法则从数组末尾移除最后一项,减少数组的length值,然后返回删除项
var colors = ["red","blue"];
colors.push("brown");    //push在最后推入一项
colors[3]="black";    //length不是只读的,可在数组最后添加一项
alert(colors.length);    // 4

var item = colors.pop( );    //pop删除最后一项
alert(item);         //"black"
  • 队列方法(先进先出):
    1.结合使用shift( )和push( )方法就可以像使用队列一样使用数组了
    2.同时使用unshift( )和pop( )方法可以从相反的方向模仿队列
  • 重排序方法:reverse( )和sort( ),但都有缺陷,系统会把数组中的所有的数字转化为ASCII字符,然后按照字符来排序,因此sort( )方法可以接收一个比较函数作为参数,以便我们指定哪个值位于哪一个值的前面
function compare(value1,value2){
    return value1>value2?1:-1;
}
var values=[0,5,15,10,1];
values.sort(conpare);
alert(values);    //0,1,5,10,15
  • 操作方法
  • 1.concat()方法可以基于当前数组中的所有项创建一个新数组,最后的原数组保持不变
  • 2.slice()方法能够基于当前数组中的一或多个项创建一个新数组,接受一到两个参数,即要返回项的起始和结束位置,返回项里不包括结束位置的想。注意,该方法不会影响原数组,如果参数中有负数,则用数组长度加上该参数确定相应的位置。
var colors=["red","green","blue","yellow","purple"];
var colors2=colors.slice(1);
var colors3=colors.slice(1,4);

console.log(colors2);     //red,green,blue,yellow,purple
console.log(colors3);    //red,green,blue,yellow
  • 3.splice()方法的主要用途是向数组的中部插入项,该方法会始终返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组),有三种方式
    a.删除,可以删除任意数量的项,只需指定2个参数:要删除的第一项的位置和要删除的项数。例如,splice(0,2)会删除数组中的前两项
    b.插入,可以向指定位置插入任意数量的项,只需提供3个参数:起始位置、0(要删除的项数)、和要插入的项。如果要插入多个项,可以再传入第四、第五以至任意多个项。例如,splice(2,0,”red”,”green”)会删除当前数组位置为2的项,然后再从位置2开始插入字符串”red”和”green”
    c.替换,可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。
var colors=["red","green","blue"];
var removed=colors.splice(0,1);    //删除第一项
console.log(colors);    //green,blue
console.log(removed);   //red,返回的数组中只包含一项

removed=colors.splice(1,0,"yellow","orange");   //从位置1开始插入两项
console.log(colors);    //green,yellow,orange,blue
console.log(removed);    //返回的是一个空数组

removed=colors.splice(1,1,"red","purple");   //删除一项,插入两项
console.log(colors);    //green,red,purple,orange,blue
console.log(removed);    //yellow,返回的数组中只包含一项
  • 位置方法:indexOf()和lastIndexOf()。这两个方法接收两个参数:要查找的项和(可选的)表示查找起点位置的索引,都返回要查找的项在数组中的位置,或者没有找到就返回-1,要求查找的项必须严格相等(就像使用===一样)。indexOf()方法从数组的开头(位置0)开始向后查找,而lastIndexOf()方法则从数组的末尾向前查找。
  • 迭代方法,以下方法都不会修改数组中的包含的值
    1.every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
    2.filter():对数组中的每一项运行给定的函数,返回该函数会返回true的项组成的数组。
    3.forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
    4.map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
    5.some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
//every
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item,index,array){
    return(item>2);
});
console.log(everyResult );   //false

//some
var someResult = numbers.some(function(item,index,array){
    return(item>2);
});
console.log(someResult);    //true
//filter
var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item,index,array){
    return(item>2);
});
console.log(filterResult);   //[3,4,5,4,3]
//map
var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item,index,array){
    return(item>2);
});
console.log(mapResult);   //[2,4,6,8,10,8,6,4,2]
//forEach
//forEach()方法,并没有返回值,本质上与使用for循环迭代数组一样
var numbers = [1,2,3,4,5,4,3,2,1];
var forEachResult = numbers.forEach(function(item,index,array){

});
  • 归并方法:reduce()和reduceRight(),两个方法都会迭代数组的所有项,然后构建一个最终返回的值。reduce()方法从数组的第一项开始,逐个遍历到最后。reduceRight则相反。这两个方法接收两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值。而传给两个方法的函数参数又接收4个参数:前一个值,当前值,项的索引和数组的对象
//使用reduce()方法可以执行求数组中所有值之和的操作
//第一次执行回调函数,prev是1,cur是2。第二次,prev是3(1加2的结果),cur是3(数组的第三项)。这个过程会持续到数组中的每一项都访问一遍,最后返回结果
var values=[1,2,3,4,5];
var sum=values.reduce(function(prev,cur,index,array){}
    return prev+cur;
);
console.log(sum);    //15

5.5Function类型

  • 函数是对象,函数名是指针。注意,使用不带圆括号的函数名是访问函数指针,并非调用函数
  • 一个函数可能会有多个名字
function sum(num1,num2){
        return num1+num2;
    }
    console.log('第一次sum'+sum(10,10));    //20

    var anotherSum=sum;
    console.log("第一次another"+anotherSum(10,10));    //20

    sum=null;
    console.log("第二次another"+anotherSum(10,10));    //20
    console.log('第二次sum'+sum(10,10));   //Uncaught TypeError: sum is not a function
  • 没有重载
//通过观察重写后的代码,可以知道,在创建第二个函数时,实际上覆盖了引用第一个函数的变量addSomeNumber。
function addSomeNumber(num){
    return num+100;
}
function addSomeNumber(num){
    return num+200;
}
var result = addSomeNumber(100);    //300
  • 函数声明与函数表达式的区别,解析器会率先读取函数声明,并使其在实行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
//以下代码完全可以正常运行,代码开始执行前,解析器就已经通过函数声明提升的过程,读取并将函数声明添加到执行环境中(运用了函数声明)
alert(sum(10,10));
function sum(num1,num2){
    return num1+num2;
}
//但是以下代码就会在运行期间报错了,(运用了函数表达式)
alert(sum(10,10));
var sum = function(num1,num2){
    return num1+num2;
}
  • 作为值的函数,以下是根据一个对象数组里某一个对象属性来进行排序的需求例子
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:"chaney",age:23},{name:"Bobo",age:24}];

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

data.sort(createComparisonFunction("age"));
alert(data[0].name);    //"Chaney"
  • 函数内部属性,在函数内部有两个特殊的对象:arguments,thisarguments是一个类数组对象,包含着传入函数中的所有参数。arguments对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
//经典的阶乘函数
//使用了arguments.callee,消除了紧密耦合的现象
function factorial(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * arguments.callee(num - 1);
        }
    }
  • 函数内部的另一个特殊对象是this。this引用的是函数执行的环境对象(当在网页的全局作用域中调用函数式,this对象引用的就是window)
  • 函数属性和方法—(属性)。每个函数都包含两个属性:lengthprototype
    1.length属性表示函数希望接收的命名参数的个数;
    2.prototype。对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。prototype属性是不可枚举的,因此使用for-in无法发现。
  • 函数属性和方法—(方法)。每个函数都包含两个非继承而来的方法:apply( )call( )。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

1.apply()方法接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中第二个参数可以是Array的实例,也可以是arguments对象

 function sum(num1,num2){
        return num1+num2;
    }
    function applySum1(num1,num2){
        return sum.apply(this,arguments);   //传入arguments对象
    }
    function applySum2(num1,num2){
        return sum.apply(this,[num1,num2]); //传入数组
    }
    alert(applySum1(10,10));    //20
    alert(applySum2(10,10));    //20

2.call()方法与apply()方法的作用相同,区别仅在与接收参数的方式不同。第一个参数是this值没有变化,变化的是其余参数都是直接传递给函数,换句话说就是传递给函数的参数必须逐个列举出来

//函数结构与apply的例子基本相同,以下是不同之处
return sum.call(this,num1,num2);

事实上,传递apply()call()它们真正强大的地方是能够扩充函数赖以运行的作用域

window.color="red";
var o={color:"blue"};
function sayColor(){
      alert(this.color);
}
sayColor();     //red

sayColor.call(this);    //red
sayColor.call(window);  //red
sayColor.call(o);   //blue;

5.7.2Math对象

1.1 min()和max()

这两个方法经常用于避免多余的循环和在if语句中确定一组数的最大值

  • min( ),用于确定一组数值中的最小值
  • max( ),用于确定一组数值中的最大值
var max=Math.max(3,54,32,16);
alert(max);   //54

var min=Math.min(3,54,32,16);
alert(min);   //3
//要找到数组中的最大或最小值,可以像下面这样使用apply()方法
var values = [1,2,3,4,5,6,7,8,9,99 ];
var max=Math.max.apply(Math,values);
1.2 舍入方法
  • Math.ceil( ) 执行向上舍入;
  • Math.floor( ) 执行向下舍入;
  • Math.round( ) 执行标准舍入,即四舍五入;
1.3 random( )方法
  • Math.random( )方法返回大于等于0小于1的一个随机数(0<=x<1);
//利用这个方法,可以从某个整数范围内随机选择一个值
//值 = Math.floor(Math.random( ) * 可能值得总数 + 第一个可能的值)
//例如:想选择一个1到10之间的数值
var num = Math.flooor(Math.random() * 10 + 1);
1.4 其他方法
  • Math.abs(num); 返回num的绝对值
  • Math.exp(num); 返回Math.E的num次幂
  • Math.log(num); 返回num的自然对数
  • Math.pow(num,power); 返回num的power次幂
  • Math.sqrt(num); 返回num的平方根
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值