第一遍囫囵吞枣,不求甚解,感觉恍然大悟,结果晚上睡觉一想发现很多问题,什么都不明白,再看第二遍,发现原来是这样。过了几天一用,发现手写起来原来还是在凭记忆,于是下一遍,下一遍...
单凭记忆去弄清楚东西很不靠谱,时间一长脑袋空白。特别是技术上的很多思想和原理,只看不练,即便当时想得特别清楚,过久了也会忘。再者就是网上一些东西,只能说是提供了一种便捷的查看途径,事后还是自己总结为好,毕竟大多都是个人总结,一些概念很难讲的很清楚,而且两个人谈同一件事情,一般说的步骤和章节都是不同的,这样很容易形成交叉记忆,越多交叉记忆越混乱。还是持怀疑的态度看东西好一点,动手试一下就知道到底是怎么个样子,知识串一下。高质量有保证的书或者官方的有些东西,是不错的来源。
趁自己这会看得还算明白,脑袋还算清楚,记录一下,做个备忘。概念性的东西是书上的,减少日后误导。例子手写加验证,再画个图,以便以后一看就明白。
一、封装
对象定义:ECMA-262把对象定义为:“无序属性的集合,其中属性可以包括基本值、对象或者函数”。
创建对象:每个对象都是基于一个引用类型创建的,这个引用类型可以是原生类型(Object, Array, Date, RegExp, Function, Boolean, Number, String),也可以是自定义类型。
1、构造函数模式
复制代码 代码如下:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
}
}
通过以上构造函数使用new操作符可以创建对象实例。
var zhangsan = new Person('zhangsan', 20);
var lisi = new Person('lisi', 20);
zhangsan.sayName();//zhangsan
lisi.sayName(); //lisi
通过new创建对象经历4个步骤
1、创建一个新对象;[var o = new Object();]
2、将构造函数的作用域赋给新对象(因此this指向了这个新对象);[Person.apply(o)] [Person原来的this指向的是window]
3、执行构造函数中的代码(为这个新对象添加属性);
4、返回新对象。
通过代码还原new的步骤:
复制代码 代码如下:
function createPerson(P) {
var o = new Object();
var args = Array.prototype.slice.call(arguments, 1);
o.__proto__ = P.prototype;
P.prototype.constructor = P;
P.apply(o, args);
}
测试新的创建实例方法
var wangwu = createPerson(Person, 'wangwu', 20);
wangwu.sayName();//wangwu
2、原型模式
原型对象概念:无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。而通过这个构造函数,可以继续为原型对象添加其他属性和方法。创建了自定义的构造函数后,其原型对象默认只会取得 constructor 属性;至于其他方法,则都从 Object 继承而来。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版管这个指针叫 [[Prototype]] 。脚本中没有标准的方式访问 [[Prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于示例和构造函数的原型对象之间,而不是存在于实例和构造函数之间。
这段话基本概述了构造函数、原型、示例之间的关系,下图表示更清晰
复制代码 代码如下:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.country = 'chinese';
Person.prototype.sayCountry = function() {
alert(this.country);
}
var zhangsan = new Person('zhangsan', 20);
var lisi = new Person('lisi', 20);
zhangsan.sayCountry(); //chinese
lisi.sayCountry(); //chinese
alert(zhangsan.sayCountry == lisi.sayCountry); //true
注意地方:构造函数的原型对象,主要用途是让多个对象实例共享它所包含的属性和方法。但这也是容易发生问题的地方,如果原型对象中包含引用类型,那么应引用类型存的是指针,所以会造成值共享。如下:
复制代码 代码如下: