javascript 高级程序设计读书笔记
javascript 高级程序设计读书笔记
面向对象
-
javascript没有类的概念,通过函数实现构造函数,通过new运算符来创建对象
function Person(name, age, job) { this.name = name; this.age = age; this.friends = ["A","B"]; this.sayname = function(){ alert(this.name); }; } var P = new Person("P",22,"coder");
-
Person与普通函数并无区别,如果直接调用则是向this(window)对象添加属性
-
用new操作符实现了4个步骤:
- 创建新对象;
- 将构造函数中的作用域赋给新对象(this指向新对象)
- 执行构造函数中的代码
- 返回新对象
-
上述方法称为构造函数模式,每一个对象互相独立,其属性和方法都独立创建,耗费空间,尤其是方法,不必要独立创建。
-
原型模式:每一个函数都有一个原型属性,默认的原型属性有一个constructor域指向函数,原型为所有函数new出的对象所共有。类似于c++中的static属性或方法。下例为推荐写法
function Person() { this.name = name; this.age = age; this.friends = ["A","B"]; } //原型模式写法1,在默认prototype上补充 Person.prototype.sayName = function() { alert(this.name); } Person.prototype.startid = 0; //共享 //写法2,覆盖默认的prototype Person.prototype = { constructor : Person, // 注意覆盖写法应加入constructor属性 sayName: function(){ alert(this.name); } startid:0 }
所有对象共享Prototype域,而构造函数里添加的域是独立的。对象构造完以后如果再给prototype中的域赋值可以将其覆盖,注意不是删除,因为如果将自己新加的delete之后,prototyoe中的就又出现了。
-
动态原型模式:在构造函数中解决原型的初始化,只有构造的第一个对象会触发if条件,填充Person的原型
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; if (typeof this.sayName != "function") { // 检查一个属性就行 Person.prototype.sayName = fuction() { alert(this.name); } Person.prototype.startid = 0; } }
-
继承——利用原型链 (不能解决所有子类原型共用一个超类实例的问题,不推荐用)
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; }; function SubType() { this.subproperty = false; } //继承 SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function() { return this.subproperty; } var instance = new SubType();
但是,由于SubType没有重定义constructor,所以继承了SuperType的constructor。但是constructor不影响instanceof
-
借用构造函数: 不是new一个父类对象,而是调用构造函数向子类添加父类的域,所以子类无法访问父类的原型中的内容,不推荐使用
function SuperType() { this.colors = ["red","blue"]; } fuction SubType() { SuperType.call(this); // 借用构造函数,在子类中再构造一次父类 }
-
组合继承:调用两次父类构造函数,效率低,此方法子类的constructor也是错的
function SuperType(name) { this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function() { alert(this.name); }; function SubType(name, age) { SuperType.call(this,name); // 借用父类构造函数 this.age = age; } SubType.prototype = new SuperType(); //原型继承 SubType.prototype.sayAge = function() { alert(this.age); }
-
寄生组合式:推荐使用,用此函数替代组合继承的的 SubType.prototype = new SuperType();
// 书中写法,constructor在原型里 function object(o) { function F(){} F.prototype = o; return new F(); } function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); //拷贝原型 prototype.constructor = subType; //添加constructor subType.prototype = prototype; //指定原型 } //网上的另一个写法, 感觉也是对的, 区别是constructor不在原型里。 SubType.prototype = SuperType.prototype; SubType.constructor = SubType;
-
有关prototype、constructor和__proto__的关系参考下面这篇文章,写的很清晰
https://blog.csdn.net/cc18868876837/article/details/81211729
-
闭包:定义在函数内的函数,内层函数拥有指向外层函数活动记录的指针,可以访问外层函数的变量。
-
私有权限:用闭包实现,有this的是公有权限,var的是非公有权限
function MyObject() { //私有变量和私有函数 var privateVariable = 10; function privateFunction() { return false; } //特权方法,外界可调用 this.publicMethod = function() { privateVariable++; return privateFunction(); } } var m = new MyObject();
静态私有:解决上述中函数不共享的问题,私有变量和prototype是共享的
(function(){ //私有 var privateVariable = 10; function privateFunction() { return false; } MyObject = function(value) { //函数中不带var的变量是全局变量 }; MyObject.prototype.publicMethod = function() { privateVariable++; return privateFunction(); }; })(); var m = new MyObject(value);