js面向对象--笔记(二)
先上张图(应该没画错吧)
以下内容参考于JavaScript高级设计程序(第三版)
创建函数的方式 1.函数表达式 var peo = function(){ name : "嗯嗯" };
2.函数声明 function Peo(name) { this.name = name; };
3.var p = new Function("a", "b", "return a + b"); (不推荐)
创建对象(new)过程:
1.在内存申请地址,存储对象
2.设置this为当前对象
3.设置属性和方法
4.返回this
// 参考高级设计139页
属性的默认特征:1.Configurable,能否delete的属性,默认为true
2.Enumerable,能否for-in的属性,默认true
3.Writeable,能否修改属性值,默认true
4.Value,该属性的数据值,默认undefined
一开始,一个一个地new对象,很麻烦,所以出现了工厂模式
工厂模式:
function my(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayHi = function() { alert("hi"); }
return o;
}
虽然工厂模式能够批量生产对象,但是用instanceOf得到的总是Objcet,但是我想要的是People、Animal这种特殊的对象
构造函数:
function People(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
alert(this.name);
}
}
但是构造函数也有缺点,就是创建出来的实例对象,如果调用sayHi这个方法,其实都不是同一个方法(虽然它们没区别),因为没创建实例对象都会在堆中开出一块内存,每个对象都有各自的sayHi方法。所以原型来了
原型
作用:共享数据、节省内存,继承
缺点:它的优点也是它的缺点,因为共享的是同一个数据,如果这个数据是引用类型的属性,实例对象1修改了引用属性,当实例对象2拿出这个引用属性是修改之后的
原型简写: People.prototype = {
constructor : People; (记得要写)
name : "哈哈";
}
注意:如果先实例对象再添加原型,你会访问不到原型里的东西,这个不难理解,因为实例时的原型没有这个属性或方法,所以报错,这里可能会疑惑,后面不是添加了原型吗?这里要借助最上面的图,创建实例对象后跟图上是一模一样的,但是当添加原型后,此时构造函数的原型对象已经是另外一个了,构造函数和实例对象原本是指向同一个但是现在各自指向各自的。(所以说为什么要先实例对象再添加原型)。
继承
1.利用原型继承
当Person原型改变了指向(指向Animal的实例对象),而Animal的实例对象又指向了Animal的原型,所以此时可以用Animal中的任何属性和方法,而原来的getName方法就访问不了,所以会报错(peo.getName())。当然如果把Peoson.prototype.getName...这行代码放到改变原型指向的代码之后(new Animal这行代码之后),就不会报错了,实际上就是给Animal原型添加一个方法,所以可以访问。注意:如果此时添加的是对象字面量(就是Peoson.prototype = { ...}),这样会覆盖new Animal这行代码。
可是这样也会有问题,如果我在后面再添加var peo1 = new Peoson("ab"); peo1.age的值也是19,无论再创建多少个实例对象,值都是一样。(也就是说改变原型的指向时把Animal中的属性都赋值了,所以继承下来的值都是相同的)。
2.借用构造函数
call(obj, "a", "b"...)
apply(obj, ["a", "b"])
这两个方法除了参数传入不同之外,没有任何区别
function test() {
result.call(this, "a"); // this(也就是test的实例对象)继承result,简单粗暴一点就是将result里的东西都搬到test里来
}
缺点跟构造函数的缺点一样,方法都不是同一个地址的
3.上面两种方法组合使用
用原型来继承方法,用借用构造函数来继承属性
4.原型式继承(Object.create())
var p = Object.create(People, { name : {value :"a"}; })
5.寄生式继承(createAnother())
var p = createAnother(People); p.sayHi = function() { alert("hi") };
6.寄生组合继承
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); // 创建对象
prototypr.constructor = subType; // 添加构造器
subType.prototype = prototype; // 改变原型
}