Skip to content
Lixiang Mu edited this page Mar 8, 2014 · 3 revisions

####1. 原型式继承是javascript的核心特征

####2. javascript的对象是动态的---可以增加属性,也可以删除属性

####3. 对象最常见的用法是创建(create)、设置(set)、查找(query)、删除(delete)、检测(test)和枚举(enumerate)它的属性

####4. 对象的属性特性

  1. 是否可写
  2. 是否可枚举
  3. 是否可配置

####5. 三类对象和两类属性 三类对象

 1. 内置对象    
 2. 宿主对象  
 3. 自定义对象

两类属性

1. 自有属性  
2. 继承属性

####6. 对象的属性名可以是javascript标识符也可以是字符串直接量(包括空字符串)属性名里有连字符必须用字符串。 例: "sub-title"

####7. 对象直接量是一个表达式,这个表达式每次运算都创建并初始化一个新对象,每次计算对象直接量时,也都会计算它的每个属性的值。

####8. 对象创建的三种方式

  1. 对象直接量
  2. 关键字new与构造函数结合
  3. Object.create()

####9. 除null外,每个对象都从原型继承属性

####10. 所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过Object.prototype获得对原型对象的引用

####11. new关键字和构造函数调用创建的对象的原型就是构造函数的prototype属性的值 例: new Object() 和 {} 创建的对象均继承自 Object.prototype; new Array()的原型是Array.prototype; new Date()的原型是Date.prototype;

####12. 没有原型的对象为数不多, Object.prototype就是其中之一

####13. 所有的内置构造函数,以及大部分自定义的构造函数都具有一个继承自Object.prototype的原型

####14. Object.create() 是一个静态函数,用于创建一个新对象,参数就是要创建对象的原型 例: var p = Object.create({x:1,y:2}); //p继承了属性 x、y p.x //1 p.y //2 p的原型就是{x:1,y:2}

	创建没有原型的对象
	var q = Object.create(null);  //q不继承任何属性和方法
	创建普通的空对象
	{} 或 new Object()

	var r = Object.create(Object.prototype); 
	r和{}或new Object()创建的对象一样原型均为 Object.prototype 

####15. 通过原型继承来的属性值也是可修改的 例: var a = {x:1, y:2}; var b = Object.create(a); b.x //1 b.y //2 //修改属性值 b.x = 3; b.y = 4; a.x //1 a.y //2 b.x //3 b.y //4

注:实际是同名覆盖已继承属性

####16. 字符串是动态的,而标识符是静态的。

####17. 对象的属性访问方式有对象.标识符对象[字符串] 字符串是属性名的字符串形式。其中[字符串]可用于访问动态属性名,即运行中设定的属性名 例: function addProduct(product, name, value){ product[name] = value; }

	//对象product的属性就是动态的
	//计算product的总价
	function getTotal(product){
		var total = 0.0;
		for(var name in product){
			total += product[name];
		}
		return total;
	}

####18. 如果对象的属性名是保留字,ES3访问方式是[],ES5可用.访问

通过原型继承创建一个新对象
function inherit(p){
	if(p==null) throw TypeError();		//p是对象,不能为null
	if(Object.create()){				//如果存在 Object.create()
		return Object.create(p);		//直接使用
	}
	var t = typeof p;
	if(t!=="object" && t!=="function") throw TypeError();
	function f(){};						//定义空构造函数
	f.prototype = p;					//将f的原型属性设置为p
	return new f();						//用f()创建继承p的对象
}

####19. 对象的属性查询是依原型链进行的,对象自身没有该属性,就在查原型,原型没有,查原型的原型,直到原型为null止

####20. 给对象p的属性x赋值,

  • 若p中已有属性x,则只是改变x的值
  • 若p中没有属性x,则为p添加属性x并赋值
  • 若p继承了x(即p的原型中有x属性),则继承的属性被新创建的同名属性覆盖

####21. 属性要么赋值失败,要么创建一个属性,要么在原始对象中设置属性,javascript中只有在查询时,才能体会到继承的存在,而设置属性则和继承无关 属性安全访问

var book = {};
var b = book && book.name && book.name.length;
b的值为undefined
var person = {name: "mlx"};
var p = person && person.name && person.name.length
p的值为3

####22. 以下场景为对象p设置属性x会失败

  1. p中属性x是只读。(defineProperty()方法中有一个例外,可以对可配置的只读属性重新赋值)
  2. p中属性x是继承的且是只读的
  3. p中不存在属性x,且p是不可扩展

####23. delete运算符可以删除对象的属性,其运算结果只是断开属性和宿主对象的联系,而不会操作属性中的属性

####24. delete运算符只能删除自有属性,不能删除继承属性 例: p = {x: 1}; delete p.x; //删除属性x,返回true delete p.x; //什么也没做 (x不存在),返回true delete p.toString; //什么也没做(toString是继承来的) delete 1; //无意义 返回true

####25. delete无法删除可配置属性为false的属性 例: delete Object.prototype; //不能删除,该属性不可配置 var x=1; delete this.x //不能删除var声明的属性 function f(){} //声明一个全局函数 delete this.f //也不能删除全局函数

####26. in运算符用于检测对象中是否存在某个属性(包括自有属性和继承属性) 例: var o = {x:1}; "x" in o; //true "x"是o的属性 "y" in o; //false "y"不是o的属性 "toString" in o; //true "toString"是o继承属性

####27. hasOwnProperty()方法,用于检测给定的名称是否是对象的自有属性,对于继承属性返回false 例: var p = {x:1}; p.hasOwnProperty("x"); //true 属性x是对象p的自有属性 p.hasOwnProperty("y"); //false 对象p中不存在属性y p.hasOwnProperty("toString") //false toString是继承的属性

####28. propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到这个属性是自有属性,且是可枚举的时返回true 通常由javascript创建的对象属性都是可枚举的 例: var p = inherit({y:2}); p.x = 1; p.propertyIsEnumerable("x"); //true, p有可枚举属性x p.propertyIsEnumerable("y"); //false, y是继承的属性 Object.prototype.propertyIsEnumerable("toString"); //false, toString不可枚举

####29.!==也可判断一个属性是否是undefined(与in运算符效果类似,但无法判断值为undefined的属性) 例: var p = {x:1}; p.x!==undefined; //true,p中有属性x p.y!==undefined; //false, p中不存在属性y p.toString!==undefined; //true, p继承了toString

####30. in运算符能区分不存在的属性 和 存在但值为undefined的属性 例: var a = {x: undefined}; //x被显式的赋值为undefined a.x !== undefined; //false, 属性存在但值为undefined a.y !== undefined; //false, 属性不存在 "x" in a; //true, 属性存在 "y" in a; //false, 属性不存在 delete a.x //删除属性x "x" in a; //false, 属性不存在

####31. for/in循环可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承的属性)

####32. Object.keys()返回一个数组,该数组由对象中的可枚举的自有属性的名称组成

####33. Object.getOwnPropertyNames()返回对象所有自有属性的名称,而不仅仅是可枚举属性

####34. 示例

示例一

/*
 *把p中可枚举的属性复制到o中,并返回o
 *如果o和p中含有同名属性,则覆盖o中的属性
 *这个函数并不处理getter和setter以及复制属性
 */
function extend(o,p){
	for(prop in p){				//遍历p中的所有属性
		o[prop] = p[prop];		//将属性添加至o中
	}
	return o;
}

示例二

/*
 *把p中可枚举的属性复制到o中,并返回o
 *如果o和p中含有同名属性,o中的属性将不受影响
 *这个函数并不处理getter和setter以及复制属性
 */
function merge(o,p){
	for(prop in p){								//遍历p中的属性
		if(o.hasOwnProperty[prop]) continue;	//过滤掉已经在o中存在的属性
		o[prop] = p[prop];						//将属性添加至o中
	}
	return o;
}	

示例三

/*
 *如果o中的属性在p中没有同名属性,则从o中删除这个属性
 *返回o
 */
function restrict(o,p){
	for(prop in o){							//遍历o中所有属性
		if(!(prop in p)) delete o[prop];	//若在p中不存在,则删除之
	}
	return o;
}

示例四

/*
 *如果o中的属性在p中存在同名属性,则从o中删除这个属性
 *返回o
 */
function subtract(o,p){
	for(prop in p){					//遍历p中的所有属性
		delete o[prop];				//从o中删除(非严格模式,删除不存在属性不会报错)
	}
}

示例五

/*
 *返回一个新对象,这个对象同时拥有o的属性和p的属性
 *如果o和p中有重名属性,使用p中的属性值
 */
function union(o,p){ return extend(extend({},o),p); }

示例六

/*
 *返回一个新对象,这个对象拥有同时在o和p中出现的属性
 *很像求o和p的交集,但p中属性的值被忽略
 */
function intersection(o,p){ retrun restrict(extend({},o),p); }

示例七

/*
 *返回一个数组,这个数组包含的是o中可枚举的自有属性的名称
 */
function keys(o){
	if(typeof o !== "object") throw TypeError();	//参数必须是对象
	var result = [];								//将要返回的数组
	for(var prop in o){								//遍历所有可枚举的属性
		if(o.hasOwnProperty(prop)){					//判断是否是自有属性
			result.push(prop)						//将属性添加至数组中
		}
	}
	return result;									//返回数组
}

####35. 在ES5中属性值可以用一个或两个方法代替,gettersetter,由gettersetter定义的属性称为存取器属性

####36. 存取器属性不具有可写性,因为其是否可写取决于有没有setter方法 例: var p = { //x和y是普通可读写属性 x:1, y:1, //r是可读写的存取器属性,它有getter和setter方法 get r(){ return Math.sqrt(this.x * this.x + this.y * this.y); }, set r(newValue){ var oldValue = Math.sqrt(this.x * this.x + this.y * this.y); var ratio = newValue / oldValue; this.x *= ratio; this.y *= ratio; }, //theta是只读存取器属性,它只有getter方法 get theta(){ return Math.atan2(this.y, this.x); } }

例2: var q = inherit(p);				//创建一个继承getter和setter的新对象
	 q.x=1,q.y=1;					//给q添加两个属性
	 console.log(q.r);				//可以使用继承的存取器属性
	 console.log(q.theta);

####37. 一个属性包含一个名字和四个特性,其中属性分为数据属性和存取器属性

  • 数据属性的四个特性分为 值(value),可写性(writable),可枚举(enumerable),可配置(configurable)
  • 存取器属性不具有值特性和可写性,其可写性是由setter方法存在与否决定(get,set,enumerable,configurable)

####38. 属性描述符对象的四个属性,表示属性的特性

  • 数据属性 (value,writable,enumerable,configurable)
  • 存取器属性(get,set,enumerable,configurable)

其中 writable,enumerable,configurable为布尔值

####39. Object.getOwnPropertyDescriptor()可获得某个对象特定属性的属性描述 例: Object.getOwnPropertyDescriptor({x:1}, "x"); //属性名用字符串形式 //返回 {value: 1,writable: true,enumerable: true, configurable: true} 查询上文对象p的theta属性 Object.getOwnPropertyDescriptor(p,"theta"); //返回 {get: /func/, set:undefined, enumerable: true, configurable: true}

//对于继承属性和不存在的属性返回 undefined
Object.getOwnPropertyDescriptor({},"x");			 //undefined, 属性不存在
Object.getOwnPropertyDescriptor({},"toString");		//undefined, 继承属性

####40. 设置属性特性,或让新建属性只拥有某种特性,调用方法Object.defineProperty() 例: var o = {}; //创建一个空对象 //添加一个不可枚举属性x,并赋值为 1 Object.defineProperty(o, "x",{value: 1, writable: true, enumable: false, configurable: true}); //属性x是存在的,但不可枚举 o.x // 1 Object.keys(o); // [] //现在对属性x做修改,使其变为只读 Object.defineProperty(o, "x", {writable: false}); //试图给x赋值 o.x = 3; //操作失败,在严格模式中抛出类型错误异常 o.x; // 1 //属性依然是可配的,可通过以下方式对其值进行修改 Object.defineProperty(o, "x", {value: 2}); o.x; //2 //将x由数据属性修改为存取器属性 Object.defineProperty(o, "x", {get: function(){return 0;}}); o.x; //0

####41. Object.defineProperty()要么修改已有属性,要么新建自有属性,但不能修改继承属性

####42. 同时修改或新建多个属性,用Object.defineProperties() 第一个参数为要修改的对象,第二个参数为映射表(它包含要新建的或修改的属性名称以及他们的属性描述) 例: var p = Object.defineProperties({},{ x: {value: 1, writable: true, enumerable: true, configurable: true}, y: {value: 1, writable: true, enumerable: true, configurable: true}, r: { get: function(){return Math.sqrt(this.x * this.x + this.y * this.y)}, enumerable: true, configurable:true } }); 返回修改后的对象

####43. 任何对Object.defineProperty()Object.defineProperties()违反规则的使用都会抛出类型错误异常

  • 对象不可扩展,则不能添加新属性,但可编辑已有属性
  • 属性不可配置,则不能修改其可配置性和可枚举性
  • 存取器属性不可配置,则不能修改其getter和setter方法,也不能将其转化为数据属性
  • 如果数据属性不可配置,则不能将其转化为存取器属性
  • 如果数据属性是不可配置的,则不能将其可写性从false修改为true,但可以从true修改为false
  • 如果数据属性不可配置,不可写,则不能修改其值;然而可配置,不可写的数据属性的值是可以修改的(实际是先转化为可写,修改值,再转化为不可写)

####44. 每个对象都有与之相关的三个属性: 原型(prototype)、类(class)、可扩展性(extensible attribute)

####45. ES5中,将对象作为参数传入 Object.getPrototypeOf() 可以查询参数的原型

####46. isPrototypeOf()检测一个对象是否是另一个对象的原型 例: p.isPrototypeOf(o); //检测p是否是o的原型

####47. 通过对象直接量,Object.create() 创建的对象的类属性依然是 Object,对于自定义构造函数创建的对象类属性也是Object。内置构造函数或宿主对象均包含有意义的类属性 例: function classof(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); }

	classof(null)		//"Null"
	classof(1)			//"Number"
	classof("")			//"String"
	classof("false")	//"Boolean"
	classof({})			//"Object"
	classof([])			//"Array"
	classof(/./)		//"Regexp"
	classof(new Date())	//"Date"
	classof(window)		//"Window"(客户端宿主对象)
	function f(){}
	classof(new f())	//"Object"

####48. 对象的可扩展性是指对象是否可以添加新属性

####49. 所有内置对象和自定义对象都是显式可扩展的

####50. Object.isExtensible() 用以检测对象是否可扩展;Object.preventExtensions() 用以将对象设置为不可扩展

注意: 对象设置为不可扩展是不可逆的,即一旦设置为不可扩展将无法设置为可扩展,但Object.preventExtensions只影响对象本身的可扩展性,若给不可扩展对象的原型添加新属性,这个不可扩展的对象同样会继承这些新属性

####51. Object.seal() 设置对象为不可扩展,且对象所有自有属性不可配置,且不可逆;Object.isSealed()检测对象是否封闭

####52. Object.freeze()将对象设置为不可扩展,将其属性设置为不可配置,还将对象的自有属性设置为只读(存取器属性不受影响);Object.isFrozen()检测对象是否被冻结