js精研

一 . 基础补充

1.值,变量和类型

  • typeof undefined;//“undefined”

  • js是基于32位整数的

  • 以下两种情况,js会自动将数值转为科学计数法

    • 小数点前的数字多于21位
    • 小数点后的0多于5个
  • 在js内部,实际存在两个0:+0和-0,他们是等价的

  • 当js在算数运算时发生溢出(overflow,结果是Infinity),下溢(underflow,结果是-Infinity)或被0整除时不会报错

  • Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。isFinite函数返回一个布尔值,检查某个值是不是正常数值,而不是Infinity。

  • 注意:0除以0是无意义的,会返回NaN

    • isNaN判断一个值是否为NaN,它只对数值有效,若传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回true,这一点要特别引起注意。也就是说,isNaN为true时,有可能不是NaN,而不是一个字符串
    • 使用isNaN前,最好判断一下数据类型 typeof value===’number’&& isNaN(value)
    • 判断NaN更可靠的方法是利用NaN在js中唯一不等于自身的值这个特点进行判断 value!==value
  • 字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。

    • length属性返回字符串的长度,该属性也是无法改变的。

    • 如果方括号中的数字超过字符串的长度,或者方括号中根本不是数字,则返回undefined。

    • 注意:字符串与数组仅仅是相似而已。字符串是无法改变字符串之中的单个字符。

      var a = ‘hello’;

      delete s[0];

      s // “hello”

      s[0] = ‘a’;

      s // “hello”

  • 尽管null和undefined是不同的,但它们都表示“值的空缺”,两者往往可以互换。当用相等运算符“==”来比较两者时,会返回true。(要使用严格相等运算符“===”来区分它们)

  • 如果JavaScript预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true。

    undefined
    null
    false
    0
    NaN
    “”或’’(空字符串)

  • 如果一个变量没有声明就直接使用,JavaScript会报错,告诉你变量未定义。

  • 声明提前(变量提升)

    • JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就是声明提前(变量提升,hoisting)。
    • 变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。
  • typeof运算符对未声明的变量运算,不会报错,输出值也是“undefined”,故不能区分该值是否已声明,但是其他运算符对未声明变量进行运算会报错

  • 对于浮点字面量的有趣之处在于,用它进行计算之前,真正存储的是字符串。任何值在输出时一般都会转化成字符串输出

  • ECMAScript默认把具有6个或6个以上前导0的浮点数转化成科学计数法。也可以用64位IEEE 754形式存储浮点值,这意味着十进制最多可以有17个十进制位,17位之后的值将被裁剪,从而造成较小的误差

  • 当计算生成的数大于 Number.MAX_VALUE 时,它将被赋予值Number.POSITIVE_INFINITY,意味着不再有数字值。同样,生成的数值小于Number.MIN_VALUE 的计算也会被赋予值Number.NEGATIVE_INFINITY,也意味着不再有数字值。如果计算返回的是无穷大值,那么生成的结果不能再用于其他计算。

2.语句

  • 注意:由于对每个case的匹配操作实际是“===”恒等运算符比较,而不是“==”相等运算符比较,因此,表达式和case的匹配并不会做任何类型转换。

  • 使用while(true)则会创建一个死循环。

  • 标签语句

    • 语句是可以添加标签的,标签是由语句前的标识符和冒号组成:

      label : statement

  • return语句只能在函数体内出现,否则报错。当执行到return语句时,函数终止执行。

  • throw语句:异常是指当发生了某种异常情况或错误时产生的一个信号。

  • with语句:用于临时扩展作用域链

    with ( object ){

    statement

    }

    将object添加到作用域链的头部,然后执行statement,最后把作用域链恢复到原生状态。

    注意:在严格模式中是禁止使用with语句的。

  • debugger语句用来产生一个断点(breakpoint),JavaScript代码的执行会停止在断点的位置。一般用来调试代码。

  • “use strict”

    使用”use strict”指令的目的是说明后续的代码将会解析成严格代码。

3.对象

  • 对象是一个基本数据类型,成员以键值对形式存在

  • 键名:对象的所有键名都是字符串,所以加不加引号都可以。如果键名是数值,会被自动转为字符串。

  • 对象的每一个“键名”又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。

  • 如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),也不是数字,则必须加上引号,否则会报错。

  • 为了避免这种歧义,JavaScript规定,如果行首是大括号,一律解释为语句(即代码块)。如果要解释为表达式(即对象),必须在大括号前加上圆括号。

  • 创建对象

    在JavaScript中,有三种方法创建对象

    1
    2
    3
    对象直接量: var o={};
    关键字new: var o=new Object();
    Object.create()函数: var o=Object.create(null)
  • 对象直接量中的最后一个属性后的逗号可有可无,但是在ie中,如果多了一个逗号,会报错。通过new创建对象

    new运算符创建并初始化一个新对象。关键字new后跟随一个函数调用,这个函数称做构造函数(constructor)。

  • 属性名可以是包含空字符串在内的任意字符串,但对象中不能存在两个同名的属性。

  • 读取对象的属性

    • 有两种方法,一种是使用点运算符(最终还是得先变成方括号),还有一种是使用方括号运算符
    • 数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运算符。
    • 通过点(.)或方括号([])运算符来获取属性的值时,运算符左侧应当是一个表达式,它返回一个对象。
  • 查看一个对象本身的所有属性,可以使用Object.keys方法,返回一个类数组

    var o = {

    name : ‘a’,

    age : 12

    }

    Object.keys(o) //[‘name’,’age’]

  • 删除属性

    • delete运算符只能删除自有属性,不能删除继承属性。

    • 删除一个不存在的属性,delete不报错,而且返回true。
    • 只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除。

  • 检测属性是否存在于某个对象中

    • 用“!==”来判断一个属性是否是undefined(无法判断属性是否是继承来的)

    • hasOwnPreperty()方法:检测的是自身属性,无关继承来的属性
    • propertyIsEnumerable()方法:只有检测到自有属性且这个属性的可枚举性为true时才返回true
    • in元素符左侧属性名(字符串),右侧是对象。如果对象的自有属性或继承属性中包含这个属性就返回true(无法判断属性是否是继承来的)

  • 对象的三大属性

    • 每个对象都有与之相关的原型(prototype),类(class)和可扩展性(extensible attribute)
    • 将对象作为参数传入Object.getPrototypeOf()可以查询他的原型
    • 检测一个对象是否是另一个对象的原型,可使用isPrototypeOf()方法
  • 序列化对象

    • 对象序列化是指将对象的状态转换为字符串,也可将字符串还原为对象

    • 在js中,提供内置函数JSON.stringify()和JSON.parse()用来序列化和还原js对象

    • NaN,Infinity和-Infinity序列化的结果是null

      var o = {

      name : ‘a’,

      age : 12,

      intro : [false,null,’’]

      }

      s= JSON.stringify(o) // s {“name”:”a”,”age”:12,”intro”:[false,null,””]}

      p=JSON.parse(s) // p是o的深拷贝

    • JSON.stringify()只能序列化对象可枚举的自有属性,对于一个不能序列化的属性来说,在序列化后的输出字符串中会将这个属性省略掉

    • 深拷贝与浅拷贝的区别

      • 浅拷贝只是复制了对象的地址,两个对象指向同一个地址,所以修改其中的值,另一个值都会随之改变

      • 深拷贝是将对象及值复制过来,两个对象修改其中任意值,另一个值不会随之改变,这就是深拷贝(如:JSON.stringify()和JSON.parse(),但是此方法无法复制函数数据类型)

      • 当你需要深拷贝对象中的方法时可使用lodash.js(提高js原生方法性能的js库)中的cloneDeep()方法

        var objA = { “name”: “戈德斯文” };

        var objB =lodash.cloneDeep(objA);

      • 深拷贝首推的方法简单有效,JSON.stringfy()和JSON.parse()即可搞定。但是这种简单粗暴的方法有其局限性。当值为undefinedfunctionsymbol 会在转换过程中被忽略。所以,对象值有这三种的话用这种方法会导致属性丢失。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        var syb = Symbol('obj');
        var person = {
        name :'tino',
        say: function(){
        console.log('hi');
        },
        ok: syb,
        un: undefined
        }
        var copy = JSON.parse(JSON.stringify(person))
        // copy
        // {name: "tino"}
  • js中对象的可枚举属性和不可枚举属性是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for….in查找遍历到

    • js中的基本包装类的原型属性是不可枚举的,如Object,Array,Number,这些对象的内置属性是不可枚举的
    • 需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false。
  • 构造函数是用来生成“对象”的函数。一个构造函数可生成多个对象,这些对象都有相同的结构

    • 构造函数的特点:函数体内使用this关键字代表所要生成的对象实例。生成对象时,必须用new命令,构造函数名字的首字母通常大写

    • new命令本身就可以执行构造函数,所以后面的构造函数可带括号可不带

      var c = new Car();

      var c = new Car;

    • 每一个构造函数都有prototype属性

事件机制

事件机制之冒泡、传播、委托

DOM事件流(event flow)存在三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段

事件捕获阶段(event capuring)

通俗理解就是,当鼠标点击或触发dom事件时,浏览器会从根节点由外往内进行事件传播,即点击了子元素,如果父元素通过事件捕获注册了对应的事件的话,会先触发父元素绑定的的事件。

事件冒泡(dubbed bubbling)

与事件捕获相反,事件冒泡是从目标元素由内往外进行事件传播,直到根节点。

无论是事件冒泡还是事件捕获,都有一个共同点就是事件传播,她就像一根引线,只有通过引线才能将绑在引线上的鞭炮(事件监听器)引爆,试想一下,如果引线不导火了,那鞭炮就只有一响了!

dom事件标准事件流的触发先后顺序是:先捕获后冒泡,即当触发dom事件时,会进行事件捕获,捕获到事件源后通过事件传播进行事件冒泡。不同浏览器对此有不同的实现,IE10及以下不支持捕获型事件,所以就少了一个时间捕获阶段,IE11,Chrome,Firefox,Safari等浏览器则同时存在。

事件绑定的方法

addEventlistener(event,listener,useCapture)

参数定义:event——(事件名称:如click,不带on)

listener——事件监听函数,

useCapture——是否采用事件捕获进行事件捕获,默认为false,即采用事件冒泡方式。

addEventListener在IE11,Chrome,Firefox,Safari等浏览器都得到支持。

attachEvent(event,listener)

参数定义:event—(事件名称,如onclick,带on),

listener—事件监听函数。

attachEvent主要用于IE浏览器,并且仅在IE10及以下才支持,IE11已经废了这个方法了

事件冒泡例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
#parent{width:200px;height:200px;background:yellow;margin:10px auto;border:1px solid black;}
#children{width:50px;height:50px;background:pink;margin:80px auto;}
</style>
<title>Document</title>
</head>
<body>
<div id="parent">
<div id="children"></div>
</div>
</body>
</html>
<script>
var children = document.getElementById('children');
var parent = document.getElementById('parent');
document.body.addEventListener('click',function(){console.log('body')},false);
parent.addEventListener('click',function(){console.log('parent')},false);
children.addEventListener('click',function(){console.log('children');
//event.stopProparation;
//可停止事件传播},false);
</script>

当点击子盒子时,打印结果依次为children——parent——body

事件触发的顺序是由内到外的,这就是事件冒泡,虽然只点击了子元素,但是他的父元素也会触发相应的事件,其实这也是合理的,因为父元素里面,点击了子元素不就相当于变相的点击了父元素。

若不想触发父元素可停止事件传播只需在子元素中添加event.stopProparation;即可。

事件捕获例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
body{background: green;}
#parent{width:200px;height:200px;background:yellow;margin:10px auto;border:1px solid black;}
#children{width:50px;height:50px;background:pink;margin:80px auto;}
</style>
<title>Document</title>
</head>
<body>
<div id="parent">
<div id="children"></div>
</div>
</body>
</html>
<script>
var children = document.getElementById('children');
var parent = document.getElementById('parent');
document.body.addEventListener('click',function(){console.log('body')},true);
parent.addEventListener('click',function(){console.log('parent')},true);
children.addEventListener('click',function(){console.log('children')},true);
</script>

点击children方块,打印body——parent——childre

点击parent方块,打印body——parent

点击body区域,打印body

事件通过事件捕获的方式注册了click事件,所以在事件捕获阶段就会触发,先是触发最外围注册了事件捕获的body,而后触发事件捕获的parent,最后触发事件源。这就是事件的时间流程。

要求

高质量代码

  • bug暴露
  • 不扩展内置原型,多用this取代构造函数的prototype
  • 使用switch模式增强可读性和健壮性
  • 使用绝对相等或绝对不等,避免隐式类型转换
  • 避免使用eval(),因此方法接受任意的字符串,被执行的代码可能被篡改,有极大的安全隐患。且会污染全局变量
  • 用方括号表示法访问动态属性
  • parseInt()下数值转换,最好指定基数参数,不然,可能以0开头的数据被当成8进制使用

提高性能

(类)数组循环获取值时缓存长度
  • 不足:每次循环时数组的长度都要去获取,会降低代码
  • 若是类数组,需实时查询基本文档(html页面),这意味着每次你访问任何集合的长度,你要实时查询DOM,而DOM操作一般都是比较昂贵的。
  • 解决:把数组长度放在一个变量里;从后往下标为0的数数,因为和0做比较要比和数组长度或是其他不是0的东西作比较更有效率。
for循环遍历数组,for-in循环遍历类数组
遍历属性时使用hasOwnProperty()方法过滤原型上的属性

var的作用

优点
  • 避免创建隐式全局变量:1.函数中未声明就使用变量 2.使用任务链进行部分var声明
  • 可移植性:可在不同主机上使用
缺点
  • 通过var创建的全局变量不可通过delete删除,无var创建的隐式全局变量(并非真正的全局变量,只是全局变量的属性)可通过delete删除

执行层面

代码处理的两个阶段(预解析hoisting)
  • 变量,函数声明,以及正常格式的参数创建,这是一个解析和进入上下文的阶段
  • 代码执行,函数表达式和不合格的标识符(为声明的变量)被创建。

二 . JavaScript对象

  • JavaScript是一种直译式脚本语言,是一种动态类型,弱类型,基于原型的语言,内置支持类型

  • 日常用途
    1. 嵌入动态文本于HTML页面。
    2. 对浏览器事件做出响应。
    3. 读写HTML元素
    4. 在数据被提交到服务器之前验证数据。
    5. 检测访客的浏览器信息。
    6. 控制cookies,包括创建和修改等。
    7. 基于Node.js技术进行服务器端编程。

对象公共属性

1.constructor属性
  • constructor属性返回对创建此对象的函数的引用
  • 函数对象。 返回创建布尔对象的函数原型。=函数.constructor;
2.prototype属性
  • 是您有能力向对象添加属性和方法
  • 当构造一个原型,所有的对应对象默认都添加了属性和方法
  • 每个js对象(除了null)都和另一个对象相关联,即继承另一个对象。另一个对象就是我们熟知的“原型(prototype),每个对象都从原型继承属性。只有null除外,他没有自己的原型对象
  • 通过Object.prototype获得对原型对象的引用,通过对象或构造函数调用创建的对象的原型就是构造函数的prototype属性的值,找不到原型,返回undefined
3.toString()把对象转为字符串并返回结果
  • String=对象.toString()
4.valueOf() 返回对象的原始值

Array=array.valueOf() 不会改变原数组

5.Object.getPrototypeOf()
  • 返回一个对象的原型
6.Object.setPrototypeOf()
  • 为现有对象设置原型,返回一个新对象
  • 接受两个参数,第一个是现有对象,第二个是原型对象
7.Object.create()
  • 用于从原型对象生成新的实例对象,可以替代new命令
  • 它接受一个对象作为参数,返回一个新的对象,后者完全继承前者的属性,即原有对象成为新对象的原型
8.Object.prototype.isPrototypeOf()
  • 判断一个对象是否是另一个对象的原型
  • Object.prototype.isPrototypeOf({}) //true
9.Object.prototype.proto_

_proto__属性(前后各两个下划线)可以改写某个对象的原型对象

10.Object.getPropertyOfNames()
  • 该方法返回一个数组,成员是对象本身的所有属性的键名,不包含的属性键名
11.Object.prototype.hasOwnProperty()
  • 返回一个布尔值,用于判断某个属性定义在对象本身还是在原型链上

1.Array数组对象

  • 数组对象的作用是使用单独的变量名来存储一系列的值
  • length属性是可写的。如果人为设置一个小于当前成员个数的值,该数组的成员会自动减少到length设置的值。
1.concat()连接两个或多个数组
  • 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本
  • array1.concat(array2,array3,…,arrayX)
2.every()检查所有数组元素,返回boolear
  • 用于检测数组所有元素是否都符合指定条件(通过函数提供),只有所有元素都满足条件才返回true

  • every()不会对空数组进行检测,且不会改变原始数组

  • array.every(function(currentValue,index,arr),thisValue)

    参数 描述
    function(currentValue, index,arr) 必须。函数,数组中的每个元素都会执行这个函数 函数参数: 参数描述currentValue必须。当前元素的值index可选。当期元素的索引值arr可选。当期元素属于的数组对象
    thisValue 可选。对象作为该执行回调时使用,传递给函数,用作 “this” 的值。 如果省略了 thisValue ,”this” 的值为 “undefined”
3.filter()创建所有符合条件元素的数组
  • 创建一个新数组,不会对空数据进行检测,也不会改变原始数组.如果没有符合条件的元素则返回空数组。
  • array.filter(function(currentValue,index,arr),thisValue)
4.indexOf()返回指定字符串值首次出现的位置
  • array.indexOf(item,start)
参数 描述
item 必须。查找的元素。
start 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。
  • 返回值为number值,如果没有搜索到则返回-1
  • lastIndexOf() 查找字符串最后出现的位置
5.join() 把数组中的所有元素为一个字符串
  • 元素是通过指定的分隔符进行分隔的

  • string =array.join(separator)

    参数separator是可选的,是指定要使用的分隔符,若省略,默认使用逗号

    返回值是一字符串。该字符串是通过把arrayObject的每个元素转换为字符串,然后把这些字符串连接起来,在两个元素之间插入separator字符串生成

6.map()通过指定函数处理原始数组,并返回处理后的数组
  • map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。map() 方法按照原始数组元素顺序依次处理元素。
  • map() 不会对空数组进行检测。map() 不会改变原始数组。
  • array.map(function(currentValue,index,arr),thisValue)
7.pop()删除数组最后一个元素并返回处理后的数组
  • array.pop();
  • array.shift();删除数组的第一个元素
8.push()向数组的末尾添加一个或更多元素,并返回新的长度
  • Number =array.push(item1,item2,…,itemX);
  • array.unshift(item1,item2,…,itemX)) ; 向数组的开头添加一个或多个元素,并返回新的长度
9.reverse()颠倒数组中元素的顺序
  • 不影响原数组
  • Array=array.reverse();
10.slice()选取数组中的一部分,并返回一个新数组
  • 新数组中不包括end对应的值

  • Array=array.slice(start,end);

参数 描述
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
11.some()检测数组元素中是否有元素符合指定条件
  • some() 方法会依次执行数组的每个元素:如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。如果没有满足条件的元素,则返回false。
  • Boolean =array.some(function(currentValue,index,arr),thisValue);
12.sort()对数组的元素进行排序
  • 排序顺序可以是字符或数字,并按升序或降序。默认按字母升序。 这种方法会改变原始数组!

  • 注意:当数字是按字母顺序排列时”40”将排在”5”前面。使用数字排序,你必须通过一个函数作为参数来调用。函数指定数字是按照升序还是降序排列。

  • Array =array.sort(sortfunction);

    参数sortfunction可选,规定排定顺序,必须是函数

    返回值Array是对原数组的引用。注意,数组在原数组进行排序,不生成副本

13.splice()从数组中添加或删除,替换元素
  • 改变原数组

  • Array =array.splice(index,howmany,item1,item2,…,itemsX);

    参数index是必须的,规定从何处添加或删除元素,该参数是开始插入或删除的数组元素的下标,必须是数字

    howmany是必填项,规定应该删除多少元素,若未规定,则默认从index开始删除直到原数组结尾的所有元素

    item1,可选,要添加到数组的新元素

14.toString()把数组转为字符串并返回结果
  • 数组元素之间用逗号分隔
  • String=array.toString()
15.valueOf() 返回数组对象的原始值

Array=array.valueOf() 不会改变原数组

16.reduce()返回累计值
  • 定义:对数组中的每个元素执行一个自定义的累计器,将其结果汇总为单个返回值
  • 形式:array.reduce((t, v, i, a) => {}, initValue)
  • 参数
    • callback:回调函数(必选)
    • initValue:初始值(可选)
  • 回调函数的参数
    • total(t):累计器完成计算的返回值(必选)
    • value(v):当前元素(必选)
    • index(i):当前元素的索引(可选)
    • array(a):当前元素所属的数组对象(可选)
  • 过程
    • t作为累计结果的初始值,不设置t则以数组第一个元素为初始值
    • 开始遍历,使用累计器处理v,将v的映射结果累计到t上,结束此次循环,返回t
    • 进入下一次循环,重复上述操作,直至数组最后一个元素
    • 结束遍历,返回最终的t

reduce的精华所在是将累计器逐个作用于数组成员上,把上一次输出的值作为下一次输入的值

2.Boolean对象

  • Boolean 对象用于转换一个不是 Boolean 类型的值转换为 Boolean 类型值 (true 或者false).

3.Date对象

  • 四种创建方法
    • var d =new Date();
    • var d =new Date(milliseconds);
    • var d =new Date(dateString);
    • var d =new Date(year, month, day, hours, minutes, seconds, milliseconds);

4.Number对象

  • Number对象是原始数值的包装对象

    属性 描述
    constructor 返回对创建此对象的 Number 函数的引用。
    MAX_VALUE 可表示的最大的数。
    MIN_VALUE 可表示的最小的数。
    NEGATIVE_INFINITY 负无穷大,溢出时返回该值。
    NaN 非数字值。
    POSITIVE_INFINITY 正无穷大,溢出时返回该值。
    prototype 允许您有能力向对象添加属性和方法。
    方法 描述
    toExponential(x) 把对象的值转换为指数计数法。
    toFixed(x) 把数字转换为字符串,结果的小数点后有指定位数的数字。
    toPrecision(x) 把数字格式化为指定的长度。
    toString() 把数字转换为字符串,使用指定的基数。
    valueOf() 返回一个 Number 对象的基本数字值。

三 . 深入理解js

1.最小全局变量(Minimizing Globals)

  • js通过函数管理作用域。在函数内部声明的变量只在这个函数内部,函数外面不能使用。另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单实用的

  • 每个js环境都有一个全局对象,但你在任意函数外面使用this就可以访问到。你创建的每一个全局变量都是这个全局对象的属性。在浏览器中,为方便起见,该全局对象有个附加属性叫做window,此window指向该全局对象本身

  • 全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。

    • 第三方的JavaScript库
    • 广告方的脚本代码
    • 第三方用户跟踪和分析脚本代码
    • 不同类型的小组件,标志和按钮
  • 要想和其他脚本成为好邻居的话,尽可能少的使用全局变量是很重要的。一些减少全局变量的策略,例如命名空间模式或是函数立即自动执行,但是要想让全局变量少最重要的还是始终使用var来声明变量。

  • js因其特征,会不自觉地创建出全局变量。隐式创建全局变量的情况

    • 你可以不声明就可以使用变量,js会默认是全局对象的属性(js有隐含的全局概念)

    • 使用任务链进行var声明 在函数内部 var a=b=0;

      其中a是本地变量,而b是全局变量,因为这个是从右到左的赋值,首先通过赋值表达式b=0,此情况下b是未声明的。这个表达式的值是0,然后这个0就分配给通过var定义的全局变量a。若你提前声明了变量,使用链分配是比较好的,不会产生意料之外的情况

  • 另外一个避免全局变量的原因是可移植性,如果你想你的代码在不同环境(主机下)运行,使用全局变量如履薄冰,因为你会无意中覆盖你最初环境下不存在的主机对象(所以你原以为名称可以放心使用,实际上对于有些情况并不适用)

  • 忘记var的副作用(Side Effect when forgetting var)
    • 隐式全局变量和明确全局变量有小差异,即通过delete操作符让变量未定义的能力。
      • 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的
      • 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的
    • 这表明,在技术上,隐式全局变量并不是真正的全局变量,但他们是全局对象的属性。属性是可以通过delete操作符删除的,而变量不能

// 定义三个全局变量
var global_var = 1;
global_novar = 2; // 反面教材
(function () {
global_fromfunc = 3; // 反面教材
}());
// 试图删除
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// 测试该删除
typeof global_var; // “number”
typeof global_novar; // “undefined”
typeof global_fromfunc; // “undefined”

  • 访问全局对象(Access to the Global Object)

    在浏览器中,全局对象可以通过window属性在代码的任何位置访问(除非你做了些比较出格的事情,像是声明了一个名为window的局部变量)。但是在其他环境下,这个方便的属性可能被叫做其他什么东西(甚至在程序中不可用)。如果你需要在没有硬编码的window标识符下访问全局对象,你可以在任何层级的函数作用域中做如下操作:

var global=(function(){

return this;

}()); 这种方法可随时获得全局对象,因其在函数中被当作一个函数调用了(不是通过new构造),this总是指向全局对象。实际上这个病不适用于ECMAScript 5严格模式,所以,在严格模式下时,你必须采取不同的形式。例如,你正在开发一个JavaScript库,你可以将你的代码包裹在一个即时函数中,然后从 全局作用域中,传递一个引用指向this作为你即时函数的参数。

  • 单var形式(Single var Pattern)

    在函数顶部使用单var语句是比较有用的一种形式,其好处在于:

    • 提供了一个单一的地方去寻找功能所需要的所有局部变量
    • 防止变量在定义之前使用的逻辑错误
    • 帮助你记住声明的全局变量,因此较少了全局变量
    • 少代码(类型啊传值啊单线完成)
  • 预解析:var散布的问题(Hoisting: A Problem with Scattered vars)

    JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。对于JavaScript,只 要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。

    // 反例
    myname = “global”; // 全局变量
    function func() {
    alert(myname); // “undefined”
    var myname = “local”;
    alert(myname); // “local”
    }
    func();

2.代码处理的两个阶段

  • 第一阶段是变量,函数声明,以及正常格式的参数创建,这是一个解析和进入上下文的阶段
  • 第二阶段是代码执行,函数表达式和不合格的标识符(未声明的变量)被创建

四 . this 精讲

谁调用这个函数或方法,this关键字就指向谁

  • this总是返回属性或方法“当前”所在的对象
  • 如果一个函数在全局环境中运行,那么this就是指顶层对象(浏览器中为window对象)。

1.改变this指向的三大方法

1.call、apply、bind方法的共同点和区别:
  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

  • apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文(函数的每次调用都会拥有一个特殊值——本次调用的上下文(context)——这就是this关键字的值。);

  • apply 、 call 、bind 三者都可以利用后续参数传参;

  • bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

2.thisObj的取值有以下4种情况:

(1) 不传,或者传null,undefined, 函数中的this指向window对象

(2) 传递另一个函数的函数名,函数中的this指向这个函数的引用

(3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean

(4) 传递一个对象,函数中的this指向这个对象

  • function.prototype.call(obj,arg1,arg2,…)
    • obj是this要指向的对象(一般会写成this),也就是想指定的上下文;arg1,arg2都是要传入的参数
    • 如果参数为空,null和undefined,则默认传入全局对象
  • function.prototype.apply(obj,[arg1,arg2,..])
    • apply()和call()差不多,但是apply的第二个参数是数组
  • function.prototype.bind(obj)
    • 将函数绑定到某个对象,然后返回一个新的函数
3.实例
1
2
3
4
5
6
7
8
9
10
11
function a(){     console.log(this);   //输出函数a中的this对象}       
function b(){}
var c={name:"call"}; //定义对象c
a.call(); //window
a.call(null); //window
a.call(undefined); //window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b); //function b(){}
a.call(c); //Object

function class1(){

this.name=function(){

​ console.log(“我是class1内的方法”);

}

}

function class2(){

class1.call(this); //此行代码执行后,当前的this指向了class1(也可以说class2继承了class1)

}

var f=new class2();

f.name(); //调用的是class1内的方法,将class1的name方法交给class2使用

function eat(x,y){

console.log(x+y);

}

function drink(x,y){

console.log(x-y);

}

eat.call(drink,3,2);/输出:5。这个例子中的意思就是用 eat 来替换 drink,eat.call(drink,3,2) == eat(3,2) ,所以运行结果为:console.log(5);/

function Animal(){

this.name=”animal”;

this.showName=function(){

​ console.log(this.name);

}

}

function Dog(){

this.name=”dog”;

}

var animal=new Animal();

var dog=new Dog();

animal.showName.call(dog);//输出:dog

在上面的代码中,我们可以看到Dog里并没有showName方法,那为什么(this.name)的值是dog呢?

关键就在于最后一段代码(animal.showName.call(dog)),意思是把animal的方法放到dog上执行,也可以说,把animal 的showName()方法放到 dog上来执行,所以this.name 应该是 dog。

function Animal(name){

this.name=name;

this.showName=function(){

​ console.log(this.name);

}

}

function Dog(name){

Animal.call(this,name);

}

var dog=new Dog(“Crazy dog”);

dog.showName();//输出:Crazy dog

Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么Dog就能直接调用Animal的所有属性和方法。著作权归作者所有。

  • 在JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call ;而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。著作权归作者所有。

详情请看:http://ghmagical.com/article/page/id/UPLfoGI9vJ91

五 . 垃圾回收机制

  • js具有自动垃圾回收机制(GC:Garbage Collection),也就是说执行环境会负责管理代码执行过程中使用的内存
  • 原理:垃圾收集器会定期(周期性)找出那些不再继续使用的变量,然后释放其内存。此过程并非实时的,因其开销会很大。
  • 不再使用的变量也就是生命周期结束的变量,当让只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束,局部变量只在函数执行过程中存在,而在这个过程会为局部变量在堆和栈分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束,而闭包由于内部函数的原因,外部函数并不能算是结束。

六. 枚举

ECMAScript原始值和引用值

1.原始值

存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。

2.引用值

存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。

为变量赋值时,ECMAScript 的解释程序必须判断该值是原始类型,还是引用类型。要实现这一点,解释程序则需尝试判断该值是否为 ECMAScript 的原始类型之一,即 Undefined、Null、Boolean、Number和String型。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。

在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。ECMAScript打破了这一传统。

如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响

存储在堆和栈中的原始值和引用值

3.对象

1.属性
  • constructor:对创建对象的函数的引用(指针)。对于Object对象,该指针指向原始的Object()函数
  • prototype:对该对象的原型的引用。对于所有的对象,他默认返回Object对象的一个实例
2.方法
  • hasOwnProperty(property):判断对象是否有某个特定的属性。必须用字符串指定该属性(o.hasOwnProperty(“name”))
  • IsPrototypeOf(object):判断该对象是否为另一个对象的原型
  • PropertyIsEnumerable:判断给定的属性是否可以用for…in语句进行枚举
  • ToString():返回对象的原始字符串表示。对于Object对象,ECMA-262没有定义这个值,所以不同的ECMAScript实现具有不同的值
  • ValueOf()返回最适合该对象的原始值。对于许多对象,该方法返回的值都与ToString()的返回值相同
  • 上面列出的每种属性和方法都会被其他对象覆盖

4.String对象

  • localeCompare()方法,对字符串进行排序。该方法有一个参数-要进行比较的字符串,返回的是下列三个值之一

    • 如果String对象按照字母顺序排在参数中的字符串之前,返回负数
    • 等于参数中的字符串,返回0
    • 排在参数中的字符串之后,返回正数
  • localeCompare()方法的独特之处在于,实现所处的区域(locale,兼指国家/地区和语言)确切说明了这种方法运行的方式。在美国,英语是ECMAScript实现的标准语言,localeCompare()是区分大小写的,大写字母在字母顺序上排在小写字母之后。不过,在其他区域,情况可能并非如此。

  • slice()和substring()

    • ECMAScript提供了两种方法从字串创建字符串值,即slice()和substring()。这两种返回的都是要处理的字符串的子串,都接受一个或两个参数,第一个参数是要获取字串的起始位置,第二个参数(如果使用的话)是要获取子串终止前的位置(也就是说,获取终止位置不包括在返回值内)。若省略第二个参数,终值位就默认为字符串的长度。但是两种方法都不影响String对象本身的值

    • 对于负数参数,slice()方法会用字符串的长度加上参数,substring()方法则将其作为0处理(也就是忽略他)

      var oStringObject = new String(“hello world”);
      alert(oStringObject.slice(“-3”)); //输出 “rld”
      alert(oStringObject.substring(“-3”)); //输出 “hello world”
      alert(oStringObject.slice(“3, -4”)); //输出 “lo w”
      alert(oStringObject.substring(“3, -4”)); //输出 “hel”

      substring()方法则将两个参数解释为substring(3, 0),实际上即substring(0, 3),因为substring()总把较小的数字作为起始位,较大的数字作为终止位。因此,substring(“3, -4”)返回的是”hel”。

  • toLowerCase()和toUpperCase()方法是原始的,是以java.lang.String中相同方法为原型实现的。

    toLocaleLowerCase()和toLocaleUpperCase()方法是基于特定的区域实现的

    • 一般来说,如果不知道在以哪种编码运行一种语言,则使用区域特定的方法比较安全。
    • String对象的所有属性和方法都可应用于String原始值上,因为它们是伪对象。
  • instanceof运算符

    • 解决使用typeof运算符时,所有类型的对象都返回“object”

5.整数

  • ECMAScript中,所有整数字面量默认都是有符号32位整数,前31位(每一位都表示2的幂)是整数数值,最后一位表示符号,0表示正数,1表示负数

  • 负整数:负数也存储为二进制代码,不过采用的形式是二进制补码。计算补码三部曲:

    • 确定该数字的非负版本的二进制表示(如,要计算-18的二进制补码,首先要确定18的二进制表示)
    • 求得二进制反码,即把0替换成1,把1替换成0
    • 在二进制反码上加上1
  • 位运算NOT(~)三部曲

    • 把运算数转化成32位数字

    • 把二进制转换成他的二进制反码

    • 把二进制数转化成浮点数

      位运算NOT实质上是对数字求负,然后减1,因此25变成-26

    • 如果运算数是对象,返回false

    • 如果运算数是数字0,返回true

    • 如果运算数是0以外的任何数字,返回false

    • 如果运算数是null,返回true

    • 如果运算数是NaN,返回true

    • 如果运算数是undefined,发生错误。

  • AND运算符的运算数可以是任何类型的

    • obj && boolean ——–obj
    • obj1 && obj2 ———obj2
    • 有null ———–null
    • 有NaN ——返回NaN
    • 第一个是undefined或第一个是true,第二个是undefined——发生错误
    • 第一个是false,第二个是undefined——返回false,因为第二个没被计算
  • 乘法运算符*

    • 如果某个运算数是NaN,结果就是NaN
    • Infinity乘以0,结果是NaN
    • Infinity乘以0以外的数,结果为Infinity或-Infinity
  • 除法运算符/

    • 如果结果太大或太小,生成的结果是Infinity或-infinity
    • 如果某个运算数是NaN,结果是NaN
    • Infinity被Infinity除,结果是NaN。Infinity/Infinity=NaN
    • Infinity被任何数字除,结果是Infinity 某个数/Infinity=Infinity
    • 0除以一个非无穷大的数字,结果为NaN 0/某个数=NaN
  • 取余%

    • Infinity%某数=NaN 某数%0=NaN
    • Infinity%Infinity=NaN
    • 被除数%Infinity=被除数
    • 0%某数=0
  • 加法+

    • 某个运算数是NaN,结果为NaN
    • (-Infinity)+(-Infinity)= -Infinity
    • Infinity + (-Infinity)=NaN
    • (+0)+(+0)=(+0)
    • (-0)+(+0)=(+0)
    • (-0)-(-0)=(-0)
    • (-0)+(-0)=(-0)
    • 如果两个运算数都是字符串,把第二个字符串连接到第一个上。
    • 如果只有一个运算数是字符串,把另一个运算数转换成字符串,结果是两个字符串连接成的字符串。
  • 等性运算符==和!=

    • 如果一个运算数是Boolean值,在检查相等性之前,把它转换成数字值,true为1,false为0

    • 字符串和数字,将字符串转成数字

    • 对象和字符串,将对象转为字符串

    • 对象和数字,将对象转成数字

    • 值null和undefined相等

    • 在检查相等性时,不能把null和undefined转换成其他值

    • 有NaN,等号返回false,非等号返回true

    • 如果两个运算数是对象,那比较的是他们的引用值,若指向同一对象,则等号返回true,否则两个运算数不等

      表达式
      null == undefined true
      “NaN” == NaN false
      5 == NaN false
      NaN == NaN false
      NaN != NaN true
      false == 0 true
      true == 1 true
      true == 2 false
      undefined == 0 false
      null == 0 false
      “5” == 5 true

6.语句

1.有标签的语句
  • break 语句和 continue 语句都可以与有标签的语句联合使用,返回代码中的特定位置。当循环内部还有循环时,会这样做
  • with语句用于设置代码在特定对象中的作用域

var sMessage = “hello”;
with(sMessage) {
alert(toUpperCase()); //输出 “HELLO”
}

(1)在这个例子中,with语句用于字符串,所以调用toUpperCase()方法时,解释程序将检查该方法是否是本地程序。如果不是,他将检查伪对象sMessage,看他是否为该对象的方法,然后,alert输出“HELLO”,因为解释程序找到了字符串”hello“的toUpperCase()方法

(2)with语句是运行缓慢的代码块,尤其是在已设置了属性值时。大多情况下,如果可能,最好避免使用它

七. 面向对象

1.具备的四种能力

  • 封装:把相关信息(数据或方法)存储在对象中的能力
  • 聚集:把一个对象存储在另一个对象内的能力
  • 继承:有另一个类(或多个类)得来类的属性和方法的能力
  • 多态:编写能以多种方法运行的函数或方法的能力

2.对象的应用

  • 对象的创建和销毁都在js执行过程中发生

3.对象废除

  • ECNAScript拥有无用存储单元搜集程序(garbage collection routine),意味着不必专门销毁对象来释放内存。当没有对象引用时,称该对象被废除了(derefence)。运行无用存储单元收集程序时,所有废除的对象都被销毁。每当执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些不可预知的情况下,无用存储单元收集程序也会运行
  • 把对象的所有引用都设置为null,可以强制性的废除材料

4.绑定

  • 即把对象的接口与对象实例结合起来的方法
  • 早绑定(early binding)是指在实例化对象之前定义它的属性和方法,这样编译器或解释程序就能够提前转换机器代码。在 Java 和 Visual Basic 这样的语言中,有了早绑定,就可以在开发环境中使用 IntelliSense(即给开发者提供对象中属性和方法列表的功能)。ECMAScript 不是强类型语言,所以不支持早绑定。
  • 另一方面,晚绑定(late binding)指的是编译器或解释程序在运行前,不知道对象的类型。使用晚绑定,无需检查对象的类型,只需检查对象是否支持属性和方法即可。ECMAScript 中的所有变量都采用晚绑定方法。这样就允许执行大量的对象操作,而无任何惩罚。

5.作用域

  • 指的是变量的适用范围
  • ECMAScript只有公共作用域,所有对象的作用域都是公共的。由于缺少私有作用域,开发者确定了一个规约,说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线
  • ECMAScript没有静态作用域(静态作用域定义的属性和方法任何时候都能从同一位置访问),但可以为构造函数提供属性和方法,构造函数是函数,函数是对象,对象可以有属性和方法

6.使用动态原型方法类的属性和方法

  • 在构造函数内定义非函数属性,而函数属性则利用原型属性定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");

if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function() {
alert(this.color);
};

Car._initialized = true;
}
}
  • 知道检查typeof Car.__initialized是否等于“undefined”之前,这个构造函数都为改变。这行代码是动态原型方法中最重要的一部分。如果这个值没定义,构造函数将用原型方法继续定义对象的方法,然后把Car._initialized设置为true,如果这个值定义了,(它的值为true,typeof的值为Boolean),那么就不再创建该方法。简而言之,该方法使用(_initialized)来判断是否已给原型赋予了任何方法,该方法只创建并赋值一次。

7.ECMAScript的字符串

  • ECMAScript的字符串是不可变的,即它们的值是不可变的

var str=”hello”;str += “world”;

创建此段代码的实际步骤(特别耗资源)

  • 创建存储“hello”字符串
  • 创建存储“world”的字符串
  • 创建连接结果的字符串
  • 把str的当前结果复制到结果中
  • 把“world”复制到结果中
  • 更新str,使它指向结果

解决方法是用Array对象存储字符串,然后用join()方法(参数是空字符串)创建最后的字符串(但是不能确切反映出他的意图)

var arr = new Array();
arr[0] = “hello “;
arr[1] = “world”;
var str = arr.join(“”);

实现步骤

  • 创建存储结果的字符串
  • 把每个字符串复制到结果中的合适位置

最好的方法是使用StringBuffer类包装该功能

function StringBuffer(){

this._strings=new Array();

}

StringBuffer.prototype.append=function(str){

this._strings.push(str);

};

StringBuffer.prototype.toString=function(){

return this._strings.join(“”);

};

这段代码首先要注意的是strings属性,本意是私有属性。它只有两个方法,append()和toString()方法。append()方法只有一个参数,他把该参数附加到字符串数组中,toString()方法调用数组的join方法,返回真正连接成的字符串。

var buffer = new StringBuffer ();
buffer.append(“hello “);
buffer.append(“world”);
var result = buffer.toString();

八 . 继承机制实现

  • 要用ECMAScript实现继承机制,您可以从要继承的基类入手。所有开发者定义的类都可以作为基类。出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可被用于恶意攻击

  • 选定基类后,就可以创建它的子类了。是否使用基类完全由你决定。有时,你可能创建一个不能直接使用的基类,他只是用于给函数提供通用函数。这种情况下,基类被看成是抽象类。

  • 创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有的属性和方法都是公用的,因此子类可以直接访问这些方法。子类还可以添加超类中没有的属性和方法,也可以覆盖超类中的属性和方法

  • JavaScript实现继承并非明确规定,而是通过模仿实现的,故和其他功能一样,不止一种实现方式。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适合的继承方法

1.对象冒充

原理:构造函数使用this关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可以使ClassA构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。

function ClassA(scolor){

this.color=scolor;

this.sayColor=function(){

alert(this.color);}

}

function ClassB(scolor){

this.newMethod=ClassA; this.newMethod(scolor); delete this.newMethod;

this.name = sName;
this.sayName = function () {
alert(this.name);
};

}

在这段段代码中,为ClassA赋予方法newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是ClassB构造函数,第三行行删除对ClassA的引用,这样以后就不能再调用它了。所有新属性或新方法都必须在删除了新方法的代码行后才能执行。否则,可能会覆盖超类的相关方法和属性。

  • 对象冒充可以实现多重继承,即一个类可继承多个超类

继承机制 UML 图示实例

function ClassZ() {
this.newMethod = ClassX;
this.newMethod();
delete this.newMethod;
this.newMethod = ClassY;
this.newMethod();
delete this.newMethod;
}

这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

2.使用call(对象参数,形参1,2,..)

3.使用apply(对象参数,形参数组)

九.object对象

  • JavaScript 原生提供Object对象(注意起首的O是大写),所有其他对象都继承自这个对象。Object本身也是一个构造函数,可以直接通过它来生成新对象。

    var obj = new Object();

  • Object作为构造函数使用时,可接受一个参数。如果该参数是一个对象,则直接返回这个对象;如果是原始类型的值,则返回该值的包装对象。注意,通过new Object()的写法生成新对象,与字面量的写法o = {}是等价的。

    var o1 = {a: 1};
    var o2 = new Object(o1);
    o1 === o2 // true
    new Object(123) instanceof Number
    // true

Object对象上面部署一个方法的两种做法。

1.部署在Object对象本身

比如,在Object对象上面定义一个print方法,显示其他对象的内容。

Object.print = function (o) { console.log(o) } ;

var o =new Object() ;

Object.print(o);

2.部署在Object.prototype对象
  • 所有构造函数都有一个prototype属性,指向一个原型对象。凡是在Object.prototype对象上面定义的属性都将被所有实例对象所共享

    Object.prototype.print = function () { console.log(this) };

    var o = new Object();

    o.print();

    上面代码在Object.prototype定义了一个print方法,然后生成一个Object的实例o。o直接继承了Object.prototype的属性和方法,可以在自身调用它们,也就是说,o对象的print方法实质上是调用Object.prototype.print方法。。

Object()方法

  • 可将任意值转为对象。这个方法常用于保证某个值一定是对象。如果参数是原始类型的值,Object方法返回对应的包装对象的实例

    Object() instanceof Object // true
    Object(undefined) // 返回一个空对象
    Object(undefined) instanceof Object // true
    Object(null) // 返回一个空对象
    Object(null) instanceof Object // true
    Object(1) // 等同于 new Number(1)
    Object(1) instanceof Object // true
    Object(1) instanceof Number // true
    Object(‘foo’) // 等同于 new String(‘foo’)
    Object(‘foo’) instanceof Object // true
    Object(‘foo’) instanceof String // true
    Object(true) // 等同于 new Boolean(true)
    Object(true) instanceof Object // true
    Object(true) instanceof Boolean // true

  • 如果参数是一个对象,他总是返回原对象

    var arr = [];
    Object(arr) // 返回原数组
    Object(arr) === arr // true
    var obj = {};
    Object(obj) // 返回原对象
    Object(obj) === obj // true
    var fn = function () {};
    Object(fn) // 返回原函数
    Object(fn) === fn // true

    利用这一点,可以写一个判断变量是否为对象的函数。

    function isObject(value) {
    return value === Object(value);
    }
    isObject([]) // true
    isObject(true) // false

Object对象的静态方法

  • 是指部署在Object对象自身的方法

  • Object.keys方法和Object.getOwnPropertyNames方法很相似,一般用来遍历对象的属性。它们的参数都是一个对象,都返回一个数组,该数组的成员都是对象自身的(而不是继承的)所有属性名。它们的区别在于,Object.keys方法只返回可枚举的属性Object.getOwnPropertyNames`方法还返回不可枚举的属性名。

    var o = {
    p1: 123,
    p2: 456
    };
    Object.keys(o)
    // [“p1”, “p2”]
    Object.getOwnPropertyNames(o)
    // [“p1”, “p2”]

    有不可枚举属性length

    var a = [“Hello”, “World”];
    Object.keys(a)
    // [“0”, “1”]
    Object.getOwnPropertyNames(a)
    // [“0”, “1”, “length”]

  • 由于JavaScript没有提供计算对象属性个数的方法,所以可以用这两个方法代替。

    Object.keys(o).length

    Object.getOwnPropertyNames(o).length

    一般情况下,几乎总是使用Object.keys方法遍历数组的属性

对象属性模型的相关方法

  • Object.getOwnPropertyDescriptor():获取某个属性的attributes对象。
  • Object.defineProperty():通过attributes对象,定义某个属性。
  • Object.defineProperties():通过attributes对象,定义多个属性。
  • Object.getOwnPropertyNames():返回直接定义在某个对象上面的全部属性的名称。

控制对象状态的方法

  • Object.preventExtensions():防止对象扩展。
  • Object.isExtensible():判断对象是否可扩展。
  • Object.seal():禁止对象配置。
  • Object.isSealed():判断一个对象是否可配置。
  • Object.freeze():冻结一个对象。
  • Object.isFrozen():判断一个对象是否被冻结。

原型链相关方法

  • Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
  • Object.getPrototypeOf():获取对象的Prototype对象。

Object对象都有的六大实例方法

  • valueOf():返回当前对象对应的值

    • valueOf方法的作用是返回一个对象的“值”,默认情况下返回对象本身。

      var o = new Object();
      o.valueOf() === o // true

    • valueOf`方法的主要用途是,JavaScript自动类型转换时会默认调用这个方法

      var o = new Object();
      o.valueOf = function (){
      return 2;
      };
      1 + o // 3

  • toString():返回当前对象对应的字符串形式

    • toString方法的作用是返回一个对象的字符串形式,默认情况下返回类型字符串。

      var o1 = new Object();
      o1.toString() // “[object Object]”
      var o2 = {a:1};
      o2.toString() // “[object Object]”

    • 自动类型转换时

      var o = new Object();
      o.toString = function () {
      return ‘hello’;
      };
      o + ‘ ‘ + ‘world’ // “hello world”

[1, 2, 3].toString() // "1,2,3"
'123'.toString() // "123"
(function () {
return 123;
}).toString()
// "function () {
//   return 123;
// }"
(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
  • 实例对象可能会自定义toString方法,覆盖掉Object.prototype.toString方法。通过函数的call方法,可以在任意值上调用Object.prototype.toString方法,帮助我们判断这个值的类型。

    Object.prototype.toString.call(value)

    不同数据类型的Object.prototype.toString方法返回值如下。

    • 数值:返回[object Number]
    • 字符串:返回[object String]
    • 布尔值:返回[object Boolean]
    • undefined:返回[object Undefined]
    • null:返回[object Null]
    • 数组:返回[object Array]
    • arguments对象:返回[object Arguments]
    • 函数:返回[object Function]
    • Error对象:返回[object Error]
    • Date对象:返回[object Date]
    • RegExp对象:返回[object RegExp]
    • 其他对象:返回[object Object]
  • 也就是说,Object.prototype.toString可以得到一个实例对象的构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    Object.prototype.toString.call(2) // "[object Number]"
    Object.prototype.toString.call('') // "[object String]"
    Object.prototype.toString.call(true) // "[object Boolean]"
    Object.prototype.toString.call(undefined) // "[object Undefined]"
    Object.prototype.toString.call(null) // "[object Null]"
    Object.prototype.toString.call(Math) // "[object Math]"
    Object.prototype.toString.call({}) // "[object Object]"
    Object.prototype.toString.call([]) // "[object Array]"

    利用这个特性,可以写出一个比typeof运算符更准确的类型判断函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var type = function (o){
    var s = Object.prototype.toString.call(o);
    return s.match(/\[object (.*?)\]/)[1].toLowerCase();
    };

    type({}); // "object"
    type([]); // "array"
    type(5); // "number"
    type(null); // "null"
    type(); // "undefined"
    type(/abcd/); // "regex"
    type(new Date()); // "date"

    在上面这个type函数的基础上,还可以加上专门判断某种类型数据的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ['Null',
    'Undefined',
    'Object',
    'Array',
    'String',
    'Number',
    'Boolean',
    'Function',
    'RegExp',
    'NaN',
    'Infinite'
    ].forEach(function (t) {
    type['is' + t] = function (o) {
    return type(o) === t.toLowerCase();
    };
    });

    type.isObject({}) // true
    type.isNumber(NaN) // true
    type.isRegExp(/abc/) // true
  • toLocaleString():返回当前对象对应的本地字符串形式。

  • hasOwnProperty():判断某个属性是否为当前对象自身的属性值还是继承自原型对象的属性

  • isPrototypeOf():判断当前对象是否为另一个对象的原型

  • propertyIsEnumerable():判断某个属性是否可枚举

Array对象

  • Array是JavaScript的内置对象,同时也是一个构造函数,可以用它生成新的数组。

    1
    2
    3
    var arr = new Array(2);
    arr.length // 2
    arr // [ undefined x 2 ]
  • Array构造函数有一个很大的问题,就是不同的参数,会导致它的行为不一致。`因此,不建议使用它生成新数组,直接使用数组字面量是更好的做法。

    // 无参数时,返回一个空数组
    new Array() // []
    // 单个正整数参数,表示返回的新数组的长度
    new Array(1) // [ undefined ]
    new Array(2) // [ undefined x 2 ]
    // 非正整数的数值作为参数,会报错
    new Array(3.2) // RangeError: Invalid array length
    new Array(-3) // RangeError: Invalid array length
    // 单个非正整数参数(比如字符串、布尔值、对象等),
    // 则该参数是返回的新数组的成员
    new Array(‘abc’) // [‘abc’]
    new Array([1]) // [Array[1]]
    // 多参数时,所有参数都是返回的新数组的成员
    new Array(1, 2) // [1, 2]
    new Array(‘a’, ‘b’, ‘c’) // [‘a’, ‘b’, ‘c’]

  • 注意,如果参数是一个正整数,返回数组的成员都是空位。虽然读取的时候返回undefined,但实际上该位置没有任何值。虽然可以取到length属性,但是取不到键名。

    var arr = new Array(3);
    arr.length // 3
    arr[0] // undefined
    arr[1] // undefined
    arr[2] // undefined
    0 in arr // false
    1 in arr // false
    2 in arr // false

  • Array.isArray():判断一个值是否为数组,弥补typeof运算符的不足

1.Array实例的方法
  • valueOf()方法返回数组本身

    var a = [1, 2, 3];
    a.valueOf() // [1, 2, 3]

  • toString()方法返回数组的字符串形式

    var a = [1, 2, 3];
    a.toString() // “1,2,3”
    var a = [1, 2, 3, [4, 5, 6]];
    a.toString() // “1,2,3,4,5,6”

  • push()方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。

    var a = [];
    a.push(1) // 1
    a.push(‘a’) // 2
    a.push(true, {}) // 4
    a // [1, ‘a’, true, {}]

  • 合并两个数组

    var a = [1, 2, 3];
    var b = [4, 5, 6];
    Array.prototype.push.apply(a, b)
    // 或者
    a.push.apply(a, b)
    // 上面两种写法等同于
    a.push(4, 5, 6)
    a // [1, 2, 3, 4, 5, 6]

  • push方法还可用于向对象添加元素,添加后的对象变成类似数组的对象,即新加入元素的键对应数组的索引,并且对象有一个length属性,其中的length属性是指加入键名的个数

    var a= {a:1};

    [].push.call(a,2);

    a //{a:1 ,0:2 , length :1}

    [].push.call(a,[3]);

    a // {a:1,0:2,1:[3],length:2};

  • pop()方法用于删除数组的最后一个元素,并返回该元素。该方法会改变原数组

    var arr=[‘a’,’b’,’c’];

    a.pop() //‘c’

    a //[‘a’,’b’]

  • 对空数组使用pop方法,不是犯错,而是返回undefined

    [ ].pop() //undefined

  • push和pop结合使用就构成后进先出的栈结构

  • join()方法以参数作为分隔符,将所有数组组成一个字符串返回。如果不提供参数,默认用逗号分隔

    var str=”abcdefgh”;

    var arr=str.split(‘’); //[“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”]

    arr.join(‘’); //“abcdefgh”

    arr.join(‘ ‘); //a b c d e f g h’;

  • 如果数组成员是undefined或null或空位,会被转成空字符串

    [undefined,null].join(‘#’) //‘#’

    [‘a’, ,’b’].join(‘-‘) //‘a- -b’

  • 这个方法也可以用于字符串,通过call方法

    Array.prototype.join.call(‘hello’,’-‘) //“h-e-l-l-o”

  • join方法也可以用于类似数组的对象

    var obj={0:’a’,1:’b’,length:2};

    Array.prototype.join.call(obj,’-‘) //‘a-b’

  • concat()用于将多个数组合并。它将新数组的成员添加到原数组的尾部,然后返回一个新数组,原数组不变

    [‘hello’].concat([‘world’], [‘!’])
    // [“hello”, “world”, “!”]

  • concat方法如果不提供参数,concat方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是如果数组成员包括复合类型的值(比如对象),则新数组拷贝的是该值的引用(你改我也会改)。

    var obj = { a:1 };
    var oldArray = [obj];
    var newArray = oldArray.concat();
    obj.a = 2;
    newArray[0].a // 2

  • concat方法也可以用于将对象合并为数组,但是必须借助call方法

    [].concat.call({a: 1}, {b: 2})
    // [{ a: 1 }, { b: 2 }]
    [].concat.call({a: 1}, [2])
    // [{a: 1}, 2]
    [2].concat({a: 1})
    // [2, {a: 1}]

  • shift用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组

    var a=[‘a’,’b’,’c’];

    a.shift();

    a //[‘b’,’c’]

  • shift方法可以遍历并清空一个数组。

    1
    2
    3
    4
    5
    6
    7
    8
    var list = [1, 2, 3, 4, 5, 6];
    var item;

    while (item = list.shift()) {
    console.log(item);
    }

    list // []

    pushshift结合使用,就构成了“先进先出”的队列结构(queue)。

  • unshift方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。

    1
    2
    3
    4
    var a = ['a', 'b', 'c'];

    a.unshift('x'); // 4
    a // ['x', 'a', 'b', 'c']

    unshift方法可以在数组头部添加多个元素。

    1
    2
    3
    var arr = [ 'c', 'd' ];
    arr.unshift('a', 'b') // 4
    arr // [ 'a', 'b', 'c', 'd' ]
  • reverse()方法用于颠倒数组中的元素的顺序,返回改变后的数组。注意,会改变原数组

    var a = [‘a’, ‘b’, ‘c’];
    a.reverse() // [“c”, “b”, “a”]
    a // [“c”, “b”, “a”]

  • slice方法用于提取原数组的一部分,返回一个新数组,原数组不变。它的第一个参数为起始位置(从零开始),第二个参数为1终止位置(但不包括该元素本身)。若省略第二个参数,则一直返回到原数组最后一个成员,相当于原数组的拷贝。

    a.slice(0) // [“a”, “b”, “c”]
    a.slice(1) // [“b”, “c”]
    a.slice(1, 2) // [“b”]
    a.slice(2, 6) // [“c”]
    a.slice() // [“a”, “b”, “c”]

  • slice方法的参数是负数时表示倒数计算的位置。

    var a = [‘a’, ‘b’, ‘c’];
    a.slice(-2) // [“b”, “c”]
    a.slice(-2, -1) // [“b”]

  • 如果参数值大于数组成员的个数,或者第二个参数小于第一个参数,则返回空数组。

    var a = [‘a’, ‘b’, ‘c’];
    a.slice(4) // []
    a.slice(2, 1) // []

  • slice方法的一个重要应用,是将类似数组的对象转为真正的数组。

    Array.prototype.slice.call({ 0: ‘a’, 1: ‘b’, length: 2 })
    // [‘a’, ‘b’]
    Array.prototype.slice.call(document.querySelectorAll(“div”));
    Array.prototype.slice.call(arguments);

  • splice方法用于删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。

    splice的第一个参数是删除的起始位置,第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。

    // 格式
    arr.splice(index, count_to_remove, addElement1, addElement2, …);
    // 用法
    var a = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’];
    a.splice(4, 2) // [“e”, “f”]
    a // [“a”, “b”, “c”, “d”]

  • 如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。

    var a = [1, 2, 3, 4];
    a.splice(2) // [3, 4]
    a // [1, 2]

  • sort方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。

  • 如果想让sort方法按照自定义方式排序,可以传入一个函数作为参数,表示按照自定义方法进行排序。该函数本身又接受两个参数,表示进行比较的两个元素。如果返回值大于0,表示第一个元素排在第二个元素后面;其他情况下,都是第一个元素排在第二个元素前面。

    [10111, 1101, 111].sort(function (a, b) {
    return a - b;
    })
    // [111, 1101, 10111]
    [
    { name: “张三”, age: 30 },
    { name: “李四”, age: 24 },
    { name: “王五”, age: 28 }
    ].sort(function (o1, o2) {
    return o1.age - o2.age;
    })
    // [
    // { name: “李四”, age: 24 },
    // { name: “王五”, age: 28 },
    // { name: “张三”, age: 30 }
    // ]

  • map方法对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组。map方法接受一个函数作为参数。该函数调用时,map方法会将其传入三个参数,分别是当前成员、当前位置和数组本身。

    var numbers = [1, 2, 3];
    numbers.map(function (n) {
    return n + 1;
    });
    // [2, 3, 4]

    numbers
    // [1, 2, 3]

    [1, 2, 3].map(function(elem, index, arr) {
    return elem * index;
    });
    // [0, 2, 6]

    map方法不仅可以用于数组,还可以用于字符串,用来遍历字符串的每个字符。但是,不能直接使用,而要通过函数的call方法间接使用,或者先将字符串转为数组,然后使用。

    1
    2
    3
    4
    5
    6
    7
    8
      var upper = function (x) {
    return x.toUpperCase();
    };
    [].map.call('abc', upper)
    // [ 'A', 'B', 'C' ]
    // 或者
    'abc'.split('').map(upper)
    // [ 'A', 'B', 'C' ]
文章目录
  1. 1. 一 . 基础补充
    1. 1.0.1. 1.值,变量和类型
    2. 1.0.2. 2.语句
    3. 1.0.3. 3.对象
      1. 1.0.3.0.1. 删除一个不存在的属性,delete不报错,而且返回true。
      2. 1.0.3.0.2. hasOwnPreperty()方法:检测的是自身属性,无关继承来的属性
      3. 1.0.3.0.3. propertyIsEnumerable()方法:只有检测到自有属性且这个属性的可枚举性为true时才返回true
  • 2. 事件机制
    1. 2.0.1. 事件捕获阶段(event capuring)
    2. 2.0.2. 事件冒泡(dubbed bubbling)
    3. 2.0.3. 事件绑定的方法
      1. 2.0.3.0.1. addEventlistener(event,listener,useCapture)
      2. 2.0.3.0.2. attachEvent(event,listener)
      3. 2.0.3.0.3. 事件冒泡例子
      4. 2.0.3.0.4. 事件捕获例子
  • 3. 要求
    1. 3.0.1. 高质量代码
    2. 3.0.2. 提高性能
      1. 3.0.2.0.1. (类)数组循环获取值时缓存长度
      2. 3.0.2.0.2. for循环遍历数组,for-in循环遍历类数组
      3. 3.0.2.0.3. 遍历属性时使用hasOwnProperty()方法过滤原型上的属性
  • 3.0.3. var的作用
    1. 3.0.3.0.1. 优点
    2. 3.0.3.0.2. 缺点
  • 3.0.4. 执行层面
    1. 3.0.4.0.1. 代码处理的两个阶段(预解析hoisting)
  • 4. 二 . JavaScript对象
    1. 4.0.0.0.1. 日常用途
  • 4.0.1. 对象公共属性
    1. 4.0.1.1. 1.constructor属性
    2. 4.0.1.2. 2.prototype属性
    3. 4.0.1.3. 3.toString()把对象转为字符串并返回结果
    4. 4.0.1.4. 4.valueOf() 返回对象的原始值
    5. 4.0.1.5. 5.Object.getPrototypeOf()
    6. 4.0.1.6. 6.Object.setPrototypeOf()
    7. 4.0.1.7. 7.Object.create()
    8. 4.0.1.8. 8.Object.prototype.isPrototypeOf()
    9. 4.0.1.9. 9.Object.prototype.proto_
    10. 4.0.1.10. 10.Object.getPropertyOfNames()
    11. 4.0.1.11. 11.Object.prototype.hasOwnProperty()
  • 4.1. 1.Array数组对象
    1. 4.1.0.1. 1.concat()连接两个或多个数组
    2. 4.1.0.2. 2.every()检查所有数组元素,返回boolear
    3. 4.1.0.3. 3.filter()创建所有符合条件元素的数组
    4. 4.1.0.4. 4.indexOf()返回指定字符串值首次出现的位置
    5. 4.1.0.5. 5.join() 把数组中的所有元素为一个字符串
    6. 4.1.0.6. 6.map()通过指定函数处理原始数组,并返回处理后的数组
    7. 4.1.0.7. 7.pop()删除数组最后一个元素并返回处理后的数组
    8. 4.1.0.8. 8.push()向数组的末尾添加一个或更多元素,并返回新的长度
    9. 4.1.0.9. 9.reverse()颠倒数组中元素的顺序
    10. 4.1.0.10. 10.slice()选取数组中的一部分,并返回一个新数组
    11. 4.1.0.11. 11.some()检测数组元素中是否有元素符合指定条件
    12. 4.1.0.12. 12.sort()对数组的元素进行排序
    13. 4.1.0.13. 13.splice()从数组中添加或删除,替换元素
    14. 4.1.0.14. 14.toString()把数组转为字符串并返回结果
    15. 4.1.0.15. 15.valueOf() 返回数组对象的原始值
    16. 4.1.0.16. 16.reduce()返回累计值
  • 4.1.1. 2.Boolean对象
  • 4.1.2. 3.Date对象
  • 4.1.3. 4.Number对象
  • 5. 三 . 深入理解js
    1. 5.0.1. 1.最小全局变量(Minimizing Globals)
      1. 5.0.1.0.1. 忘记var的副作用(Side Effect when forgetting var)
      2. 5.0.1.0.2. 访问全局对象(Access to the Global Object)
      3. 5.0.1.0.3. 单var形式(Single var Pattern)
      4. 5.0.1.0.4. 预解析:var散布的问题(Hoisting: A Problem with Scattered vars)
  • 5.0.2. 2.代码处理的两个阶段
  • 6. 四 . this 精讲
    1. 6.0.1. 谁调用这个函数或方法,this关键字就指向谁
    2. 6.0.2. 1.改变this指向的三大方法
      1. 6.0.2.0.1. 1.call、apply、bind方法的共同点和区别:
      2. 6.0.2.0.2. 2.thisObj的取值有以下4种情况:
      3. 6.0.2.0.3. 3.实例
  • 7. 五 . 垃圾回收机制
  • 8. 六. 枚举
  • 9. ECMAScript原始值和引用值
    1. 9.0.1. 1.原始值
    2. 9.0.2. 2.引用值
    3. 9.0.3. 3.对象
      1. 9.0.3.0.1. 1.属性
      2. 9.0.3.0.2. 2.方法
  • 9.0.4. 4.String对象
  • 9.0.5. 5.整数
  • 9.0.6. 6.语句
    1. 9.0.6.0.1. 1.有标签的语句
  • 10. 七. 面向对象
    1. 10.0.1. 1.具备的四种能力
    2. 10.0.2. 2.对象的应用
    3. 10.0.3. 3.对象废除
    4. 10.0.4. 4.绑定
    5. 10.0.5. 5.作用域
    6. 10.0.6. 6.使用动态原型方法类的属性和方法
    7. 10.0.7. 7.ECMAScript的字符串
  • 11. 八 . 继承机制实现
    1. 11.0.1. 1.对象冒充
    2. 11.0.2. 2.使用call(对象参数,形参1,2,..)
    3. 11.0.3. 3.使用apply(对象参数,形参数组)
  • 12. 九.object对象
    1. 12.0.1. Object对象上面部署一个方法的两种做法。
      1. 12.0.1.0.1. 1.部署在Object对象本身
      2. 12.0.1.0.2. 2.部署在Object.prototype对象
  • 12.0.2. Object()方法
  • 12.0.3. Object对象的静态方法
  • 12.0.4. 对象属性模型的相关方法
  • 12.0.5. 控制对象状态的方法
  • 12.0.6. 原型链相关方法
  • 12.0.7. Object对象都有的六大实例方法
  • 12.0.8. Array对象
    1. 12.0.8.0.1. 1.Array实例的方法
  • |