Open LiuL0703 opened 6 years ago
我们创建每一个函数 都有一个prototype属性 该属性指向一个对象 这个对象就是原型 我们创建一个对象时候 可以根据自己的需求 选择性的将一些方法属性通过prototype属性 挂载在原型对象上 而每一个new出来的实例都有一个proto属性 该属性指向构造函数的原型对象 通过这个属性 让实例方法能够访问 到原型对象上的这方法
当函数可以记住并访问所在的词法作用域时,就产生了闭包,这个函数持有对该词法作用域的引用,这个引用就叫做闭包 闭包本质还是函数,只不过这个函数绑定了上下文环境(函数内部引用的所有变量) 缺点:常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。 作用(使用场景):可以用来管理私有变量和私有方法,将对变量(状态)的变化封装在安全的环境中,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收
function Animals(){ this.name = ['cat','dog']; this.other = 'animals'; } function Cat(){ }; // 继承 Cat.prototype = new Animals();
var c1 = new Cat(); var c2 = new Cat();
c1.name.push('pig'); console.log(c1.name); // ["cat", "dog", "pig"] console.log(c2.name); // ["cat", "dog", "pig"]
c1.other = 'cat'; console.log(c1.other); // cat console.log(c2.name); // animals
#### 缺点: 引用类型的属性被所有实例共享 一旦修改 会反应在所以实例上 创建子类型实例时 不能向超类型传参 注:通过原型链实现继承时 不能使用对象字面量创建原型方法 因为会重写整个原型链 + ### 借用构造函数 ```js function Animals(){ this.name = ['cat','dog']; this.other = 'animals'; } function Cat(){ Animals.call(this); }; var c1 = new Cat(); var c2 = new Cat(); c1.name.push('pig'); console.log(c1.name); // ["cat", "dog", "pig"] console.log(c2.name); // ["cat", "dog"]
function Animals(name){ this.name = name; this.animals = ['cat','dog']; }
Animals.prototype.sayName = function(){ console.log(this.name); } function Cat(name,age){ // 属性继承 Animals.call(this,name); this.age = age; }
Cat.prototype = new Animals(); Cat.prototype.constructor = Cat(); Cat.prototype.sayAge= function(){ console.log(this.age); };
var c1 = new Cat('Cat1',18); c1.animals.push('pig'); console.log(c1.animals); // ["cat", "dog", "pig"] c1.sayName(); // Cat1 c1.sayAge(); // 18
var c2 = new Cat('Cat2',19); console.log(c2.animals); // ["cat", "dog"] c2.sayName(); // Cat2 c2.sayAge(); // 19
#### 优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。 #### 缺点:无论什么情况下都会调用两次父类型构造函数 一次是在创建子类型原型时候 另一次是在子类型构造函数内部 子类型中包含全部父类型对象的实例属性 调用子类型构造函数时会重写这些属性 + ### 寄生式继承 创建一个仅用于封装继承过程的函数 该函数在内部以某种方式来增强对象 最后返回对象 ```js function Animals(orginal){ var c = Object(orginal); c.sayHi = function(){ console.log('Hi'); } return c; } var c = { name:'cat', others:['cat1','cat2'] } var cat = Animals(c); cat.sayHi(); // 'Hi'
基本思路是:不必为了指定子类型的原型而调用父类型的构造函数 我们只需要的是一个父类原型的副本 本质上就是使用寄生式继承来继承父类的原型 然后讲结果指定给子类型的原型
function object(o) { function F() {} F.prototype = o; return new F(); }
function inheritPrototype(child, parent) { var prototype = object(parent.prototype); prototype.constructor = child; child.prototype = prototype; }
// 继承 inheritPrototype(Child, Parent);
#### 优点:集组合继承和寄生继承优点于一身 是实现继承最有效的方式
原型
我们创建每一个函数 都有一个prototype属性 该属性指向一个对象 这个对象就是原型 我们创建一个对象时候 可以根据自己的需求 选择性的将一些方法属性通过prototype属性 挂载在原型对象上 而每一个new出来的实例都有一个proto属性 该属性指向构造函数的原型对象 通过这个属性 让实例方法能够访问 到原型对象上的这方法
闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包,这个函数持有对该词法作用域的引用,这个引用就叫做闭包 闭包本质还是函数,只不过这个函数绑定了上下文环境(函数内部引用的所有变量) 缺点:常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。 作用(使用场景):可以用来管理私有变量和私有方法,将对变量(状态)的变化封装在安全的环境中,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收
继承
原型链继承
var c1 = new Cat(); var c2 = new Cat();
c1.name.push('pig'); console.log(c1.name); // ["cat", "dog", "pig"] console.log(c2.name); // ["cat", "dog", "pig"]
c1.other = 'cat'; console.log(c1.other); // cat console.log(c2.name); // animals
优点:可以在子类型构造函数中向超类型构造函数传参
缺点:方法都在构造函数中定义,每次创建实例都会创建一遍方法 无法实现函数复用
组合继承
Animals.prototype.sayName = function(){ console.log(this.name); } function Cat(name,age){ // 属性继承 Animals.call(this,name); this.age = age; }
Cat.prototype = new Animals(); Cat.prototype.constructor = Cat(); Cat.prototype.sayAge= function(){ console.log(this.age); };
var c1 = new Cat('Cat1',18); c1.animals.push('pig'); console.log(c1.animals); // ["cat", "dog", "pig"] c1.sayName(); // Cat1 c1.sayAge(); // 18
var c2 = new Cat('Cat2',19); console.log(c2.animals); // ["cat", "dog"] c2.sayName(); // Cat2 c2.sayAge(); // 19
缺点:无法做到函数复用
寄生组合式继承
基本思路是:不必为了指定子类型的原型而调用父类型的构造函数 我们只需要的是一个父类原型的副本 本质上就是使用寄生式继承来继承父类的原型 然后讲结果指定给子类型的原型
function object(o) { function F() {} F.prototype = o; return new F(); }
function inheritPrototype(child, parent) { var prototype = object(parent.prototype); prototype.constructor = child; child.prototype = prototype; }
// 继承 inheritPrototype(Child, Parent);