本人能力有限,有误请斧正javascript
本文旨在复习面向对象(不包含es6)html
本文学习思惟java
keys的支持git
var o = {};
var o = new Object()
var o = Object.create( )
object.create()有两个参数第一个是要新建立对象的原型对象, 第二个可选:本身定义的属性,须要配置麻烦通常不用,返回一个新对象,带着指定的原型对象和属性es6
经过给Object.create()参数传null能够得到一个纯净的没有原型的对象。缘由是null是原型链的链末github
输出查看原型链发现create在创造一个对象会存在传入的属性与方法
这个方法太适合继承了,他会直接继承传入的属性和方法
经过测试传入{}时,也会存在Object.__proto__ 指向 Object.__proto__
;编程
// Object.create() 实现方式 // 实际这个是原型式继承的核心 var object = function(proto){ var F = function(){}; // 建立一个对象 F.prototype = proto; //变量原型指向传入对象 return new F(); }
参考资料:MDN-继承与原型链数组
构造函数(函数声明或者函数表达式)本质仍是函数,只是用来建立对象,还有个惯例就是首字母大写网络
// 构造函数 function Person(){} // 调用构造函数,建立对象 var p1 = new Person();
参考:app
经过new关键字能够建立新对象!
在new一个对象的时候作了什么事?4个步骤(高程3)
MDN简化版,只讨论过程,没法传参
// MND简化 /* 一个继承自 Foo.prototype 的新对象被建立。 使用指定的参数调用构造函数 Foo ,并将 this 绑定到新建立的对象。 new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的状况。 由构造函数返回的对象就是 new 表达式的结果。若是构造函数没有显式返回一个对象,则使用步骤1建立的对象。 (通常状况下,构造函数不返回值,可是用户能够选择主动返回对象,来覆盖正常的对象建立步骤) */ var Foo = function(){}; var _new2 = function(fn){ var o = Object.create(fn.prototype); var k = fn.call(o); if(typeof k === 'object'){ return k; }else{ return o; } } var f = _new2(Foo);
阮老师的版本能够传参,并且很详细了
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) { // 将 arguments 对象转为数组 var args = [].slice.call(arguments); // 取出构造函数 var constructor = args.shift(); // 建立一个空对象,继承构造函数的 prototype 属性 var context = Object.create(constructor.prototype); // 执行构造函数 var result = constructor.apply(context, args); // 若是返回结果是对象,就直接返回,不然返回 context 对象 return (typeof result === 'object' && result != null) ? result : context; } // 实例 var actor = _new(Person, '张三', 28);
构造函数是对一个对象的抽象描述,实例则是对象的具体表现
好吧!大boss出场,都说javaScript最具备特点的就是原型
参考:
原型是什么?(高程3)
咱们建立的每一个函数都有一个prototype(原型) 属性,这个属性是一个指针,指向一个对象
理解原型对象 高程3 -- p148有兴趣能够去读一下
不管何时只要建立了一个新函数,就会根据一组特定的规则为该函数建立一个prototype属性,这个属性将指向函数的原型对象。在默认状况下,全部的原型对象会自动得到一个constructor(构造函数)属性,这个属性包含一个指向prototype属性全部函数的指针。经过这个构造函数,咱们还能够继续为原型对象添加其余属性和方法
按照书上的理解:
简述:([[Prototype]] === __proto__
)
__poroto__
指向原型对象constructor
的属性,指向构造函数var Person = function() {}; Person.prototype.age = 1; var p = new Person(); var p2 = new Person(); console.log(p.__proto__ === Person.prototype); // true console.log(p2.__proto__ === Person.prototype); // true console.log(Person === Person.prototype.constructor); // true
原型链就是在查找到某个属性或者方法不断向上查找的一个过程
MDN-很是具备表明的简化原型链
// 让咱们假设咱们有一个对象 o, 其有本身的属性 a 和 b: // {a: 1, b: 2} // o 的 [[Prototype]] 有属性 b 和 c: // {b: 3, c: 4} // 最后, o.[[Prototype]].[[Prototype]] 是 null. // 这就是原型链的末尾,即 null, // 根据定义,null 没有[[Prototype]]. // 综上,整个原型链以下: // {a:1, b:2} ---> {b:3, c:4} ---> null console.log(o.a); // 1 // a是o的自身属性吗?是的,该属性的值为1 console.log(o.b); // 2 // b是o的自身属性吗?是的,该属性的值为2 // 原型上也有一个'b'属性,可是它不会被访问到.这种状况称为"属性遮蔽 (property shadowing)" console.log(o.c); // 4 // c是o的自身属性吗?不是,那看看原型上有没有 // c是o.[[Prototype]]的属性吗?是的,该属性的值为4 console.log(o.d); // undefined // d是o的自身属性吗?不是,那看看原型上有没有 // d是o.[[Prototype]]的属性吗?不是,那看看它的原型上有没有 // o.[[Prototype]].[[Prototype]] 为 null,中止搜索 // 没有d属性,返回undefined
再用对象表示一个
// 属性遮蔽 function Person() { this.name = '111'; } Person.prototype.name = '222'; var p1 = new Person(); console.log(p1.name); // 111 console.log(p1.__proto__.name); // 222 var p2 = new Person(); console.log(p2.age);
如今要查找p2.age属性
__prope__
找到原型对象,原型对象中有么?没有undefined
属性屏蔽就是找到了就不会再找了(实例上的属性>原型链上的属性),实际仍是存在
若是指定的属性在指定的对象或其原型链中,则in 运算符返回true。语法:
prop in object
isPrototypeOf() 方法用于测试一个对象是否存在于另外一个对象的原型链上。
function Foo() {} function Bar() {} function Baz() {} Bar.prototype = Object.create(Foo.prototype); Baz.prototype = Object.create(Bar.prototype); var baz = new Baz(); console.log(Baz.prototype.isPrototypeOf(baz)); // true console.log(Bar.prototype.isPrototypeOf(baz)); // true console.log(Foo.prototype.isPrototypeOf(baz)); // true console.log(Object.prototype.isPrototypeOf(baz)); // true
instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。(判断他们的地址指向是否一致)。有一种特殊状况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。
几点instanceof的注意
//instanceof判断会失真 var obj = Object.create(null); typeof obj // "object" Object.create(null) instanceof Object // false //null做为一个特殊的Object却不属于Object建立的实例,null原型链的链末 undefined instanceof Object // false null instanceof Object // false // instanceof 用于对象 var str = '1' var str2 = new String('2'); str instanceof String // false str2 instanceof String // true
typeof 1 //number typeof '' // string typeof undefined //undefined typeof true // boolean typeof function(){} // function typeof {} // object typeof [] // object typeof null // object typeof Symbol() //symbol ES6
继承有几种
我用我总结了一些思惟导图
这里把继承的几种方式罗列出来方便查阅,如下大可能是代码,简易的我总结在思惟导图中了
关键点是要打通原型链
因为原型对象是函数初次建立就会存在的对象,因此会共享
共享就会存在共享问题
优势:
缺点:
// 父类 function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; } // 子类 function SubType() { this.subproperty = false; } // 继承父类 打通原型链 SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.subproperty; } var instance = new SubType(); console.log(instance.getSuperValue()); // true
关键在于环境变量(this)的指向,因为每次建立都会建立一个新的this因此会拥有本身的属性与方法,因为是改变this指向因此没法共享原型对象
优势:
缺点:
// 父类 function SuperType() { this.colors = ['red']; } // 子类 function SubType() { // 继承父类 SuperType.call(this); } var instance1 = new SubType(); colors.push('black'); cosnole.log(instance1.colors); // red,black var instance2 = new SubType(); console.log(instance2.colors); // red
组合了原型继承与借用构造函数继承继承了优势,可是因为组合,因此建立了两次对象,形成轻微的浪费空间
优势:
缺点
// 父类 function SuperType(name) { this.name = name; this.colors = ['red']; } SuperType.prototype.sayName = function () { console.log(this.name); } // 子类 function SubType(name, age) { // 继承属性 SuperType.call(this, name); this.age = age; } // 继承方法 SubType.prototype = new SuperType(); SubType.prototype.sayAge = function () { console.log(this.age); } var instance1 = new SubType('name1', 1); instance1.colors.push('black'); console.log(instance1.colors); // red,black instance1.sayName(); // name1 instance1.sayAge(); // 1 var instance2 = new SubType('name2', 2); console.log(instance2.colors); // red instance2.sayName(); // name2 instance2.sayAge(); // 2
寄生组合继承是把原型继承给改掉,实际上就是想要父级的原型链,不必定要建立对象因此有了寄生组合继承,该继承是目前最完善的继承方式
// 寄生继承 function inheritPrototype(subType, superType) { var prototype = Object.create(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } // 父类 function SuperType(name) { this.name = name; this.colors = ['red']; } SuperType.prototype.sayName = function () { console.log(this.name); } // 子类继承 function SubType(name, age) { SuperType.call(this, name); } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function () { console.log(this.age) }
阮一峰的网络日志:
看了高程3与阮一峰老师的博客,结合起来更加好理解