一、继承
通过 new 实例化出来的对象继承构造函数的原型。
function Person() {}
Person.prototype.name = 'Lucy';
var p = new Person();
console.log(p);
通过更改构造函数 prototype 属性可以实现继承。
但这种继承没有那么完美,Student继承了Professor、Teacher的所有属性,有些是Student不需要的,如果新建实例对象占用内存也大
Professor.prototype = {
name: 'Mr. Zhang',
tSkill: 'JAVA'
}
function Professor() {}
var professor = new Professor();
Teacher.prototype = professor;
function Teacher() {
this.name = 'Mr. Wang';
this.mSkill = 'JS/JQ';
}
var teacher = new Teacher();
Student.prototype = teacher;
function Student() {
this.name = 'Mr. Li';
this.pSkill = 'HTML/CSS';
}
var student = new Student();
console.log(student);
原型继承特点
1.Target.prototype = Origin.prototype 只会继承 Origin 构造函数原型上的属性和方法。
2.不会继承 Orgin 构造函数自身的属性和方法。
3.在 Target.prototype 上面新增属性和方法,Origin.prototype 也会同步更改(指向同一对象)。
//公共原型
function Teacher() {
this.name = 'Mr. Li';
this.tSkill = 'JAVA';
}
Teacher.prototype = {
pSkill: 'JS/JQ'
}
var t = new Teacher();
console.log(t);
function Student() {
this.name = 'Mr. Wang';
}
Student.prototype = Teacher.prototype;
Student.prototype.age = 18;
var s = new Student();
console.log(s);
二、call_apply
通过 call、apply 借用其它构造函数的属性和方法,但无法继承该构造函数原型上的属性和方法
这不是继承这是借用,Studnet借用Teacher中的函数与方法
Teacher.prototype.wife = 'Ms. Liu';
function Teacher(name, mSkill) {
this.name = name;
this.mSkill = mSkill;
}
function Student(name, mSkill, age, major) {
Teacher.apply(this, [name, mSkill]);
//通过改变this的指向,返回Student的this,而不是Teacher中的this
this.age = age;
this.major = major;
}
var student = new Student('Mr. Zhang', 'JS/JQ', 18, 'Computer');
console.log(student);
三、圣杯模式
还是不好,改变Teacher的原型就改变了Student的原型,改了Student就改了Teacher
因为它们俩的原型指向同一个空间,储存地址一样
function Teacher() {
this.name = 'Mr. Li';
this.tSkill = 'JAVA';
}
Teacher.prototype = {
pSkill: 'JS/JQ'
}
var t = new Teacher();
console.log(t);
function Student() {
this.name = 'Mr. Wang';
}
Student.prototype = Teacher.prototype;
Student.prototype.age = 18;
var s = new Student();
console.log(s);
1.创建 Buffer 构造函数。
2.Buffer 构造函数继承 Origin 构造函数。
3.Target 构造函数继承 Buffer 构造函数实例化后的对象。
4.此时 Target 构造函数原型和 Origin 构造函数原型就不再指向同一对象。
5.实例化后的 target 对象继承了 Origin 构造函数原型上的属性和方法。
利用Buffer的实例对象,实例对象是新的空间
Student实例对象->Student.prototype(Buffer实例对象)->Buffer.prototype(Teacher.prototype)->Object.prototype
function Teacher() {
this.name = 'Mr. Li';
this.tSkill = 'JAVA';
}
Teacher.prototype = {
pSkill: 'JS/JQ'
}
var t = new Teacher();
console.log(t);
function Student() {
this.name = 'Mr. Wang';
}
function Buffer() {}
Buffer.prototype = Teacher.prototype;
var buffer = new Buffer();
Student.prototype = buffer;
//Student.prototype = new Buffer();//也行
Student.prototype.age = 18;
var s = new Student();
console.log(s);
封装原型继承
function inherit(Target, Origin) {
function Buffer() {}
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
Target.prototype.constructor = Target;
Target.prototype.super_class = Origin;
}
function Teacher() {}
function Student() {}
inherit(Student, Teacher);
var s = new Student();
var t= new Teacher();
console.log(s);
console.log(t);
function inherit(Target, Origin) {
function Buffer() { }
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
Target.prototype.constructor = Target;
Target.prototype.super_class = Origin;
}
// function Teacher() { }
// function Student() { }
function Teacher() {
this.name = 'Mr. Li';
this.tSkill = 'JAVA';
}
function Student() {
this.name = 'Mr. Wang';
}
inherit(Student, Teacher);
var s = new Student();
var t = new Teacher();
console.log(s);
console.log(t);
IIFE实现封装继承方法
Buffer形成闭包,但Buffer虽然没有重置,但这里面不受影响
var inherit = (function () {
var Buffer = function () { }
return function (Target, Origin) {
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
Target.prototype.constructor = Target;
Target.prototype.super_class = Origin;
}
})();
Teacher.prototype.name = 'Mr. Zhang';
function Teacher() { }
function Student() { }
inherit(Student, Teacher);
Student.prototype.age = 18;
var s = new Student();
var t = new Teacher();
console.log(s);
console.log(t);
四、模块化
1.防止全局污染。
2.利于后期维护。
3.二次开发。
返回构造函数在外部使用,Programmer不返回
var inherit = (function () {
var Buffer = function () { }
return function (Target, Origin) {
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
Target.prototype.constructor = Target;
Target.prototype.super_class = Origin;
}
})();
var initProgrammer = (function () {
var Programmer = function () {}
Programmer.prototype = {
name: '程序员',
tool: '计算机',
work: '编写应用程序',
duration: '10个小时',
say: function () {
console.log('我是一名' + this.myName + this.name + ', 我的工作是用' + this.tool + this.work + ', 我每天工作' + this.duration + ',我的工作需要用到' + this.lang.toString() + '。');
}
}
function FrontEnd() {}
function BackEnd() {}
inherit(FrontEnd, Programmer);
inherit(BackEnd, Programmer);
FrontEnd.prototype.lang = ['HTML', 'CSS', 'JavaScript'];
FrontEnd.prototype.myName = '前端';
BackEnd.prototype.lang = ['Node', 'Java', 'SQL'];
BackEnd.prototype.myName = '后端';
return {
FrontEnd: FrontEnd,
BackEnd: BackEnd
}
})();
var frontEnd = new initProgrammer.FrontEnd();
var backEnd = new initProgrammer.BackEnd();
frontEnd.say();
backEnd.say();
总结
var func1 = (function () {
var a = 1;
console.log('a',a)
return function () {
a = 2
console.log('a',a)
}
})();
console.log(window)
func1未使用,但里面的方法运行了,打印window有,func1是返回的函数
打印
说明函数运行了
var func1 = (function () {
var a = 1;
console.log('a', a)
// return function () {
// a = 2
// console.log('a', a)
// }
})();
console.log(window)
五、作业
使用模块化开发实现以下功能:
1.打印一个参数值以内能被3或5或7整除的数。
2.打印斐波那契数列的第N位。
3.打印从0到一个数的累加值。
window.onload = function () {
console.log(initFib(10));
console.log(initDiv(100));
console.log(initSum(100));
}
var initFib = (function () {
function fib(n) {
if (n <= 0) {
return 0;
}
if (n <= 2) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
return fib;
})();
var initDiv = (function () {
function div(n) {
var arr = [];
for (var i = 0; i <= n; i++) {
if (i % 3 === 0 || i % 5 === 0 || i % 7 === 0) {
arr.push(i);
}
}
return arr;
}
return div;
})();
var initSum = (function () {
function sum(n) {
var sum = 0;
for (var i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
return sum;
})();