说到原型以前,先复习一下对象建立方式:app
<script> var obj = { a: 1} obj.b = 2 console.log(obj) </script>
<script> function CreatePerson (name, age) { var obj = new Object () obj.name = name obj.age = age obj.sayHi = function () { console.log('哈喽') } return obj } var person1 = CreatePerson('张三', 18) var person2 = CreatePerson('李四', 20) </script>
<script> function Person (name, age) { this.name = name this.age = age this.sayHi = function () { console.log('哈喽') } } var person1 = new Person('张三',18) var person2 = new Person('李四',20) </script>
用new操做符调用函数时,会自动执行下面的操做函数
- 建立(或构造)一个新的对象
- 这个新对象会执行prototype链接
- 这个新对象会绑定到函数调用的this
- 若是函数没有返回其余对象, 那么new表达式中的函数调用自动返回这个新对象
//咱们来举个例子 var Foo() { //这是一个普通函数 } Foo() //普通函数调用 var a = new Foo()//在普通调用前加一个new关键字后,这个调用就变成了构造函数调用
new会劫持全部普通函数,并用构造函数的形式调用它优化
var a = new Foo() 这句话的执行机制: Foo是一个普通函数,在使用new调用时,它就会构造一个对象,而且赋值给athis
用new的方法来调用Foo会产生一个新对象a,这个新对象的内部连接__proto__会关联到Foo的原型对象上
a.__proto__ == Foo.prototypeprototype
<script> function Person () { } Person.prototype.name = '张三' Person.prototype.age = 18 Person.prototype.sayHi = function () { console.log('哈喽') } var person1 = new Person() var person2 = new Person() </script>
<<script> function Person () { } Person.prototype = { name: '张三', age: 18, sayHi: unction () { console.log('哈喽') } } var person1 = new Person() var person2 = new Person() console.log(person1.constructor == Person) // false console.log(person1.constructor == Object) // true </script>
- js 中全部的对象都有一个特殊的内置属性[[prototype]] ,这个属性其实就是用来对其余对象的引用
- 这种写方法改变了原型内部的constructor指针的属性了 ,再也不指向Person函数了,若是这个指针很重要,那么能够手动设置
<<script> function Person () { } Person.prototype = { constructor:Person, name: '张三', age: 18, sayHi: unction () { console.log('哈喽') } } var person1 = new Person() var person2 = new Person() console.log(person1.constructor == Person) // true console.log(person1.constructor == Object) //false </script>
<script> var obj = { a: 2 } console.log(obj.a) // 2 </script>
prototype机制就是存在于对象中的一个内部连接,它会引用其余对象。指针
这个连接的做用就是: 若是在对象上没有找到须要的属性或者方法,引擎就会在prototype关联的对象上进行查找。若是在后者的对象中没有找到这个属性和方法,引擎就会继续查找他的prototype,以此内推,若是没有找到,就会返回underfind。
这就是所谓的原型链。(有点像嵌套的做用域链)code
构造函数就是初始化一个实例对象,对象的prototype属性是继承一个实例对象。对象
<script> function Bird(legNum, wingNum) { this.leg = legNum; this.wing = wingNum; } Bird.prototype.appearance = function () { console.log('鸟类都有漂亮的羽毛') } function Swan (beh,legNum,wingNum) { this.behaviour = beh; } Swan.prototype = new Bird(2,2,);// 继承了Bird中的属性和方法,可是不能经过传参修改这些值 Swan.prototype.story = function () { console.log('是由丑小鸭变成的'); } // 白天鹅 var whiteSwan = new Swan('会游泳') console.log(whiteSwan) whiteSwan.appearance() // 鸟类都有漂亮的羽毛 whiteSwan.story() // 是由丑小鸭变成的 </script>
<script> function Person (name, age) { this.name = name; this.age = age; } Person.prototype.behaviour = function () { console.log('你们好,我是一类人') } function Man(name, age, gender) { Person.call(this, name ,age); this.gender = gender; } //能够建立多个实例对象 var man1 = new Man('张三', 18, '男') var man2 = new Man('李四', 20, '女') //可是 不能调用原型中的属性和方法 console.log(man1) console.log(man2) man1.behaviour()//会报错,这种方法继承不到Person函数中原型中的属性方法 </script>
call(this, 参数1 , 参数2...)继承
- 优势:能够继承全部在构造函数体中书写的属性,而且能够进行传参
- 缺点: 没法继承原型中的属性和方法
原型方式:能够继承原型链中的属性ip
看实例
<script> // 组合继承 function Person (name, age) { this.name = name; this.age = age; } //Person的原型 Person.prototype.behaviour = function () { console.log('你们好,我是一类人') } //console.log(Person())//underfined //Man 的构造函数 function Man(name, age, gender) { //call调用的方法进行继承,这个方法改变了Man这个构造函数内部的指向(即constructor指针) Person.call(this, name ,age);//第二次调用Person this.gender = gender; } //这里的经过new建立了一个实例对象,并把这个实例对象赋值给了Man的原型对象, 因此改变了 Man原型对象的内部指针(constrouctor) //本来Man 的原型对象中的constructor指向Man这个函数的,可是如今被改变成指向Person这个函数了 Man.prototype = new Person() //第一次调用Person //Man 原型对象中的方法 Man.prototype.action = function () { console.log('吃饭、睡觉、打豆豆') } //能够建立多个实例对象 var man1 = new Man('张三', 18, '男') var man2 = new Man('李四', 20, '女') console.log(man1) man1.behaviour() man1.action() </script>
- 优势:全部的属性和方法都可以被继承,而且全部的属性都可自由传参。
- 缺点:每调用一次Man构造函数时,就会调用两次Person函数
<script> //构造函数 function Person (name, age) { this.name = name; this.age = age; } Person.prototype.behaviour = function () { console.log('你们好,我是一类人') } function Man (name, age, gender) { this.gender = gender var person = new Person(name,age) // 在Man函数内部对Person进行遍历, 把People具备的属性赋值给Man for (var k in person) { this[k] = person[k] } } Man.prototype.action = function () { console.log('吃饭、睡觉、打豆豆') } //建立实例对象man var man = new Man('张三', 18, '男') var man2 = new Man('李四', 20, '女') console.log(man.name) console.log(man.age) console.log(man) console.log(man2) man.behaviour() </script>
优势:能够传参,能够继承到原型中属性和方法
<<script> //构造函数 function Person (name, age) { this.name = name this.age = age } Person.prototype.behaviour = function () { console.log('你们好,我是一类人') } function Man (name, age, gender) { //在Man中添加一个属性people,把People这个函数体赋值给Man的属性people,而后再进行调用 this.people = Person //进行调用 this.people(name, age) this.gender = gender } Man.prototype = function () { console.log('吃饭、睡觉、打豆豆') } //实例对象 var man = new Man('张三', 18 , '男') console.log(man) man.behaviour()// 报错 不能继承到Person原型中的属性方法 </script>
- 优势: 能够传参
- 缺点:原型内的方法没法继承,而且还多了一个属性people