JavaScript学习笔记(一)——核心语法

时间:2022-08-26 17:03:36
  • JavaScript数据类型分为两类:原始类型和对象类型;原始类型包括数字、字符串和布尔值。JavaScript基本数据类型包括:数字、字符串、布尔值、null、undefined、对象(包括数组、函数)。
  • 任意JavaScript的值都可以转换成布尔值,其中undefined、null、0、-0、NaN、"" 将被转换成false
  • null、undefined都不包含任何属性和方法(也就是它们之后不能接 “.” 和 “[ ]”)。
  • 字符串所有的方法返回的是一个新的字符串值。
  • in运算符希望它的左操作数是一个字符串或可以转换成字符串,希望它的有操作数是一个对象,如果右侧的对象拥有一个名为左操作数值的属性名,那么返回true。instanceof运算符希望它的左操作数是一个对象,右操作数标识对象的类,如果左侧的对象是右侧类的实例,则返回true。
  • typeof运算符返回的值分别为:
    undefined            "undefined" ;
null "object"
true/false "boolean" ;
任意数字或NaN "number" ;
任意字符串 "string" ;
任意函数 "function" ;
任意内置对象(非函数) "object" ;
任意宿主对象 由编译器各自实现的字符串,但不是"undefined""boolean""number""string"
  • 两个单独的对象永不相等,两个单独的数组永不相等,如下例:
    var o = {x:1} , p = {x:1};
o === p; // false
var a = [1,2] , b = [1,2];
a === b; // false
  • delete运算符只能删除自有属性,不能删除继承属性。delete只是断开属性与宿主对象之间的联系,并不会去操作属性中的属性,如下例:
    var a = { p:{x:1} };
var b = a.p;
delete a.p;
b.x // 值为1
  • 检测摸个属性是否存在于某个对象中,可以通过in、hasOwnProperty()、propertyIsEnumerable()来判断。(1) in运算符左侧是属性名、右侧是对象,如果对象的自有属性或继承属性中包含这个属性,则返回true,否则返回false;(2) 对象的hasOwnProperty()方法用来检测该属性是否为对象的自有属性;(3) propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到该属性是对象的自有属性且该属性可枚举时(比如toString方法不可枚举),返回true。还可以通过 “!==” 来检测属性是否为undefined,例:var o = {x:1}; o.x !== undefined; /*true*/ o.y !== undefined; /*false*/,in可以区分不存在的属性和存在单值为undefined的属性,例:
    var o = { x:undefined };
o.x !== undefined; //false:属性存在,但值为undefined,应该是 ===
o.y !== undefined; //false:属性不存在
"x" in o; // true:属性存在
"y" in o; // false:属性不存在
  • 数据属性的4个特性分别是:它的值(value)、可写性(writable)、可枚举性(enumerable)、可配置性(configurable);存取器属性不具有值特性和可写性,它的可写性是有setter方法是否存在决定的,它的4个特性分别是:读取(get)、写入(set)、可枚举性(enumerable)、可配置性(configurable)。writable、enumerable和configurable是布尔值,get属性和set属性是函数值
  • JSON.stringify()将对象装换成JSON(只能序列化对象的可枚举属性),JSON.parse()将JSON转换成JavaScript对象。JSON并不能表示JavaScript里所有的值,支持对象、数组、字符串、无穷大数字、true、false和null
  • JavaScript数组是无类型的,数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类型,包括其他的数组和对象;JavaScript数组是动态的,根据需要它们会自动增长或缩减;JavaScript数组可能是稀疏的,数组元素的索引不一定是连续的,稀疏数组的length比数组的所有元素的索引大。
  • 关于类数组对象,JavaScript数组有一些特性是其他对象没有的,如自动更新length属性值、设置length为一个较小值能将数组截断、可以从Array.prototype中继承一些有用的方法、其内属性为”Array”。常见的类数组对象有:Arguments对象document.getElementsByTagName()返回的值
  • 数组元素的添加和删除:push()方法在数组末尾添加一个或多个元素,unshift()方法在数组的首部插入一个或多个元素,并将其他元素依次移到更高的索引处;删除元素与为其赋undefined值是类似的(只是赋undefined值不会修改length属性,也不会移动其他元素的索引),pop()方法删除数组末尾的一个元素并返回删除的元素,shift()方法删除数组首部的一个元素并返回删除的元素。
  • 数组的reverse()方法返回逆序的数组,它不返回新数组,而是再原先的数组上重新排列它们。sort()方法将数组排序,也是在原先的数组上排序,不返回新数组
  • Array.concat()方法创建并返回一个新数组,它的元素包括调用concat()的原始数组的元素和concat()的每个参数,如果参数中的任何一个自身是数组,则连接的是数组的元素,而非数组本身,例:
    var a = [1,2,3];
a.concat(4,5); //返回[1,2,3,4,5]
a.concat(4,5,[6,7]); //返回[1,2,3,4,5,6,7]
a.concat(4,[5,[6,7]]); //返回[1,2,3,4,5,[6,7]]
  • Array.slice()方法返回指定数组的一个片段或子数组,它的2个参数分别指定了片段的开始和结束的位置。返回的数组包含第一个参数指定的位置和所有到但不包含第二个参数制定的位置之间的所有数组元素。如果只有一个参数,返回的数组包含从参数指定的位置到数组结尾的所有元素。如果参数出现负数,则表示相对于数组中最后一个元素的位置(负几就是倒数第几个元素)。slice()方法不会修改原数组。(总结:push后增,pop后删,unshift前增,shift前删)
  • Array.splice()方法是数组插入和删除元素的通用方法。它在插入或者删除后的数组元素会根据需要增加或减小它们的索引值,因此数组其他部分依然保持连续。splice()的第一个参数指定了插入和(或)删除的起始位置。第二个参数指定了应该从数组中删除的元素的个数。如果省略第二个参数,则删除从起始位置到数组结尾的所有元素。splice()返回一个由删除元素组成的数组(操作的是原数组,但返回的是删除的元素组成的数组)。splice()的前2个参数指定需要删除的数组元素,其后的任意参数指定了需要插入到数组中的元素,从第一个参数指定的位置开始插入如果插入的参数中有数组,则直接插入数组,而插入不是数组的元素,区别于concat()方法),下面一些例子:
    var a = [1,2,3,4,5];
a.splice(3); //返回[4,5] , a = [1,2,3]
a.splice(1,1); //返回[2] , a = [1,3]
var b = [1,2,3,4,5];
b.splice(2,0,"a","b"); //返回[] , b = [1,2,"a","b",3,4,5]
b.splice(2,2,"c",[1,2]); //返回["a","b"] , b = [1,2,"c",[1,2],3,4,5]
  • Array.every()Array.some()方法对数组元素应用指定的函数进行判断,返回true或false。some()在判定函数第一次返回true就停止遍历,返回true;every()在判定函数第一次返回false就停止遍历,返回false。注意:如果数组是空数组,every()返回true,some()返回false
  • Array.reduce()Array.reduceRight()方法使用指定的方法将数组元素组合,生成单个值。reduce()需要2个参数,第一个参数是执行化简操作的函数,第二个参数可选,是传递给函数的初始值。reduceRight()和reduce()差不多,只是reduceRight()按照数组索引从高到低(从右到左)处理数组,如下例:
    var a = [1,2,3];
a.reduce(function(x,y){ return x+y },0); //数组求和,返回6
a.reduce(function(x,y){ return x>y?x:y }); //求数组最大值,返回3
  • 关于this关键字,它在函数中没有作用域限制,嵌套的函数不会从调用它的函数中继承this。如果嵌套函数作为方法调用,其this值指向调用它的对象,如果嵌套对象作为函数调用,其this值为全局对象(非严格模式)或undefined(严格模式),而不会指向调用外层函数的上下文,例:
    var o = {
m : function(){
var self = this; //将this值保存到一个变量中
console.log(this === o); // true:this对象就是o
f(); //调用函数f()
function f(){
console.log(this === o); // false:嵌套函数的this为全局对象或undefined
console.log(self === o); // true:self就是外部的this
}
}
}
o.m(); //调用对象o的方法m()
  • 如果函数或者方法调用之前带有关键字new,它就变成构造函数,凡是没有形参的构造函数调用都可以省略圆括号,如var o = new Object()var o = new Object是等价的。构造函数调用将创建一个新的空对象,这个对象继承自构造函数的prototype属性。这个构造函数可以使用this关键字来引用这个新创建的对象,如new o.m()中,调用上下文的并不是o.
  • 实参对象arguments是一个类数组对象,除了数组元素外,还包含calleecaller两个属性。在ES5严格模式中,对2个属性读写操作都会产生一个类型错误;在非严格模式中,callee属性指代当前正在执行的函数,caller属性指代调用当前正在执行的函数的函数(???)。callee属性可以在匿名函数中实现递归调用自身,如下:
    var a = function(x){
if(x <= 1) return 1;
return x * arguments.callee(x-1);
};
  • 函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的,下面区别2个例子:
    var scope = "global scope";  //全局变量
function checkscope(){
var scope = "local scope"; //局部变量
function f(){
return scope; //返回scope
}
return f(); //在函数checkscope内部调用f()
}
chekcscope(); // => "local scope"
    var scope = "global scope";  //全局变量
function checkscope(){
var scope = "local scope"; //局部变量
function f(){
return scope; //返回scope
}
return f; //将在函数checkscope外部调用f()
}
chekcscope()(); // => "local scope"
  • 函数可以通过call()apply()间接调用,可以将call()和apply()看做是某个对象的方法。call()和apply()的第一个参数是要调用函数的母对象,它调用上下文,在函数体内通过this获得对它的引用。在ES5严格模式中,第一个实参会变成this的值(包括原始值、null、undefined),在ES3和非严格模式中,传人的null和undefined会被全局对象代替,其他原始值会被相应的包装对象替代。call()方法第一个实参之后的其他所有实参就是要传入待调用函数的值,如f.call(o,1,2)apply()方法与call()类似,只是它的实参放入一个数组中(可以传类数组,如arguments),如f.apply(o,[1,2])。下面是2个具体的例子(返回函数所有参数的和):
    function sum(){
return Array.prototype.reduce.call(arguments,function(a,b){ //arguments为调用上下文
return a+b;
},0);
}
sum(2,4,6); // =>12
    function sum(){
return Array.prototype.reduce.apply(arguments,[function(a,b){ //arguments为调用上下文
return a+b;
},0]);
}
sum(2,4,6); // =>12
  • bind()方法将函数绑定至某个对象,可以通过f.apply(o,arguments)来模拟bind()方法,例:
    function f(y){    //这个是待绑定的函数
return this.x + y;
}
var o = { x:1 }; //将要绑定的对象
var g = f.bind(o); //通过调用g(x)来调用o.f(x)
/* 上面这行可以换成: var g = function(){
* return f.apply(o,arguments);
* }
*/

g(2); // =>3
  • 对于任意函数F,F.prototype.constructor === F,constructor属性为对象提供了类。
  • 正则表达式中,^ $ . * + ? = ! : | \ / ( ) [ ] { }具有特殊含义,需要加\转义。