JavaScript 高级程序设计(一)


希望对找与 javascript 相关工作的同学有所帮助,敲得好累~

P1 基本概念

1.1 标识符

1.2 关键字和保留字

1.3 变量

var a = 'hello'; // var声明a变量,并初始化为 'hello'
var b; // var声明b变量,但未初始化
console.log(b); // undefined
console.log(c); // c没有声明
// Uncaught ReferenceError: c is not defined

在严格模式下,给未声明的变量赋值会抛出 ReferenceError

1.4 数据类型

5种基本数据类型:undefined, null, boolean, number, string
复杂数据类型:Object

1.5 typeof 操作符

可能返回字符串结果:undefined, boolean, string, number, object, function

console.log(typeof 9); // number
console.log(typeof true); // boolean
console.log(typeof 'asd'); // string
console.log(typeof null); // object
console.log(typeof [1,2,3]);  // object
console.log(typeof /\d+/);  // object
console.log(typeof Array.prototype.forEach); // function

1.6 null 类型

null 表示一个空对象指针。
如果定义的变量是用来保存对象的,最好将它初始化为 null。这样一来,只要直接检查变量是否为null来判断它是否已经保存了一个对象的引用。

if (car !== null) {
    // 对car对象执行某些操作
}

undefined的比较

console.log(null == undefined) // true
console.log(null === undefined) // false

1.7 Boolean 类型

var a = new Boolean(123); // 这是个对象
var a = Boolean(123);
console.log(typeof a) // object
console.log(a == true) // true
console.log(typeof b) // boolean
console.log(b == true) // true
数据类型 true false
Boolean true false
String 非空字符串 ""
Number 非零数字(包括无穷大) 0或NAN
Object 任何对象 null
Undefined 不存在的 undefined

1.8 Number 类型

  • 默认是十进制整数
  • 八进制:以0开头,然后是 0-7 (严格模式无效,抛出错误)
  • 十六进制:以0x开头,然后是 0-9及A-F,a-f
var a = 55 //55
a = 070 // 八进制的56
a = 079 //无效的八进制,解析为79
a = 0xA // 十六进制的10
a = 0x1f // 十六进制的31

浮点数值的最高精度是17位小时,但算术计算时的精确度远不如整数。例如 0.1+0.2 的结果不是 0.3,而是 0.30000000000000004

// 求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题
// 输入 multiply(3, 0.0001)
// 输出 0.0003
function multiply(a, b) { 
     //求两个数中精度大的一个 
      var stra = a.toString(); 
      var strb = b.toString(); 
      var len = Math.max(stra.length-stra.indexOf('.')-1,strb.length-strb.indexOf('.')-1); 
      return (a*b).toFixed(len); 
  }

数值范围
Infinity 正无穷,-Infinity 正无穷
可使用 isFinity() 判断是否有穷,有穷返回 true
利用 Number.NEGATIVE_INFINITYNumber.POSITIVE_INFINITY来获得 -InfinityInfinity

NaN

console.log(NAN == NAN) // false

isNaN() 判断一个值是否 不是数值

isNaN(10) // false
isNaN("10") // false, "10"可以转换位10
isNaN('red') // true
isNaN(true) // false, boolean可转换为数子1

Number() 数值转换

  • Boolean值:true => 1, false => 0
  • Number值:不变
  • null:0
  • undefined:NaN
  • String:"" => 0, '123' => 123, 忽略前导零 '0010' => 10, '1.1' => 1.1, 十六进制 '0xA' => 10, 包含除上述格式外的字符 'ab100cd' => NaN
  • Object:先调用 valueOf(),按上述规则转换,如果为NaN,调用 'toString()', 按上述规则转换
Number('abc') // NaN
Number('10') // 10
Number(0010) // 10
Number(false) // 0

parseInt()

parseInt('1234abc') // 1234
parseInt('abc1234') // NaN
parseInt('') // NaN
parseInt('0xA') // 10
parseInt(22.5) // 22
parseInt('070') // 70,看下面解释

ES5不具有解析八进制的能力,会忽视前导零。
使用 parseInt() 的第二个参数指定解析格式

parseInt('0xA', 16) // 10
parseInt('A', 16) // 10
parseInt('A') // NaN
parseInt('10', 10) // 10
parseInt('10', 8) // 8
parseInt('10', 2) // 2

1.9 String 类型

字面量 含义
\n 换行
\t 制表
\b 退格
\r 回车
\f 进纸
\\ 斜杠 \
\' 单引号 '
\" 双引号 "

toString()
nullundefined值 没有这个方法
toString() 默认以十进制返回数值的字符串表示,但可以提供一个参数转换成指定的格式

var a = 11;
console.log(a.toString()) // '11'
a = true;
console.log(a.toString()) // 'true'
var n = 10;
console.log(n.toString()) // '10'
console.log(n.toString(2)) // '1010'
console.log(n.toString(8)) // '12'
console.log(n.toString(10)) // '10'
console.log(n.toString(16)) // 'a'

String()
在不知道要转换的值是不是nullundefined,可以用 String()

  • 如果值有 toString() 方法,则调用它
  • 如果值为 null,返回 'null'
  • 如果值为 undefined,返回 'undefined'

1.10 Object 类型

var o = new Object();
var o = new Object; // 有效,但不推荐省略圆括号

属性和方法:constructor, hasOwnProperty(), isPrototypeOf(), propertyIsEnumerable(), toLocaleString(), toString(), valueOf

1.11 桉位非,桉位与,桉位或,桉位异或

1.12 有无符号位的左移和右移

P2 变量、作用域和内存问题

2.1 变量

  • 基本类型值:简单的数据段 => undefined, null, boolean, number, string 这5种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
  • 引用类型值:保存在内存中的对象。在操作对象时,实际是在操作对象的引用而不是实际的对象。

2.2 复制变量值

如果复制的是基本类型的值,则复制后的结果和原变量是独立的

var a = 1;
var b = a;
console.log(a) // 1
console.log(b) // 1
a = 2;
console.log(a) // 2
console.log(b) // 1
b = 3;
console.log(a) // 2
console.log(b) // 3

如果复制的是引用类型的值,这个值的副本是个指针,复制操作后两个变量将引用同一个对象。

var a = new Object();
var b = a;
a.name = 'hqy';
console.log(b.name) // 'hqy'

2.3 传递参数

注意,访问变量有按值引用两种方式,当时参数只能按值传递.

  • 向参数传递基本类型的值,被传递的值会被复制给一个局部变量(命名参数,或成为arguments对象中的一个元素
  • 向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部参数,所以这个局部变量的变化会被反应在函数的外部。
// 传递基本类型的值
function add(num) {
    num += 10;
    return num;
}
var count = 20;
var result = add(count);
alert(count) // 20,没有变化
alert(result) // 30

// 传递引用类型的值
// 即使这个变量时按值传递的,obj也会按引用来访问同一个对象
function setName(obj) {
    obj.name = 'hqy';
}
var a = new Object();
setName(a);
alert(a.name); // 'hqy'

// 以上例子让我们错误地认为参数还是按引用传递的
// 证明对象是按值传递的例子
function setName(obj) {
    obj.name = 'hqy';
    obj = new Object(); 
    // 上面代码重写obj,现在这个变量引用的是一个局部变量
    obj.name = 'sss';
}
var a = new Object();
setName(a);
alert(a.name); // 'hqy'

2.4 检测类型

typeof 在检测基本数据类型时很给力,但检测引用类型的值就没用了。这时候我们就要使用 instanceof

alert(person instanceof Object) // 变量 person 是 Object 吗
alert(person instanceof Array)  // 变量 person 是 Array 吗
alert(person instanceof RegExp) // 变量 person 是 RegExp 吗

// 更好的方法
alert(Object.prototype.toString.call(person) === '[object, Array]')

2.5 执行环境和作用域

执行环境定义了变量或函数有权访问的其他数据,决定他们各自的行为。每个执行环境都有一个与之关联的变量对象。每个函数都有自己的执行环境。
当代码在一个环境中执行时,会创建对象的一个作用域链(保证对执行环境有权访问的所有变量和函数的有序访问)。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量参数。活动对象最开始只包含一个变量 arguments

延长作用域链
try-catch语句的 catch 块,with 语句, eval()

function buildUrl() {
    var a = 'qwq';
    with (location) {
        var url = href + a;
    }
    return url;
}
// with 接受的、是location对象,这个变量被添加到作用域链的前端。引用 href 就是在引用 location.href()

2.6 没有块级作用域

函数中没有用 var 定义变量,这个变量就会被添加到全局环境。外部无法直接获取函数内声明的变量。
如果局部环境中存在同名标识符,就不会使用位于福环境中的标识符。

2.7 垃圾回收

管理内存

function createPerson() {
    var name = 'hqy';
    return function() {
        return name;
    }
}
var f = createPerson();
alert(f()); // 'hqy'
// 由于闭包的作用域链中保存着 name,那么意味着这个name占用的内存就永远不会被回收
f = null; // 将 f 设置为 null,减少引用数,确保正常回收其占用的内存

P3 引用类型

3.1 Object 类型

// 构造函数
var a = new Object();
a.name = 'hqy';
a.age = 21;

// 对象字面量,此时不会调用 Object 构造函数
var a = {
    name: 'hqy',
    age: 21
}

// 访问对象属性
alert(a.name) // 'hqy'
alert(a['name']) // 'hqy' ,方括号内是属性的字符串形式

3.2 Array 类型

创建数组

var a = new Array(20) // 创建一个包含20项的数组
var a = new Array('red', 'blue') // 创建一个包含2项的数组 ['red', 'blue']
var a = ['red', 'blue']; // 建一个包含2项的数组 ['red', 'blue']
var a = []; // 空数组

修改数组

var a = ['red', 'blue'];
a[5] = 'green';
alert(a[2]) // undefined
alert(a.length) // 6

检测数组

value instanceof Array
Array.isArray(value)
Object.prototyoe.toString.call(value) === '[object, array]'

转换方法

var a = ['red', 'blue', 'yellow'];
console.log(a.toString()) // red,blue,yellow 以逗号分隔的字符串
console.log(a.valueOf()) // ["red", "blue", "yellow"] 即数组本身

// toLocaleString() 调用的是每一项的 toLocaleString() 

console.log(a.join('||')) // red||blue||yellow 默认是逗号

栈方法

  • push() 接受任意数量的参数逐个添加到数组末尾并返回修改后数组的长度
  • pop() 移除数组最后一项并返回该项
    队列方法
  • shift() 移除数组的一项并返回该项
  • unshift() 数组前端添加任意项并返回新数组的长度

重排序
reverse() 反转数组

var a = [1, 2, 3, 4];
console.log(a.reverse()) // [4, 3, 2, 1]

sort() 自定义排序,默认是根据转换成字符串对比每个字符大小,'5' 大于 '10'

// 从小到大
var a = [2, 1, 4, 3];
a.sort(function(a, b) {
    return a - b;
})
console.log(a) // [1, 2, 3, 4]

// 给定一个数组 [{name: 'hqy', age: 21}, {name: 'qqq', age: 44}, ...],根据 age 排序
function compare(key) {
    return function(obj1, obj2) {
        var val1 = obj1[key];
        var val2 = obj2[key];
        if(val1 < val2) {
            return -1;
        } else if(val1 > val2) {
            return 1;
        } else {
            return 0;
        }
    }
}
var a = [{name: 'hqy', age: 21}, {name: 'qqq', age: 44}, ...];
a.sort(compare('age')); // 根据健 age 将数组从小到大排序

数组操作方法
concat() 合并数组,创建新数组,不影响原数组

var a = [1, 2, 3];
var b = a.concat(4, [5, 6]);
alert(a) // 1, 2, 3
alert(b) // 1, 2, 3, 4, 5, 6

slice() 截取字符串,返回新字符串

var a = [1, 2, 3, 4];
var b = a.slice(1, 2);
alert(a) // 1, 2, 3, 4
alert(b) // 2, 3
b = a.slice(1)
alert(b) // 2, 3, 4

splice() 向数组添加或删除内容,改变原数组

// 只是删除
var a = [1, 2, 3, 4];
var b = a.splice(0, 2) // 删除了前两项
alert(a) // 3, 4
alert(b) // 1, 2

// 只是添加
var a = [1, 2, 3, 4];
var b = a.splice(1, 0, 6, 7) // 在位置1了前两项
alert(a) // 1, 6, 7, 2, 3, 4
alert(b) // 空数组

// 既添加又删除
var a = [1, 2, 3, 4];
var b = a.splice(1, 2, 6, 7) // 从位置1删除2项,再在位置1添加2项
alert(a) // 1, 6, 7, 4
alert(b) // 2, 3

位置方法
indexOf(), lastIndexOf()

迭代方法
可接收4个参数:item, index, array

  • every():对数组每一项执行给定函数,每一项都返回true,则返回true
  • some(0:对数组每一项执行给定函数,其中一项返回true,则返回true
  • filter():返回该函数会返回true的项组成的数组
  • forEach():对数组每一项执行给定函数,没有返回值
  • map():返回每次函数调用的结果组成的数组

归并方法
reduce, reduceRight 接收4个参数: 前一个值, 当前值,项的索引,数组对象

// 计算给定数组 arr 中所有元素的总和 
function sum(arr) {
    return arr.reduce(function(prev, cur, index, array) {
        return prev + cur;
    })
}

3.3 Date 类型

var now = new Date();
var date1 = new Date("2017, 3, 1");

var start  = Date.now() // 取得当前时间

var date2 = new Date("2017, 3, 2");
alert(date2 > date1) // true

toString(), valueOf(), toLocaleString()

var now = new Date();
console.log(now.toLocaleString());
// 2017/7/1 下午10:13:31
console.log(now.valueOf());
// 1498918470507
console.log(now.toString());
// Sat Jul 01 2017 22:14:17 GMT+0800 (中国标准时间)

3.4 Function 类型

定义函数

// 函数声明
function sum(n1, n2) {
    return n1 + n2; 
}

// 函数表达式
var sum = function(n1, n2) {
    return n1 + n2; 
}

函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没什么不同,一个函数可能会有多个名字。

function a(n, m) {
    return n + m;
}
alert(a(1, 2)); // 3
var b = a;
alert(b(1, 2)); // 3
a = null;   // 将 a 设置为 null,让它和函数断绝关系,但 b 还是正常的
alert(b(1, 2)); // 3

没有重载

function a(n) {
    return n * 2;
}
function a(n) {
    return n * 3;
}
alert(a(3)) // 9

函数声明和函数表达式

// 函数表达式只有当解析器执行到它所在的代码行,才会真正被解释执行
alert(a) // ReferenceError
var a = function() {
    return true;
}

要访问函数的指针而不执行函数的话,必须去掉函数名后的那对大括号。
函数内部属性

  • arguments: 类数组对象,包含着传入函数的所有参数,只能.length,不具备数组的其他方法
  • this: 引用的是函数执行的环境对象

arguments.callee 指向拥有这个arguments 对象的函数 (严格模式下会报错)

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

函数属性和方法
每个函数都包含两个属性:lengthprototype

// length 返回函数希望接收的命名参数个数
function a(n, m) {
    return n + m;
}
alert(a.length) // 2

prototype 属性是不可枚举的,因此使用 for-in 无法发现.
每个函数都包含两个非继承来的方法:apply()call(). 它们第一个参数都是在其中运行函数的作用域,第二个apply是数组,而call是要求一个个列举

function sum(n, m) {
    return n + m;
}
function applySum(num1, num2) {
    // 使用 apply
    return sum.apply(this, arguments);
    // 使用 call
    return sum.apply(this, arguments[0], arguments[1]);
}

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

在严格模式下,未指定环境对象而调用函数,则this 不会转型为window,除非明确把函数添加到某个对象或者调用applycall,否则this将是 undefied.

bind()
该方法会创建一个函数的实例,其this会绑定到传给bind()函数的值

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

3.5 String 类型

replace()

// 第二个参数是函数, 参数依次为匹配项,位置,原始字符串
function htmlEscape(text) {
    return text.replace(/[<>"&]/g, function(match, pos, originalText) {
        switch(match) {
            case '<':
                return '<';
            case '>':
                return '>';
            case '&':
                return '&';
            case '"':
                return '"';
        }
    })
}

3.6 Global对象

诸如 isNaN(), isFinite(), parseInt, parseFloat() 都是 Global 对象的方法
URI 编码方法:encodeURI(), encodeURIComponent(), decodeURI(), decodeURIComponent()

3.7 Math 对象

max(), min()
舍入方法

  • Math.ceil():向上舍入
  • Math.floor():向下舍入
  • Math.round():四舍五入最接近的整数

random()

值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

P4 面向对象的程序设计

JavaScript 高级程序设计(二)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容