面向对象编程的特点
封装:使用对象的人无需考虑内部实现 ,只考虑功能的使用。
继承:为了代码的可复用 。
多态:不同对象 作用于同一操作 产生不同结果。
JS如何创建对象 普通方式 1 2 3 const A = new Object ()A.attribute = '' A.fn = function ( ) { }
工厂模式 1 2 3 4 5 6 function Creat (attr ) { return A } const aa = Creat('...' )const bb = Creat('...' )
存在问题:往实例化对象上层找不到父类,只能知道是一个Object
构造函数/实例 1 2 3 4 5 6 7 8 9 10 function Player (name ) { this .name = name this .run = function ( ) { console .log('...' ); } } const x = new Player('a' )const y = new Player('b' )console .log(x.run === y.run)
缺点:通过this添加的属性和方法,总是指向当前对象(改变当前对象不会影响构造函数),实例化时通过this添加的属性和方法都会在内存当中复制一份。
原型对象 1 2 3 4 5 6 7 8 9 10 function Player (name ) { this .name = name } Player.prototype.run = function ( ) { console .log('...' ); } const x = new Player('a' )const y = new Player('b' )console .log(x.run === y.run)
静态属性 1 2 3 4 5 6 7 function Player (name ) { Player.count = 1 } const p = new Player('a' )console .log(p.count) console .log(Player.count)
原型及原型链 查找原型对象的方法 1 2 xxx.__proto__ Object .getPrototypeOf(xxx)
new关键字做了什么
创建了新对象并将.__proto__指向构造函数的.prototype
将this指向新创建的对象
返回新对象(1. 有显式的返回值且是对象则返回这个对象 2. 其他情况返回this)
1 2 3 4 5 6 7 8 9 10 11 function newSimulator ( ) { const obj = new Object () const constructor = [].shift.call(arguments) // 取出参数第一项,并删除掉,剩余参数在下一步会用到 obj.__proto__ = constructor .prototype // 3. this指向新对象,也就是改变this的指向:例如apply,call const ret = constructor .apply(obj, arguments) // 4. 返回新对象或this return typeof ret === 'object' ? ret : obj }
1 2 3 4 5 6 7 8 9 function Player (name, type ) { this .name = name this .say = () => { console .log(`i am ${name} ,i create by ${type} ` ) } } const a = new Player('a' , 'new' )a.say() const b = newSimulator(Player, 'b' , 'newSimulator' )b.say()
理解原型链 当读取实例对象的属性时,如果找不到,会查找对象原型中的属性,直到最上层为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 Object .prototype.name = 'Object' ;function Player ( ) {}Player.prototype.name = 'Player' ; const p1 = new Player();p1.name = 'p1' ; console .log(p1.name); delete p1.name;console .log(p1.name); delete Player.prototype.name;console .log(p1.name);
JS实现继承 原型链继承 1 2 3 4 5 6 7 8 9 function Parent ( ) { this .name = 'ParentName' ; this .actions = ['sing' , 'jump' , 'rap' ]; } function Child ( ) {}Child.prototype = new Parent(); Child.prototype.constructor = Child;
存在问题:引用类型被改变,所有实例共享,无法传参
1 2 3 4 5 const c1 = new Child();c1.actions.push('basketball' ); console .log(c1.actions); const c2 = new Child();console .log(c2.actions);
构造函数继承 1 2 3 4 5 6 7 8 9 function Parent (name ) { this .name = name; this .actions = ['sing' , 'jump' , 'rap' ]; this .say = function ( ) {} } function Child ( ) { Parent.apply(this , arguments ); }
1 2 3 4 5 6 7 const c1 = new Child('c1' );const c2 = new Child('c2' );c1.actions.pop() console .log(c1.name, c1.actions) console .log(c2.name, c2.actions) console .log(c1.say === c2.say);
组合继承 该继承同时解决以上两种继承存在的问题,副作用是会重复执行构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Parent (name, actions ) { this .name = name; this .actions = actions; } Parent.prototype.say = function ( ) { console .log(this .name + ' say' ); } function Child ( ) { Parent.apply(this , arguments ); } Child.prototype = new Parent(); Child.prototype.constructor = Child;
1 2 3 4 5 6 7 const c1 = new Child('c1' , ['eat' ]);const c2 = new Child('c2' , ['run' ]);c1.actions.pop() console .log(c1.name, c1.actions) console .log(c2.name, c2.actions) console .log(c1.say === c2.say);
寄生组合式继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function Parent (name, actions ) { this .name = name; this .actions = actions; } Parent.prototype.say = function ( ) { console .log(this .say + ' say' ); } function Child ( ) { Parent.apply(this , arguments ); } Child.prototype = Object .create(Parent.prototype); Child.prototype.constructor = Child;
解析其中 Object.create
等于以下写法(es5):
1 2 3 let TempFunction = function ( ) {}; TempFunction.prototype = Parent.prototype; Child.prototype = new TempFunction();
这也就是“寄生”的含义:用一个纯粹的中间函数去执行了new。
es6继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Parent { constructor () { this .name = 'aaa' ; } say() { console .log(this .name, 'say' ); } } class Child extends Parent { constructor () { super (); } }
写到es6已经完全不需要说什么了,一句话总结:JS,面向未来编程😋