理解JavaScript原型和面向对象(继承)
JavaScript面向对象核心知识归纳:http://duni.sinaapp.com/?p=742
彻底理解JavaScript原型:http://www.imooc.com/article/2088
js构造函数的方法与原型prototype:http://caibaojian.com/js-constructor-vs-prototype.html
关于__proto__和prototype的一些理解:http://www.cnblogs.com/zzcflying/archive/2012/07/20/2601112.html
理解JavaScript作用域和作用域链:http://www.cnblogs.com/dolphinX/p/3280876.html
JavaScript中的this简单易懂:http://www.imooc.com/article/1758
JavaScript中this绑定详解:http://www.html5cn.org/article-9834-1.html
apply和call的应用与区别: http://www.html5cn.org/article-2875-1.html
如何编写可维护的面向对象JavaScript代码:http://saebbs.com/forum.php?mod=viewthread&tid=37721&page=1&extra=#pid254894
js面向对象[继承]:http://www.w3cfuns.com/notes/22817/d2f3569a8e8a2db7c4d7162e96c0c7d8.html
全面理解面向对象的JavaScript:http://caibaojian.com/javascript-object-2.html#?wb
JavaScript中对象的7种创建方式:http://www.w3cfuns.com/notes/33204/f36b70e9910da3fc4461568fc3806ca1.html
一道常被人轻视的前端JS面试题:http://www.cnblogs.com/xxcanghai/p/5189353.html
前端小白如何用面向对象思想写代码:https://segmentfault.com/a/1190000008993282?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com
关于JavaScript原型的概念:
1.所有的对象都有"proto"属性,该属性对应该对象的原型
2.所有的函数对象都有"prototype"属性,该属性的值会被赋值给该函数创建的对象的"proto"属性(当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例,就是设置实例的"proto"属性,也就是说,所有实例的原型引用的是函数的"prototype"属性)
3.所有的原型对象都有"constructor"属性,该属性对应创建所有指向该原型的实例的构造函数
通过一个很简单的例子来了解原型:
function Person(name, age){ //构造函数 this.name = name; this.age = age; this.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); }; } Person.prototype.Say = function () { alert("Person say"); } var p = new Person("will", 22); p.Say(); 为什么p可以访问Person的Say? 首先var p=new Person(),可以得出p.__proto__=Person.prototype。那么当我们调用p.Say()时,首先p中没有Say这个属性,于是,他就需要到他的__proto__中去找,也就是Person.prototype,而我们在上面定义了Person.prototype.Say=function(){}; 于是,就找到了这个方法。 再来看一个关于原型继承的例子: // 定义Human类 function Human() { this.setName = function (fname, lname) { this.fname = fname; this.lname = lname; } this.getFullName = function () { return this.fname + " " + this.lname; }; } // 定义Human类 function Human() { this.setName = function (fname, lname) { this.fname = fname; this.lname = lname; } this.getFullName = function () { return this.fname + " " + this.lname; }; } //定义Employee类 function Employee(num) { this.getNum = function () { return num; } }; //让Employee继承Human类 Employee.prototype = new Human(); //实例化Employee对象 var john = new Employee("4815162342"); john.setName("John", "Doe"); alert(john.getFullName() + "'s employee number is " + john.getNum());//John Doe's employee number is 4815162342
构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
//组合使用构造函数模式和原型模式 function Person(name, age) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, //更正为正确的指向 sayName: function(){ alert(this.name); } }; var person1 = new Person("Nicholas", 29); person1.sayName();//Nicholas console.log(person1.age);//29 console.log(person1.constructor);//function Person(){} console.log(person1.__proto__);//访问person1实例的原型对象 console.log(Person.prototype.constructor);//function Person(){} console.log(person1.constructor === Person.prototype.constructor);//true
组合继承:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
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.constructor = SubType; //更正为正确的指向 SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas" instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg" instance2.sayAge(); //27
关于原型的继承:
//原型继承 function A(){ this.name = 'world'; } function B(){ this.bb = "hello"; } var a = new A(); var b = new B(); Object.setPrototypeOf(a, b);//用Object.setPrototypeOf()方法来设置对象的原型,等同于A.prototype = new B(); a.constructor = A;//将b设置为a的原型,此处有一个问题,即a的constructor也指向了B构造函数,可能需要纠正 console.log(a.constructor);//hello //ES6中的类继承 class B{ constructor(){ this.bb = 'hello' } } class A extends B{ constructor(){ super(); this.name = 'world'; } } var a = new A(); console.log(a.bb + " " + a.name);//hello world console.log(typeof(A));//"function"