《深入理解JavaScript》笔记

《深入理解JavaScript》笔记

1、基础JavaScript

1.1、背景

1.1.1、JavaScript与ECMAScript

JavaScript是编程语言
ECAMScript是这种语言规范

1.1.2、JavaScript的影响和本质

在其他语言,我们学的是语言特性,而在JavaScript中,我们常学的却是模式。

1.2、语法

1.2.1、语法概述

一个单独的等于号(=),用于为变量赋值。
三个连续的等于号(===),用于比较两个值。

1.2.2、语句和表达式

语句“做事情”。
表达式产生值。
JavaScript两种方式实现if-then-else
语句方式:

var x;
if(y >= 0){
	x = y;
} else {
	x = -y;
}

表达式方式:

var x = y >= 0 ? y : -y;

后面这种方式可以用于函数的参数(而前者不行)

myFunction(y >= 0 ? y:-y)

表达式语句

1.2.3、分号

分号用于结束语句,而不是结束块。有一种情况会看到分号出现在块之后:函数表达式作为一个表达式时。

var x = 3 * 7;
var f = function() {};
1.2.4、注释

单行注释
多行注释

x++; // single-line comment 
/* this is
   a multiline
   comment.
*/

1.3、变量和赋值

变量在声明后使用

var foo; // declare variable 'foo'

foo = fuck oriented object
foo是"你要让它是什么就是什么"。

1.3.1、赋值

变量声明和赋值可以同时进行

var foo = 6;

也可以为一个已有变量进行赋值

foo = 4;  //change variable 'foo'
1.3.2、复合赋值运算符
x += 1;
x = x + 1;
1.3.3、标识符与变量名

保留字(不能用于变量名、函数名、参数名)
arguments break case catch class const continue debugger default delete do else enum export extends false finally for function if implements import in instanceof interface let new null package private protected public return static super switch this throw true try typeof var void while
infinity NaN undefined

1.4、值

布尔值、数字、字符串、数组等。在JavaScript值所有的值都有属性。每一个属性都有一个key(或者是name)和一个value。属性就像是一条记录的字段。通过点(.)操作符可以读取属性。

value.propKey

字符串‘abc’有length这个属性

var str = 'abc';
str.length

也可以写为

'abc'.length

点操作同样可以用于给属性赋值

var obj = {};    // empty object
obj.foo = 123;    // create property 'foo', set it  to 123
console.log(obj.foo)

也可以通过点操作来调用方法:

'hello'.toUpperCase()    // 大写
'HELLO'
1.4.1、原始值和对象

原始值包括布尔值、数字、字符串、null和undefined
其他的值都是对象
这两者之前最主要的区别在于它们的比较方式;每个对象都有唯一的标识且只等于自己。

var obj1 = {};
var obj2 = {};
obj1 === obj2    // false
obj1 === obj1    //true

所有的原始值,只要编码值相同,则被认为相等

var prim1 = 123;
var prim2 = 123;
prim1 === prim2    // true
1.4.2、原始值(primitives)

布尔值:true、false
数字:20156、1.351
字符串:‘dh’、“abc”
两个“空值”: undefined、null
特点:
(1)按值进行比较
内容比较:

3 === 3    // true
'abc' === 'abc'    // true

(2)不可改变
其属性不能被改变、添加或移除:

var str = 'abc';
str.length = 1;    // try to change property 'length'
str.length    // => no efffect    3
str.foo = 3;     // try to create property 'foo'
str.foo    // => no effect, unknown property  undefined
1.4.3、对象
  • 简单对象,可以通过对象字面量来创建
{
	firstName: 'Jane',
	lastName: 'Doe'
}
  • 数组,可以通过数组字面量来创建
['apple', 'banana', 'cherry']

可以通过数字索引来访问它们

  • 正则表达式,可以通过正则表达式字面量来创建
/^a+b+$/

对象具有一下特点:
(1)按引用进行比较
比较身份标识:每个值都有各自的身份标识

{} === {}    // two different empty objects    false
var obj1 = {};
var obj2 = obj1;
obj1 === obj2    // true

(2)默认可变
对象属性可以很自由地被改变、添加和移除

var obj1 = {}
var obj2 = 123;   // add property 'foo'
console.log(obj1.foo)    // 123
1.4.4、undefined和null

“空值”

  • undefined的意思是“没有值”。
    未被初始化的变量即为undefined;
var foo;
console.log(foo)    // undefined

丢失的参数也会是undefined

function f(x) { return x }
console.log(f())    // undefined

访问不存在的属性,也会得到undefined

var obj = {};    // empty object
console.log(obj.foo)    // undefined
  • null的意思是“没有对象”。在用到对象的时候它表示空值(例如参数、对象链中的最后一个元素等)。
    undefined和null没有属性,甚至连toString()这种标准方法都没有。

检查undefined 或 null
函数允许透过undefined或null来表示缺失的值。可以通过以下显示的检查来做到同样的事情:

if(x === undefined || x === null){
	...
}

也可以利用 undefined 或 null 都可被视为 false 这一事实来处理:

if(!x){
	...
}

false, 0, NaN 和 ‘’ 都可被视为false

1.4.5、使用 typeof 和 instanceof 对值分类

typeof用于原始值
instanceof用于对象

  • typeof用法返回值是一个表示这个值“类型”的字符串。
typeof value
typeof true    // 'boolean'
typeof 'abc'    // 'string'
typeof {}    // empty object literal  'object'
typeof []    // empty object literal  'object'
操作数结果
undefined‘undefined’
nullobject
布尔值boolean
数字number
字符串string
函数function
所有其他的常规值object
引擎创建的值JavaScript引擎可以被允许去创建一些值,且typeof的结果可以返回任意字符串(可以与列表值列出的结果都不一样)

typeof null 返回object是一个不能修正的bug,因为这会破坏现有的代码。但这并不表示null是一个对象

  • instanceof用法:
value instanceof Constr

如果value是一个通过Constr构造器创建的对象,则返回true

var b = new Bar();    // object created by constructor Bar
b instanceof Bar    // true
{} instanceof Object    // true
[] instanceof Object    // true
[] instanceof Object    // Array is a subconstructor of Object    true
undefined instanceof Object    // false
null instanceof Object    // false

1.5 布尔值 true false

以下运算会产生布尔值

  • 二元逻辑运算符: &&(与),|| (或)
  • 前置逻辑运算符:!(非)
  • 比较运算符:
    相等运算符:
    排序运算符(针对字符串及数字):>, >=, <, <=
1.5.1 真值与假值

以下值会被解释成false

  • undefined、null
  • 布尔值:false
  • 数字:-0、NaN
  • 字符串:‘’
    其他所有的值(包括所有的对象)都会被当成true。
    Boolean()作为函数调用时,会将传入的参数转换为一个布尔值。
Boolean(undefined)    // false
Boolean(0)    // false
Boolean(3)    //true
Boolean({})    // empty object    true
Boolean([])    // empty array     true
1.5.2、二元逻辑运算符

二元逻辑运算符是短路的。因为如果第一个运算数就足以确定结果的话,则不会对第二个运算数做评估。
以下表达式,其中的foo()函数永远不会被调用:

false && foo()
true || foo()

二元逻辑运算符会返回运算数值得一个----可能是一个布尔值,也可能不是。
(1)与(&&)
如果第一个运算数是假值,返回它。否则,返回第二个运算数。

NaN && 'abc'    // NaN
123 && 'abc'    // 'abc'

(2)或(||)
如果第一个运算数是真值,返回它。否则,返回第二个运算数。

'abc' || 123    // 'abc'
'' || 123    // 123
1.5.3、等式运算符

两种类型相等

  • 常规的,或“宽松的”相等(或不相等):== 和 !=。
  • 严格的相等(或不相等):=== 和 !==
    常规相等,更多考虑值是否相等。

1.6、数字

js中所有的数字都是浮点数

1 === 1.0    // true

也包含一些特殊的数字:
NaN(“not a number”) 一个错误的值

Number('xyz')    // 'xyz' can't be converted to a number
NaN

Infinity多数情况下也是一个错误的值:

3/0    // Infinity
Math.pow(2, 1024)    // number too large Infinity

Infinity比任何一个数都要大(NaN除外)
-Infinity比任何一个数都要小(NaN除外)

1.7、运算符

  • 加法: 数字1 + 数字2
  • 减法: 数字1 - 数字2
  • 乘法: 数字1 * 数字2
  • 除法: 数字1 / 数字2
  • 取模: 数字1 % 数字2
  • 增量:++变量,变量–
  • 减量:–变量,变量–
  • 负数:-值
  • 转变成数字: +值
1.8字符串

单引号 双引号之内。反斜杠(\)用于转义字符及产生一些控制字符。

'abc'
"abc"

'Did she say "Hello"?'
"Did she say \"Hello\"?"

'That\'s nice!'
"That's nice!"

'Line 1\nLine2'    // newline
'Backlash: \\'

可以通过方括号来访问字符串中的单个字符:

var str = 'abc'
str[1]    // 'b'

字符串的length属性可以对字符的个数进行计数:

'abc'.length    // 3

像所有的原始值一样,字符串是不可变的;如果要改变一个已有的字符串,必须创建一个新的才行。

1.8.1 字符串运算符

字符串可以通过加号(+)进行连接,如果其中一个运算数是字符串的话,另一个运算数将被转换为字符串:

var messageCount = 3;
console.log('You have' + messageCount + 'messages')    // 'You have 3 messages'

在多个步骤转换连接字符串,可以使用+=运算符:

var str = '';
str += 'Multiple ';
str += 'pieces ';
str += 'are concatenated.';
console.log(str)    // 'Multiple pieces are concatenated.'
1.8.2、字符串方法
'abc'.slice(1)    // copy a substring    'bc'
'abc'.slice(1,2)    // 'b'

'\t xyz   '.trim()    // trim whitespace    'xyz'

'mjolnr'.toUpperCase()    // 'MJOLNR'

'abc'.indexOf('b')    // find a string    1
'abc'.indexOf('x')    // -1

str.slice(start, end) 提取字符串某个部分,start(包含),end(不包含)。
str.trim() 删除字符串的头尾空白符,空白符包括:空格、制表符tab、换行符等其他空白符等。不会更改原始字符串。
str.toUpperCase()将字符串转换为大写字母,不会更改原始字符串。

1.9、语句

1.9.1、条件语句

if语句有一个then从句以及一个可选的else从句

if(myvar === 0){
	// then
}

if(myvar === 0){
	// then
} else {
	// else	
}

if(myvar === 0){
	// then
} else if(myvar === 1){
	// else-if
} else if(myvar === 2){
	// else-if
} else {
	// else
}

从句仅有一个单独的语句(对 for 和 while 语句同样适用):

if(x < 0) return -x;

switch语句:
fruit的值会决定要执行哪个case:

switch(fruit){
	case 'banana':
		//...
		break;
	case 'apple':
		//...
		break;
	default: //all other cases
		//...
}

case 之后跟的“运算数”可以是任意表达式;在switch里的参数会通过===来进行比较。

1.9.2、循环语句

for(init; condition; post_iteration){
statement
}
初始化会在循环开始前执行。
条件会在每次循环迭代之前做检查,如果是false则终止循环。
后迭代会在每次循环迭代后执行。

for(var i=0; i < arr.length; i++){
	console.log(arr[i])
}

while循环语句会在条件成立的时候会持续循环

// Same as for loop above
var i = 0;
while(i < arr.length) {
	console.log(arr[i])
	i++;
}

do-while循环语句在条件成立时会持续循环。由于条件会跟在代码体之后,所以,这些代码体至少会执行一次:

do{
	// ...
} while (condition);

有两条语句适用于所有的循环方式:

  • break可以跳离循环
  • continue会开始一个新的循环迭代

1.10、函数

函数声明

function add(param1, param2) {
	return param1 + param2;
}

函数表达式

var add = function(param1, param2){
	return param1 + param2;
};

函数表达式会产生一个值,因此可以将函数作为参数直接传递给另外的函数:

someOtherFunction(function(p1, p2){ ... })
1.10.1、函数声明的提升特性

函数声明具有提升特性----它们的实体会被移动到所在作用域的开始处。这使得我们可以引用后面声明的函数。

function foo(){
	bar();    //OK,bar is hoisted
	function bar() {
		...
	}
}

var声明也具有提升的特性,但通过它们执行的赋值却不具备该特性。

function foo() {
	bar();  // Not OK, bar is still undefined
	var bar = function(){
		// ...
	};
}
1.10.2、特殊的变量arguments

函数的所有参数都可以被自由调用,会通过arguments变量来使所有参数可用。
arguments看起来像个数组,但却不具备数组的方法

function f() { return arguments }
var args = f('a', 'b', 'c');
console.log(arrs.length)    // 3
console.log(args[0])    // 'a'
1.10.3、参数太多或太少
function f(x, y){
	console.log(x, y)
	return toArray(arguments);
}
// 额外的参数会被忽略
f('a', 'b', 'c')    //a, b
// 丢失的参数会得到undefined这个值
f('a')    // a, undefined
f()    // undefined, undefined
1.10.4、可选参数

以下是一个给参数赋上默认值的通用模式:

function pair(x, y){
	x = x||0;
	y = y||0;
	return [x,y];
}
1.10.5、强制参数长度

arguments.length

function pair(x, y){
	if(arguments.length !== 2){
		throw new Error('Need exactly 2 arguments');
	}
	...
}
1.10.6、将arguments转换为数组

arguments不是数组,它只是类似于数组。有length属性,可以通过方括号去访问它的元素。不能移除它的元素,也不能对它调用数组的方法。

function toArray(arrayLikeObject){
	return Array.prototype.slice.call(arrayLikeObject)
}
1.11、异常捕获
function getPerson(id) {
	if(id < 0){
		throw new Error('ID must not be negative:'+id);
	}
	return {id: id} // normally: retrieved from database
}

function getPersons(ids){
	var result = [];
	ids.forEach(function(id){
		try{
			var person = getPerson(id);
			result.push(person);
		} catch(exception){
			console.log(exception);
		}
	});
	return result;
}

使用try语句包裹关键代码,如果try语句有异常会被抛出那么catch语句就会执行。

1.12、严格模式

切换严格模式:
在JavaScript文件或者<script>标签第一行输入:

'use strict';

也可以在每一个函数值激活严格模式:

function functionInStrictMode(){
	'use strict';
}

1.13、变量作用域和闭包

var x;
x = 3;
y = 4;
// ReferenceError: y is not defined

使用单个var语句声明和初始化多个变量:

var x = 1, y = 2, z = 3;
1.13.1、变量是函数作用域的

一个变量的作用域总是完整的函数(相对于当前块)

function foo(){
	var x = -512;
	if(x < 0){
		var tmp = -x;
		...
	}
	console.log(tmp);  // 512
}

可以看到变量tmp并不局限于一行;直到函数结束它都存在。

1.13.2、变量的提升特性

所有变量声明都会被提升:声明会被移动到函数的开始处,而赋值则仍然会在原来的位置进行。

function foo(){
	console.log(tmp);  // undefined
	if(false){
		var tmp = 3;  //
	}
}

然而在程序内部,上述函数的执行过程其实是这样的

function foo(){
	var tmp;  // hoisted declaration
	console.log(tmp);
	if(false){
		tmp = 3;  // assignment stays put
	}
}
1.13.3、闭包

每个函数都和它周围的变量保持着连接,哪怕它离开被创建时的作用域也是如此。

function createIncrementor(start){
	return function(){  //1
		start++;
		return start;
	}
}

函数从标记为(1)的这行开始被创建,在创建结束后计离开它的上下文环境,但它仍然保持着和start的连接:

var inc = createIncrementor(5);
inc()  // 6
inc()  // 7
inc()  // 8

函数以及它所连接的周围作用域值的变量即为闭包。
createIncrementor()的返回其实就是一个闭包。

1.13.4、IIFE模式:引入一个新的作用域

防止一个变量变成全局变量
将函数当做类似块的方式来使用----IIFE(立即调用函数表达式)

(function() {	// open IIFE
	var tmp = ...;	// not a global variable
}());	//close IIFE

IIFE用例:闭包造成的无意共享

1.14、对象和构造函数

两种基础的面对对象机制:单一对象和构造函数

1.14.1、单一对象

对象具有属性,属性都是一个(键、值)对。键名都是字符串,值可以是任何值。

'use strict';
var jane = {
	name: 'Jane',
	describe: function() {
		return 'Person named' + this.name;
	}
}

获取(get)以及设置(set)这些属性
使用in运算符检查属性是否存在:

'newProperty' in jane  // true
'foo' in jane  // false

如果读取一个不存在的属性,会得到undefined。
检查执行:

jane.newProperty !== undefined  // true
jane.foo !== undefined  //false

使用delete运算符移除属性:

delete jane.newProperty  // true
'newProperty' in jane  // false
1.14.2、任意属性名

属性的键名可以是任何字符串。
如果想用其他的字符串作为属性名,则必须将它们用引号引起来,在通过对象字面量和方括号来获取或设置这个属性:

var obj = {'not an identifier': 123};
console.log(obj['not an identifier']);  // 123
obj['not an identifier'] = 456;

方括号可以用来动态计算属性键名:

var obj = {hello: 'world'};
var x = 'hello';
console.log(obj[x]); // 'world'
console.log(obj['hel'+'lo'])  // 'world'
1.14.3、提取方法

如果对方法进行提取,则会失去与对象的连接。

var func = jane.describe;
func()
// TypeError: Cannot read property 'name' of undefined

处理这个问题的解决方案使用bind()方法,所有函数都支持。会创建一个this总是指向给定值的新函数。

var func2 = jane.describe.bind(jane);
func2()
'Person named Jane'
1.14.4、方法中的函数

所有函数都有其特殊的this变量。如果在方法中有嵌套函数,在嵌套函数内部不能访问方法中的this变量。

var jane = {
	name: 'Jane',
	friends:['Tarzan', 'Cheeta'],
	logHiToFriends: function(){
		'use strict';
		this.friends.forEach(function (friend){
			// 'this' is undefined here
			console.log(this.name+'says hi to '+friend);
		})
	}
}

调用logHiToFriends会产生一个错误:

jane.logHiToFriends()
TypeError:Cannot read property 'name' of undefined

解决方法:
1、将this保存在不同的变量中
2、利用forEach的第二个参数,给this指定一个值

1.14.5、构造函数:对象工厂

继承
除了“真正的”函数和方法,函数在JavaScript中还扮演了另一个角色:如果用new运算来调用的话,它们将变成构造函数即对象工厂。
构造函数的名称以大写字母开头

// Set up instance data
function Point(x, y){
	this.x = x;
	this.y = y;
}
// Methods
Point.prototype.dist = function(){
	return Math.sqrt(this.x*this.x + this.y*this.y)
}

构造函数包含两部分:
1、Point设置实例数据(实例数据特定于每一个实例)
2、Point.prototype属性包含一个带有方法的对象(所有实例共享)
new

var p = new Point(3, 5);
console.log(p.x)    // 3
console.log(p.dist)    // 5.83
p instanceof Point    // true

p是Point的一个实例

1.15、数组

通过证书索引从0开始被访问。

1.15.1、数组字面量

创建数组

var arr = ['a', 'b', 'c']

整数索引访问和修改

arr[0]    // 'a'
arr[0] = 'x'    // ['x', 'b', 'c']

length:数组有多少元素,添加或删除元素

var arr = ['a', 'b'];
arr.length    // 2

arr[arr.length] = 'c'
arr    // ['a', 'b', 'c']
arr.length    // 3

arr.length = 1;
arr    // ['a']

in 操作符

var arr = ['a', 'b', 'c'];
1 in arr    // is there an element at index 1?  true
5 in arr    // is there an element at index 5?  false

数组是对象,拥有对象属性

var arr = []
arr.foo = 123;
arr.foo    // 123 
1.15.2、数组方法
var arr = ['a', 'b', 'c'];

arr.slice(1,2)    // copy elements    ['b']
arr.slice(1)    // ['b', 'c']

arr.push('x')    // append an element  ['a', 'b', 'c', 'x']

arr.pop()    // remove last element  ['a', 'b', 'c']

arr.shift()    // remove first element  ['b', 'c']

arr.unshift('x')    // prepend an element  ['x', 'b', 'c']

arr.indexOf('b')    // find the index of an element    1
arr.indexOf('y')    // -1

arr.join('-')    // all elements in a single string 'x-b-c'
arr.join('')    // 'xbc'
arr.join()    // 'x,b,c'    
1.15.3、遍历数组

迭代元素,forEach 和 map
forEach将当前元素和元素的index扔到一个函数中:

['a', 'b', 'c'].forEach(
	function (elem, index){  //1
		console.log(index+'. '+elem);
	}
)

1处参数可以被忽略,只包含一个elem参数
map通过应用一个函数映射到现有的数组的每个已经存在的元素创建一个新的数组:

[1, 2, 3].map(function(x) {return x*x})    // [1, 4, 9]

1.16、正则表达式

使用斜线分割:

/^abc$/
/[A-Za-z0-9]+/
1.16.1、test()方法:匹配吗
/^a+b+$/.test('aaab')    // true
/^a+b+$/.test('aaa')    // false
1.16.2、exec()方法:匹配以及捕获分组
/a(b+)a/.exec('_abbba_aba_')    // ['abbba', 'bbb']
1.16.3、replace()方法:搜索和替换
'<a> <bbb>'.replace(/<(.*?)>/g, '[$1]')    // '[a] [bbb]'

replace的第一个参数必须是一个带着/g标志的正则表达式;否则将只替换第一次出现的内容。

1.17、Math

Math.abs(-2)    // 2

Math.pow(3, 2)    // 3 to power of 2    9

Math.max(2, -1, 5)    // 5

Math.round(1.9)    // 2

Math.PI  // pre-defined constant for n    3,1415926

Math.cos(Math.PI)    // compute the cosine for 180°   -1

1.8、标准库的其他功能

Date:日期构造器
JSON:解析和生成JSON数据的对象
console.*:

2、背景

2.1、JavaScript可以自由使用吗

2.2、JavaScript优雅吗

2.3、JavaScript有用吗

2.3.1、图形用户界面

HTML5

2.3.2、其他技术补充完善JavaScript

(1)类库
(2)Node.js
编写服务端代码及Shell脚本
(3)JSON
(4)NoSQL数据库

2.4、JavaScript有什么好用的工具吗

2.5、JavaScript是否足够快

  • asm.js
  • ParallelJS

2.6、JavsScript是广泛使用的吗

2.7、JavaScript有前途吗

3、JavaScript的性质

(1)它是动态的
(2)它是动态类型
变量和属性值可以保存任意类型
(3)它是函数式和面向对象的
支持两种范式:函数式编程(一类函数、闭包、部分程序通过bind()、数组对象内建map()以及reduce()等)以及面向对象编程(可变状态、对象、继承等)。
(4)它静默失败
(5)它部署的是开源代码
(6)它是网络平台的一部分

3.1、古怪和非官方特性

没有块级作用域的变量,没有内建模块,没有对子类化的支持

3.2、优雅部分

一类函数
闭包
原型
对象直接量
数组直接量

3.3、影响

在这里插入图片描述

4、JavaScript是如何创造出来的

5、标准化ECMAScript

6、JavaScript的历史里程碑

3、深入JavaScript

7、JavaScript的语法

7.1、语法概览

7.2、注释

7.3、表达式与语句

7.4、控制流语句和块

7.5、使用分号的规则

7.5.1、以块结束的语句后面没有分号
  • 循环语句:for, while(不包括do-while)
  • 分支语句:if, switch, try
  • 函数声明语句
7.5.2、空语句

分号本身是一条空语句,什么也不做。
下两条语句是等价的:

while(processNextItem() > 0);
while(processNextItem() > 0){}
7.5.3、自动分号插入

自动分号插入(ASI)的目标是使分号对行结束来说是可选的。

  • 行结束符后(如换行符)跟着一个非法的token。
  • 遇到一个结束的花括号。
  • 文件已达结尾。

陷阱:ASI会出乎意料地破坏语句

return
{
	name: 'John'
};

转换

return;
{
	name: 'John'
};

陷阱:ASI可能不按预期触发

7.6、合法标识符

7.7、数字字面量的方法调用

不可以写

1.toString()

可以写

1..toString()
1 .toString()    // space before dot
(1).toString()
1.0.toString()

7.8、严格模式

7.8.1、启用严格模式
7.8.2、严格模式:建议与注意事项
7.8.3、严格模式中,变量必须被声明

严格模式:所有变量都必须被显示声明
宽松模式:未显示声明的变量将会创建一个全局变量

7.8.4、严格模式下的函数

函数必须在作用域的顶部声明

function strictFunc(){
	'use strict';
	{
		// SyntaxError:
		function nested(){
		}
	}
}

上面代码无效,因为函数需要被创建于包围函数的作用域值,而不是块内。
可以通过一个变量声明和函数表达式在块中创建函数:

function strictFunc() {
	'use strict';
	{
		// OK
		var nested = function(){
		};
	}
}

更严格的函数参数规定
arguments对象拥有更少的属性
无方法的函数中this的值为undefined
宽松模式,无方法的函数中this的值会指向全局对象(在浏览器中是指window)

function sloppyFunc(){
	console.log(this === window);  // true
}

严格模式,是undefined

function strictFunc(){
	'use strict';
	console.log(this === undefined);  // true
}

7.8.5、严格模式中,设置或者删除不可改变的属性会抛出异常

严格模式,对属性的非法操作会抛出异常。例如,对于只读属性的设定操作会抛出异常,同理不可以删除不可设置属性

var str = 'abc';
function sloppyFunc(){
	str.length = 7;  // no effect, silent failure
	console.log(str.length);  // 3
}
function strictFunc() {
	'use strict';
	str.length = 7; //TypeError: Cannot assign to read-only property 'length'
}
7.8.6、严格模式中的不合格标识符不能删除

宽松模式,删除全局变量foo:

delete foo

严格模式:删除全局变量

delete window.foo;  // browsers
delete global.foo;  // Node.js
delete this.foo;  // everywhere(in global scope)
7.8.7、严格模式中,eval更加简洁

要执行的字符串中声明的变量将不会添加到eval()所在的作用域中。

7.8.8、严格模式中禁用的特性
  • with语句不能再被调用
  • 没有八进制数字

8、值

8.1、JavaScript中的类型体系

8.1.1、JavaScript类型

ECMAScript语言类型:

  • Undefined,Null
  • Boolean,String,Number
  • Object
8.1.2、静态与动态

静态:编译时、非运行时
动态:运行时

8.1.3、静态类型与动态类型
8.1.4、静态类型检查和动态类型检查
8.1.5、强制转换

8.2、原始值和对象

8.2.1、原始值

(1)按值进行比较:
内容比较

3 === 3  // true
'abc' === 'abc'  // true

(2)不可改变
其属性不能被改变、添加或移除:

var str = 'abc';
str.length = 1;  // try to change property 'length'
str.length  // => no effect  3
str.foo = 3;  // try to create property 'foo'
str.foo  // => no effect, unknown property  undefined

读取一个未知属性时,总会返回undefined
(3)固定类型的组合
不能自定义原始值

8.2.2、对象
  • 简单
{
	firstName: 'Jane',
	lastName: 'Doe'
}
  • 数组
['apple', 'banana', 'cherry']
  • 正则表达式
/^a+b+$/

特点:
(1)按引用进行比较
每个值都有各自的身份标识,比较引用时会比较对象的身份标识:

{} === {}  // two different empty objects  false

(2)默认可变
对象属性可以很自由地被改变、添加和移除:通过固定键值访问属性
(3)用户可扩展
构造函数(实例工厂)可以被看作是自定义类型的补充

8.3、undefined和null

  • undefined 没有值----删除一个对象属性或者数组元素
  • null 没有对象----将属性或者元素设置为空
8.3.1、undefined和null的出现场景

undefined出现的场景

  • 未初始化的变量是undefined
  • 如果访问一个不存在的属性,会返回undefined
  • 如果函数中没有显示地返回任何值,函数会隐式返回undefined

null的出现场景

  • null是原型链最顶端的元素
  • 当字符串中没有匹配到正则表达式的结果
8.3.2、检测undefined和null

检测null

if( x === null )...

检测undefined

if( x === undefined )...

检测undefined或null

// Does x have a value?
if( x !== undefined && x !== null ){
	...
}
// Is x a non-value?
if( x === undefined || x === null ){
	...
}

利用undefined和null都可被认为false的特性

8.3.3、undefined和null的历史

null在强制转换为数字时会变为0

Number(null)  // 0
5 + null  // 5
  • 这个值不应该具有指向性,因为它表达的不仅仅是一个对象
  • 这个值得强制转换不应该为0,因为这会使错误难以发现
    undefined强制转换为NaN
Number(undefined)  // NaN
5 + undefined  // NaN
8.3.4、修改undefined

两种技巧防止改变undefined
(1)技巧一
隐藏全局undefined(因为它可能是错误的值)

(function (undefined){
	if(x === undefined) ... //safe now
}());  // don't hand in a parameter

在上面的代码中,undefined保证会是正确的值,因为它的值不是由函数调用时所提供的。
(2)技巧二
和’void 0’进行比较,'void 0’总是undefined

if(x === void 0)  // always safe

8.4、原始值的包装对象

布尔值、数字、字符串====构造函数=>Boolean、Number、String

  • 作为构造函数,它们创建的对象和它们包装的原始值有很大的不同
typeof new String('abc')    // 'object'
new String('abc') === 'abc'    // false
  • 作为函数,它们会将值转换为相应的原始值
String(123)    // '123'
8.4.1、包装对象不同于原始值

原始值(比如’abc’)从根本上与包装实例有很大差别(比如new String(‘abc’))

typeof 'abc'  // a primitive value    'string'
typeof new String('abc')  // an object
'abc' instanceof String  // never true for primitives
'abc' === new String('abc')    // false

包装实例是对象,而在js中没有比较对象的方法

var a = new String('abc');
var b = new String('abc');
a == b    // false
8.4.2、原始值的包装与去包装

对原始值增加属性

new Boolean(true)
new Number(123)
new String('abc')

调用valueOf()对原始值进行去包装

new Boolean(true).valueOf()    // true
new Number(123).valueOf()    // 123
new String('abc').valueOf()    // 'abc'

将包装对象转换为原始值时只能正确地提取出数字和字符串,而布尔值不能。

Boolean(new Boolean(false))  // does not unwrap    true
Number(new Number(123))    // unwraps  123
String(new String('abc'))    // unwraps  'abc'
8.4.3、原始值从包装器借调方法

原始值没有私有方法,但是它们会从各自的包装器中借调方法:

'abc'.charAt === String.prototype.charAt    // true

宽松模式,原始值会在运行过程中转换为包装器。
严格模式,对包装器原型方法的调用是透明的。

8.5、强制类型转换

8.5.1、强制类型转换会隐藏bug
8.5.2、转换成布尔值、数字、字符串和对象的函数

假值:

  • undefined、null
  • false
  • 0,NaN
  • ‘’
    真值:
    其他值
8.5.3、算法:ToPrimitive()----将值转换为原始值
ToPrimitive(input, PreferredType?)

可选参数PreferredType表明转换后的类型:它可以是Number或String,具体取决于ToPrimitive的结果是希望转换成数字还是字符串。
(1)如果input是原始值,返回这个值
(2)否则,如果input是对象,调用input.valueOf()。如果对象是原始值,返回结果。
(3)否则,调用input.toString()。如果结果是原始值,返回结果。
(4)否则,抛出一个TypeError(说明将输入转换为原始值出错了)

9、运算符

9.1、运算符和对象

大部分运算符只对原始值有效,对象在运算之前会被转换为原始值。

[1, 2] + [3]    // '1,23'
String([1,2])    // '1,2'
String([3])    // '3'

9.2、赋值运算符

x = value     // 给前面已声明的变量x赋值
var x = value    // 在声明变量的时候直接赋值
obj.propKey = value    // 设置属性
obj['propKey'] = value    // 设置属性
arr[index] = value    // 设置数组元素
x = y = 0    // 链式赋值

复合赋值运算符

  • 算术运算符:*=, /=, %=, -=
  • 位运算符:<<=, >>=, >>>=, &=, ^=, |=
  • 字符拼接:+=

9.3、等号运算符:= = = 和 = =

9.3.1、严格相等(= = = 和 != =)

不同类型的值总是严格不等的。如果两个值的类型相等,则会进行如下的情况。

  • 是否为 undefined === undefined 的比较。
  • 是否为 null === null 的比较。
  • 比较两个数字。
x === x    // unless x is NaN
+0 === -0
NaN !== NaN    // read explanation that follows
  • 比较两个布尔值,两个字符串:结果显而易见。
  • 比较两个对象(包括数组和函数):当且仅当x和y是同一个对象时,x === y。如果想比较两个不同的对象,则需要自己实现一个比较算法。
  • 其他比对:不严格相等
    陷阱:NaN
    特殊数字NaN和本身不相等。
NaN === NaN    // false

严格不等(!==)

x !== y
// 等价
!(x === y)
9.3.2、普通(宽松)相等(==,!=)

如果两个运算数的类型相同(六种规范类型:Undefined、Null、Boolean、Number、String、Object)
1、undefined 和 null,宽松相等

undefined == null    // true

2、一个字符串和一个数字,则将字符串转换为一个数字,使用严格相等比较两个运算数。
3、一个布尔值和一个非布尔值,则将布尔值转换为一个数字,然后(再次)进行宽松比较。
4、一个对象和一个数字或者一个字符串,则尝试转换此对象为一个原始值
宽松不等(!=)

x != y
// 等价于
!(x == y)

陷阱:宽松相等和布尔转换不同

2 == true    // 2 === 1  false
2 == false    // 2 === 0  false
1 == true    // 1 === 1  true
0 == false    // 0 === 0  true

虽然空字符串等于false,但不是所有的非空字符串都等于true:

'' == false    // 0 === 0    true
'1' == true    // 1 === 1    true
'2' == true    // 2 === 1    false
'abc' == true    // NaN === 1    false

陷阱:宽松相等中的字符串

'abc' == new String('abc')  // 'abc' == 'abc'  true
'123' == 123  // 123 === 123  true
'\n\t123\r' == 123 // usually not OK  true
'' == 0  // 0 === 0    true

陷阱:宽松相等中的对象
如果比较对象和非对象,它们会被转换为原始值

{} == '[object Object]'    // true
['123'] == 123    // true
[] == 0    // true

只有两个对象是同一个对象时才会相等,无法真正比较两个包装对象。

new Boolean(true) === new Boolean(true)    // false
new Number(123) === new Number(123)    // false
new String('abc') === new String('abc')    // false
9.3.3、没有针对==的有效用例

用例:检测undefined或null
用例:字符串中的数字
用例:比较包装实例和原始值

9.4、排序运算符

9.5、加号运算符(+)

9.6、布尔运算符和数字运算符

9.7、条件运算符

9.7.1、条件运算符(?:)

《condition》?《if_true》:《if_else》
var x = (obj ? obj.prop : null)

9.7.2、逗号运算符
9.7.3、void运算符

(1)void 0 等同于 undefined
(2)避免表达式返回结果
(3)用作IIFE的前缀
(4)为什么会有void运算符

9.8、通过typeof和instanceof判断值类型

9.8.1、typeof:判断原始值
9.8.2、instanceof:检测对象是否给定构造函数的实例

9.9、对象运算符

new----调用一个构造函数

new Point(3, 5)

delete----删除一个属性

delete obj.prop

in----遍历和检测属性,检测一个对象是否包含一个给定的属性

'prop' in obj

10、布尔类型

10.1、转换成布尔值

Boolean(value)  // (Invoked as a function, not as a constructor)
value ? true : false
!!value  // A single "not" converts to negated boolean; use twice for the nonnegated conversion
10.1.2、真值和假值

陷阱:所有的对象都是真值

Boolean(new Boolean(false))    // true
Boolean([])    // true
Boolean({})    // true

10.2、逻辑运算符

10.2.1、二元逻辑运算符:与(&&)和或(||)

(1)值保留
总是返回其中的一个运算数,且不改变它的值
(2)短路
如果第一个运算数以及决定结果,则不在求第二个运算数的值

10.2.2、逻辑与(&&)
10.2.3、逻辑或(||)

示例1:参数的默认值
示例2:属性的默认值
示例3:函数结果的默认值

10.2.4、逻辑非(!)

10.3、等号运算符、排序运算符

10.4、Boolean函数

11、数字

11.1、数字字面量

11.1.1、说明
11.1.2、在字面量上调用方法

11.2、转换成数字

11.2.1、手动转换为数字

两种将任意值转换为数字
Number(value)
+value

11.2.2、parseFloat()

11.3、特殊的数字值

11.3.1、NaN

错误值NaN(not a number)是一个数字

typeof NaN   // 'number'

陷阱:检查一个值是否是NaN

NaN === NaN    // false

[NaN].indexOf(NaN)    // -1

Array.prototype.indexOf也使用了严格相等(===),因此不能通过该方法在数组中查找NaN。
如果想要检查一个值是否为NaN,全局函数isNaN():

isNaN(NaN)    // true
isNaN(33)    // false
11.3.2、Infinity

错误:巨大的数字
错误:被0除
检查Infinity
全局函数isFinite()可以检查一个值是否是实际的值(既不是Infinity,也不是NaN)

11.3.3、两个0

+0 和 -0 数值和符号是分开存储的

11.4、数字的内部表示

js的数字是64位精度的,也叫作双精度(double类型)

符号指数[-1023,1024]分数
占1位占11位占52位
第63位第62~52位第52~0位

一个数字的值根据如下方程计算得到
(-1)sign x %1.fraction x 2 exponent
前置的百分号(%)代表中间的数字采用二进制计数法编写:一个1,后面是一个二进制的点,跟着一个二进制的分数----也就是分数(一个自然数)的二进制数字。
特殊的指数
e的范围是 -1023<e<1024(不包括上下界)

  • 1024是给错误值用得,比如NaN和Infinity。
  • -1023是给这些值用的:
    ----0
    ----接近0的很小的数字

11.5、处理舍入错误

1.6、JavaScript中的整形

11.6.1、整型的范围
  • 安全整型,js支持的最长的实用整型范围:53位加一个符号( − 2 5 3 -2^53 253 2 5 3 2^53 253
  • 数组索引
    32位无符号
    最大长度:2的32 - 1
    索引范围:[0, 2 3 2 − 1 2^32 - 1 2321]
  • 按位运算符
    无符号右移运算符(>>>):32位,无符号,范围[0,2的32次方]
    其他的所有按位运算符:32位,含一个符号,范围 [ − 2 3 1 , 2 3 1 ] [-2^31, 2^31] [231,231]
  • “字符码”,UTF-16码以数字组成单元:
    可以被String.fromCharCode()接受
    可以被String.prototype.charCodeAt()返回
    16位,无符号
11.6.2、将整型表示位浮点数字
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值