创建对象的几种方法
- 对象字面量
var obj1 = {
name:'luoyi'
}
var obj2 = new Object({
name:'louyi3'
}) //也可以归类为构造函数形式
- 构造函数形式
var Foo = function(){
this.name = 'luoyi'
}
var foo = new Foo()
- Object.create()方法
var obj = {
name:'luoyi'
}
var obj2 = Object.create(obj)
原型与原型链
var Foo = function(name){
this.name = name
}
var foo = new Foo('luoyi')
- 构造函数:构造函数可以使用new运算符来生成一个实例
- 实例:通过构造函数new出来的对象
- prototype: 函数都有prototype属性
- 原型对象:函数的prototype属性就是原型对象
- constructor: 原型对象上有一个constructor属性指向构造函数
- 实例的__proto__属性指向函数的prototype属性(原型对象)
instanceof的原理
instanceof 是通过原型链判断的,A instanceof B, 在A的原型链中层层查找,是否有原型等于B.prototype,如果一直找到A的原型链的顶端(null;即Object.proptotype.proto),仍然不等于B.prototype,那么返回false,否则返回true.
new一个对象的过程
- 创建一个新对象。
- 这个新对象继承自构造函数的prototype,即会被执行原型连接。
- 构造函数被执行,执行的时候参数被传入,this被指定为新实例
- 如果构造函数返回了一个对象,那么这个对象就会取代整个new出来的结果;如果构造函数没有返回其他对象,那么new出来的结果为步骤1中创建的对象。
自定new的过程
function new1 (func){
var o = Object.create(func.prototype)
var [func,...args] = [...arguments]
var k = func.call(o,...args)
if(typeof k === 'object'){
return k
}else{
return o
}
}
继承
类的声明
// ES5的实现方式
funciton Animal1(){
this.name = 'name'
}
// ES6中的实现方式
class Animal2{
constructor(){
this.name = 'name'
}
}
typeof Animal2 // 'function' 类的数据类型就是函数,类本身就指向构造函数
Animal2 === Animal2.prototype.constructor // true
实例化类的对象
ES5的实例化方式与ES6的实例化方式相同
var cat = new Animal()
类的继承
继承的本质是原型链
- 借助构造函数实现继承
function Parent (){
this.name = 'parent'
}
function Child (){
Parent.call(this)
this.type = 'child'
}
Parent.prototype.say = function(){
console.log('say hi')
}
var child = new Child()
child.say() //没有这个方法
- 缺点:Parent原型链上的方法是没有办法被继承的,没有实现真正的继承。
- 借助原型链实现继承
function Parent2 (){
this.name = 'parent2'
}
function Child2(){
this.type = 'child2'
}
Child2.prototype = new Parent2()
var child2 = new Child2()
- 缺点1:Child2的所有实例对象共享__proto__:
c2.__proto__ === c22.__proto__
function Parent2 (){
this.name = 'parent2';
this.play = [1,2,3]
}
function Child2(){
this.type = 'child2'
}
Child2.prototype = new Parent2()
var c2 = new Child2()
var c22 = new Child2()
c2.play.push(4)
c22.play // [1,2,3,4]
- 缺点2:child2.constructor指向的Parent2
- 组合继承:构造函数继承和原型链继承的组合
function Parent3(){
this.name = 'parent3'
this.play = [1,2,3]
}
function Child3(){
Parent3.call(this)
this.type = 'child3'
}
Child3.prototype = new Parent3();
var s = new Child3()
var s1 = new Child3()
s.play.push(4)
s.play() //[1,2,3,4]
s1.play() // [1,2,3]
- 缺点:父类的构造函数执行了两次
组合继承的优化方式1
function Parent3(){
this.name = 'parent3'
this.play = [1,2,3]
}
function Child3(){
Parent3.call(this)
this.type = 'child3'
}
//Child3.prototype = new Parent3();
Child3.prototype = Parent3.prototype;
var s = new Child3()
var s1 = new Child3()
s.play.push(4)
s.play() //[1,2,3,4]
s1.play() // [1,2,3]
- 缺点:constructor指向的是父类的构造函数
组合集成的优化方式2
function Parent3(){
this.name = 'parent3'
this.play = [1,2,3]
}
function Child3(){
Parent3.call(this)
this.type = 'child3'
}
//Child3.prototype = new Parent3();
//Child3.prototype = Parent3.prototype;
Child3.prototype = Object.create(Parent3.prototype)
Child3.prototype.constructor = Child3
Zepto中是如何使用原型链
写一个实际应用中原型链继承的例子:封装一个DOM查询的例子
function Elem(id){
this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val){
var elem = this.elem
if(val){
elem.innerHTML = val
}else{
return elem.innerHTML
}
}
Elem.prototype.on = function(type,fn){
var elem = this.elem
elem.addEventListener(type,fn)
}
var div1 = new Elem('div1')