JS权威指南
-
书中错误
- p161,
isArray
函数中的Function.isArray => Array.isArray
- p161,
--- 对象 ---
对象属性
- constructor
constructor
指代创建这个对象的构造函数;
对象方法
- obj.hasOwnProperty('x')
检测指定的名字是否为对象的自有属性
- Object.keys(o)
keys()
返回对象o
所有自有属性的名称组成的数组
- Object.getOwnPropertyNames(o)
返回对象
o
所有自有属性的名称(包括不可枚举属性)组成的数组
- Object.getOwnPropertyDescriptor({x: 1}, 'x')
返回对象特定属性的属性描述符
- Object.defineProperty(o, 'x', {get: function () { return 2 } } )
设置属性的特性
- Object.create()
创建一个拥有指定原型和若干个指定属性的对象
- Object.prototype.isPrototypeOf(o)
检测一个对象是否是另一个对象的原型
- Object.isExtensible(o)
判断对象是否可以扩展
- Object.preventExtensions(o)
可将对象设置为不可扩展
- Object.seal(o)
将当前已有的
configurable
设置为false
(不可删除,但可写,也可转换为只读)
- Object.freeze(o)
将当前对象冻结(
configurable、writable
都会被设置为false
)
- getPrototypeOf(o)
返回指定对象的原型
三类javascript对象
- 内置对象(数组,函数,日期和正则)是由
ECMAscript
定义的对象或类; - 宿主对象是由js解释器所嵌入的宿主环境定义的;
- 自定义对象是由运行中的
js
代码创建的对象;
判断对象的类型
var toString = Object.prototype.toString;
function getType(obj){
return toString.call(obj).slice(8, -1);
}
// ---eg---:
var o = {};
getType(o); //"Object"
//简便方式
[].toString.call(5).slice(8, -1) // 'Number'
对象特性
- 对象的原型指向另外一个对象,本对象的属性继承自它的原型对象;
- 对象的类
class
是一个标识对象类型的字符串; - 对象的扩展标记指明了是否可以向该对象添加新属性;
对象的三个属性
- 原型
prototype
:原型属性是用来继承属性的 - 类
class
- 可扩展性
extensible attribute
var p = {x: 1};
var o = Object.create(p);
Object.prototype.isPrototypeOf(o);
两类属性
- 自有属性是直接在对象中定义的属性;
- 继承属性是在对象的原型对象中定义的属性;
对象属性特性
- 可写
writable attribute
,表明是否可以设置该属性的值; - 可枚举
enumerable attribute
,表明是否可以通过for/in
循环返回该属性。当值为false
时,Object.keys(obj)
,该属性不会被列出。 - 可配置
configurable attribute
,表明是否可以删除或修改该属性;
通过原型继承创建对象
function inherit (p) {
if(p == null) throw TypeError();
if(Object.create) return Object.create(p);
var t = typeof p;
if(t !== 'object' && t !== 'function') throw TypeError();
function f(){};
f.prototype = p;
return new f();
}
属性检测
- 通过
in
操作符,此方法适合明确要查找的属性时使用(会查找原型链);
var o = { x: 1 };
'x' in o; // => true,存在自有属性x
'y' in o; // => false,自有属性和继承属性都没找到'y'
'toString' in o; // => true,存在继承属性'toString'
-
hasOwnProperty()
方法可以检测是否为该对象的自有属性(不会查找原型链);
var o = { x: 1 };
o.hasOwnProperty('x'); // => true,存在自有属性
o.hasOwnProperty('y'); // => false, 不存在自有属性'y'
o.hasOwnProperty('toString'); // => false,不存在自有属性'toString'
-
propertyIsEnumerable()
方法为hasOwnProperty()
的增强版,在检测是否为自有属性的同时还要检测该属性的可枚举性;
var o = inherit( { y: 2 } );
o.x = 1;
o.propertyIsEnumerable( 'x' ); // => true,'x'是可枚举的自有属性
o.propertyIsEnumerable( 'y' ); // => false,'y'不是自有属性
Object.prototype.propertyIsEnumerable( 'toString' ); // => false,'toString'不可枚举
属性的特性
- 数据属性特性:
- value(值)
- writable(可写性)
- enumerable(可枚举性)
- configurable(可配置性)
- 存取器属性特性
- get(读取)
- set(写入)
- enumerable
- configurable
对象序列化
- 序列化后传至后端(属性为
undefined
时,序列化会忽视该属性)
var obj = {
x: undefined,
y: true,
z: [1, 2, 3],
nullVal: null
};
JSON.stringify(obj); //"{"y":true,"z":[1,2,3],"nullVal":null}"
-
JSON
数据转换为js对象
var obj = JSON.parse('{"x": 1}');
- 自定义序列化(方法名必须为
toJSON
)
var obj = {
x: 1,
y: 2,
o: {
o1: 1,
o2: 2,
toJSON: function(){
return this.o1 + this.o2;
}
}
}
JSON.stringify(obj); //"{"x":1,"y":2,"o":3}"
--- 数组 ---
属性
length返回数字的长度
方法
第13条以后的为ES5新增方法,它们都不修改原数组
- join()
以传入的参数为分隔符拼接数组元素,返回生成的字符串(不修改原数组)
- reverse()
颠倒数组元素顺序,返回倒序后的数组(修改原数组)
- sort()
排序数组元素,如数组包含undefined值,则将其排至数组末尾,返回排序后的数组(修改原数组)
- 比较函数:
arr.sort( function( a, b ) { return a - b; } //从小到大排序 arr.sort( function( a, b ) { return b - a; } //从大到小排序
- concat()
合并传入的数组元素,返回合并的新数组(不修改原数组)
- slice()
截取数组元素,返回由截取元素组成的新数组(不修改原数组)
- splice()
插入或删除数组元素,返回由删除的元素组成的新数组(修改原数组)
- 删除操作(参数①为要删除的起始下标,参数②为要删除的项数)
var a = [1, 2, 3]; a.splice(0, 1); // => [1], a为[2, 3]
- 插入操作(参数①指定插入位置,参数②为0,参数③为插入项)
var a = [1, 2, 3]; a.splice(1, 0, 4, 5); // => [], a为[1, 4, 5, 2, 3]
- 替换操作(参数①起始下标,参数②为删除的项数,参数③为插入项)
var a = [1, 2, 3]; a.splice(1, 1, 4); // => [2], a为[1, 4, 2, 3]
- push()
在数组的尾部添加一个或多个元素,返回插入元素后数组的
length
值(修改原数组)
- pop()
删除数组最后一个元素,返回删除的元素(修改原数组)
- unshift()
在数组的头部添加一个或多个元素,返回插入元素后数组的
length
值(修改原数组)
- shift()
删除数组头部的一个元素,返回删除的元素(修改原数组)
- toString()
将数组每个元素转化为字符串,用逗号拼接,并输出(类似调用元素的
toString()
方法)
- toLocalString()
类似
toString()
方法,只是拼接方式使用本地化分隔符代替
- forEach()
从头至尾遍历数组,为每个元素调用指定的函数
- map()
返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组
- filter()
使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组
- every()
测试数组的所有元素是否都通过了指定函数的测试,都通过才返回
true
- some()
测试数组中的某些元素是否通过了指定函数的测试,有一项返回
true
则返回true
- reduce()
接收一个函数作为累加器,数组中的每个值(从左到右)开始合并,最终为一个值
- reduceRight()
接受一个函数作为累加器,让每个值(从右到左,亦即从尾到头)缩减为一个值。(与
reduce()
的执行方向相反)
- indexOf()
返回给定元素能找在数组中找到的第一个索引值,否则返回 -1(从头至尾开始查找)
- lastIndexOf()
返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1(从尾至头开始查找)
数组检测
- ES5方法
Array.isArray([]) // true
- 兼容处理
var isArray = Array.isArray || function(o) { return typeof o === 'object' && Object.prototype.toString.call(o).slice(8, -1) === 'Array'; };
类数组对象
常见的类数组对象有DOM操作返回的NodeList集合,以及函数内部的arguments对象
将类数组转化为数组的方法:
//方法一:
var args = Array.prototype.slice.call(arguments);
//方法二:
var args = [].slice.call(arguments);
//方法三:
var args = Array.from(arguments);
计算亮点之间的距离
function Point(x, y){
this.x = x;
this.y = y;
}
Point.prototype.r = function () {
return Math.sqrt(this.x * this.x + this.y * this.y);
};
var p = new Point(1, 1);
跳转至淘宝
function moveon () {
var answer = confirm('准备好了嘛?');
if (answer) location = 'http://taobao.com';
}
setTimeout( moveon, 1000 );
兼容bind方法
if(!Function.prototype.bind){
Function.prototype.bind = function(o /*, args */){
var self, boundArgs;
self = this;
boundArgs = arguments;
return function(){
var args, i;
args = [];
for(i = 1; i < boundArgs.length; i++) args.push(bounddArgs[i]);
for(i = 0; i < arguments.length; i++) args.push(arguments[i]);
}
}
}
输出调试消息至页面
function debug (msg) {
var log = document.querySelector('#debuglog');
if (!log) {
log = document.createElement('div');
log.id = 'debuglog';
log.innerHTML = '<h1>Debug log</h1>';
document.appendChild(log);
}
var pre = document.createElement('pre');
var txt = document.createTextNode(msg);
pre.appendChild(txt);
log.appendChild(pre);
}
对象转到数字
- 空数组转数字为什么为 0
-
中间的转换过程(对象转数字):
//首先调用对象的valueOf()方法 var arr = []; //如果对象存在valueOf方法并返回一个原始值 arr.valueOf(); // => 空数组对象自身 //否则,如果对象具有toString()方法: arr.toString(); // => "" //如果toString()方法返回一个原始值,则将其转换为数字 Number(""); // => 0 //否则抛出一个类型错误
- 具有一个元素的数组(值为数字)转换为数字
-
转换过程:
//首先调用对象的valueOf()方法 var arr = [9]; //如果对象存在valueOf方法并返回一个原始值 arr.valueOf(); // => 数组对象自身 /否则,如果对象具有toString()方法: arr.toString(); // => "9" //如果toString()方法返回一个原始值,则将其转换为数字 Number("9"); // => 9 //否则抛出一个类型错误
- 具有一个元素的数组(值为字符串)转换为数字
-
转换过程
//首先调用对象的valueOf()方法 var arr = ['one']; //如果对象存在valueOf方法并返回一个原始值 arr.valueOf(); // => 数组对象自身 /否则,如果对象具有toString()方法: arr.toString(); // => "one" //如果toString()方法返回一个原始值,则将其转换为数字 Number("9"); // => NaN //否则抛出一个类型错误
对象转换到字符串
同对象转到数字过程,只是先进行
toString
操作,再进行valueOf
操作;
delete运算符
- 用来删除对象属性或者数组元素(不能删除通过
var
声明的变量); - 再次访问被删除对象属性或数组元素时,返回
undefined
; -
delete
操作不改变数组的长度; - 可以通过
in
操作符检测属性是否存在; - 只会断开属性和对象之间的联系,而不回去操作属性中的属性(见示例5);
var obj = {
one: 'one',
two: 'two'
};
delete obj.one;
'one' in obj; // => false
console.log(obj.one); // => undefined
var arr = [1, 2, 3];
delete arr[0];
console.log(1 in arr);
console.log(arr[0], arr.length); // => undefined 3
// 示例5
var a = { p: { x: 1 } };
var b = a.p;
delete a.p;
console.log(b.x); // => 1 ,该p属性下的x属性依然可以访问到;
eval()
-
eval()
只有一个参数;- 如果传入的参数不是字符串,则直接返回这个参数;
- 如果传入的值为字符串,则字符串会被当初
js
代码进行编译;- 编译失败会抛出语法错误;
- 成功则开始执行代码,并返回字符串中的最后一个表达式或语句的值;
- 如果最后一个表达式或语句没有值,则最终返回
undefined
;
eval()
具有改变局部变量的能力;
此处直接调用了
eval()
,因此它总是在调用它的上下文作用域内执行(即与普通代码执行类似);
var x = 'global';
function f () {
var x = 'local';
eval("x += ' changed';");
return x;
}
console.log(f(), x); // => 'local changed global'
- 间接调用
eval()
则不能改变局部变量和函数;
此处间接调用
veal()
,并没有改变函数内的变量y
,操作的对象为全局变量y
;
var global_eval = eval, //把eval赋值给一个全局变量保存
y = 'global';
function g () {
var y = 'local';
global_eval("y += ' changed';"); //间接调用eval()
return y;
}
console.log(g(), y); // => 'local global changed'
返回对象的类
function classof(o) {
if (o === null) return "Null";
if (o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8,-1);
}
返回函数的名字
Function.prototype.getName = function(){
if('name' in this) return this.name;
return this.toString().match(/function\s*([^(]*)\(/)[1];
}