23. Object对象 构造函数的参数若为对象,则返回原参数对象,指向同一个对象的引用(可基于此判断一个参数变量是否为对象即value===Object(value)); 构造函数的参数为原始数据类型,则返回包装后的对象。如Number、Boolean、String等,其中无参或参数为undefined或null均返回一个空对象。 添加新方法: 1. 通过直接在Object类上创建,也即Object.some_function = function(obj){some-codes;}可以使用该类的方法, 但是创建的Object对象实例是不能使用该some_function(var obj = new Object();obj.some_function(some_obj)会失败), 但仅能被Object调用,即Object.some_function(obj)(Object自身对象的静态方法,不同于C++、Java的静态方法);。 2. 在Object的原型属性上创建,即Object.prototype.some_function = function(obj){some-codes;},此时通过Object创建的 各个对象均可以调用该some_function函数(该函数式Object.prototype对象的属性), 即var obj = new Object();obj.some_function(some_obj);凡是在Object.prototype对象上的属性和方法均被所有实例对象所共享。 Object自身对象的静态方法: keys:返回对象属性的数组,只返回可枚举的属性。 getOwnPropertyNames:返回对象属性的数组,包括不可枚举的属性。 Object的实例对象的方法: 实例对象的方法一部分为继承于Object的prototype原型对象上的方法,另外也可以添加自己的实例对象方法。 注意:Object对象上的预定义的方法或者新添加的方法,在Object实例对象或者子类对象实例上都不会被继承,但可通过某种方式可实现。 valueOf方法:实际上是来自于Object的prototype原型对象上的方法,在自动类型转换的地方会默认使用该方法。 toString方法:同valueOf,但其返回对象的字符串形式,另外同样在自动类型转换的地方会有用。 部分预定义的对象,如数组、字符串、函数、Date对象都分别实现各自版本的toString方法,覆盖了Object.prototype.toString方法 (事实上并不是覆盖,只是在调用的时候优先选择自身对象同名的函数而已,若要调用原型上的方法,则可通过调用原型对象上该函数 的call/apply方法,如Object.prototype.toString.call(obj),obj为该自身对象)。 24. Array对象 Array既是内置对象也是构造函数,其中参数可以作为构造长度或是初始化数据内容,不过此方式行为因参数类型不一样, 大多数时候不建议使用构造函数的方式来初始化Array对象。如:new Array(23.4)与new Array(23.4, 12.3)前者会报错,后者生成[23.4,12.3] 的数组,此外new Array(10)将创建个数为10,内容为undefined的数组(但没有键名值),故一般使用字面量的方式初始化创建数组对象。 isArray方法:可判断一个对象或值是否为Array类型,typeof运算符对Object类型判断是无能为力的,可借助此类函数或toString方法来判断。 push方法:数组末尾添加元素并返回添加新元素后的数组长度 pop方法:数组末尾删除最后一个元素。 join方法:以参数作为分隔符,将所有数组成员组成一个字符串返回。如果不提供参数,默认用逗号分隔。 concat方法:用于多个数组的合并,并返回新的合并后的数组。 shift方法:用于删除数组的首部元素,并返回该元素。 unshift方法:用于在数组的首部添加元素,并返回添加新元素后的数组长度。 reverse方法:用于颠倒数组中元素的顺序,返回改变后的数组。 slice方法:切片,用于提取原数组的一部分,返回一个新数组,原数组不变,另外其可将类似数组的对象转为真正的数组,如: Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })、Array.prototype.slice.call(arguments);等。 splice方法:用于删除原数组的一部分成员,并可以在被删除的位置添加新的数组成员,返回值是被删除的元素,其也可达到切片的目的。 sort方法:按照字典顺序排序,若为数值会被先转成字符串,再按照字典顺序进行比较,此可能导致如101<11,故可传入自定义比较函数实现; map方法:对数组的所有元素依次调用同一个传参函数,根据函数结果返回一个新数组,该函数将被传入三个参数,分别为元素对象,元素当前位置, 以及数组对象本身;此外map也可传入第二个参数,以表示回调函数执行时this所指向的对象(若回调函数中有this关键字时)。 forEach方法:与map方法类似,不过不返回数组,只用来操作数据,同样也可以传第二个参数,指代回调用的this所指向的对象。 filter方法:参数是一个函数,所有数组元素依次执行该函数,返回结果为true的成员将组成一个新数组返回,不影响原数组对象。 some方法:参数为测试函数,即只要有一个数组元素的返回值是true(即通过该测试函数),则整个some方法的返回值就是true。 every方法:参数也为测试函数,要求所有数组元素的返回值都是true,才返回true,否则false;对于空数组[],无论测试函数条件如何, some方法始终返回false,every方法则返回true。 reduce方法和reduceRight方法:遍历处理数组的每个成员,最终累积计算为一个值,累积执行次数length-1次,前者从左右至右,后者从右至左; 此外,此两个方法的第一个参数为一个累积执行函数,该函数的参数分别为累积变量、累积的执行时的当前变量、累积执行的当前位置、原数组对象; 该累积执行函数返回值将作为下一次累积执行的第一个参数(累积变量);reduce和reduceRight方法可指定第二个参数,用以指定累积变量的初值, 当指定了初值时,累积执行次数变为length次,累积执行的当前位置将从0开始;指定了初始累积值在数组为空时可防止执行reduce报错。 indexOf方法:返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1。 lastIndexOf方法:返回给定元素在数组中最后一次出现的位置,如果没有出现则返回-1;当数组中包含NaN时,查找该数组中是否有NaN会失败, 无法找到元素,如[NaN].lastIndexOf(NaN);[NaN].indexOf(NaN)返回-1;但对于null和undefined可以找到。 25. 属性描述符 26. 对象 JavaScript的面向对象是基于构造函数和原型链,不同于C++/Java的基于类/类继承。 JavaScript使用构造函数(constructor)作为对象的模板,它提供模板,描述对象的基本结构。 构造函数与普通函数一样,故为了与普通函数区别,构造函数名字的第一个字母通常大写, 此外函数体内部使用了this关键字,代表了所要生成的对象实例;生成对象的时候,需用new来调用该构造函数。 若没有添加new调用构造函数,则只是调用普通函数,且可能导致难以预料的问题,可采取一些方式来防止没有调用new来构建对象,如: function Obj(){if(!(this instanceof Obj)){return new Obj();}}或者 function Obj(){if(new.target !== Obj){return new Obj();}}。 new操作符执行流程: 1. 创建一个空对象,作为将要返回对象的实例; 2. 将此空对象的原型指向构造函数的prototype原型属性对象; 3. 将此空对象赋值给内部函数的this关键字; 4. 执行构造函数内部的代码。 若构造函数内部有return语句,而且return后面跟着一个对象(不是基本的原始数据类型),而不会返回this对象,否则返回this对象。 同样的,若构造函数内部无this关键字(退化为普通函数,且若内部没有return一个对象(不是基本的原始数据类型)), 调用了new创建对象返回的是空对象。 使用Object.create创建实例对象,有时只能拿到实例对象,而该对象根本就不是由构造函数生成的,这时可以使用Object.create()方法, 直接以某个实例对象作为模板,生成一个新的实例对象,即:var Obj = {'attr':'value'};var subObj = Object.create(Obj); 此时subObj继承了前者的属性和方法。