本篇主要是记录一下对js中对于原型的理解...编程
原型涉及到构造函数, 原型对象, 实例化对象三者之间的关系...数组
构造函数安全
function Person (name,age) { //(1)建立一个空对象: {} //(2)将this指向这个空对象 : this = {} //(3)执行构造函数赋值代码(完成对象的赋值) this.name = name; this.age = age; this.sayHi = function () { console.log(this.name + 'hello world'); }; //(4)返回这个对象 }; var man = new Person('huahua',18); 1.何为构造函数? 构造函数:首先,它是函数,而且任何的函数均可以做为构造函数存在,它的本质是初始化对象。 构造函数都是和new关键词一块儿使用的。 new就是在建立对象,从声明开始一共作了4件事(如上),构造函数就是在为初始化的对象添加属性和方法(成员) 2.构造函数的特色: a:构造函数的首字母必须大写,用来区分于普通函数 b:内部使用的this对象,来指向即将要生成的实例对象 c:使用New来生成实例对象
实例对象函数
1.上面的 man 就是经过Person这个构造函数实例化出来一个对象,咱们称为 **实例化对象**;何为对象的实例化呢? 2.在我看来就是给一个空对象添加了一些属性和方法,使其具备了一些特征和行为...也就是上面new关键字干的事;跟面向对象中的一些概念比较相似... 面向对象编程: 面向对象就是对现实中的事物进行抽象化...而后再给其设置特征属性和行为使之具体化; 面向对象就是对面向过程进行封装后的结果... 3.实例对象中存在一个__proto__属性; 这个属性指向了构造函数的原型prototype... 注意: 实例对象访问成员的规则:先看本身有没有这个成员,若是有则访问,没有则访问原型的
原型对象this
上面已经聊过构造函数和实例化对象了,那么原型对象又是什么呢? 当咱们在声明一个函数时, 系统会帮咱们建立一个与该函数对应的属性prototype,咱们称它为原型对象; 以上面的Person为例,这个prototype是该函数的一个属性,咱们能够调用Person.prototype来修改其成员或者进行重写; 原型对象中有一个构造器指针constructor属性来指向对应的构造函数,他的做用是可让实例对象知道本身是哪个构造函数生成的; 如 man.constructor 即man.__proto__.constructor指向了 Person.
下面用一张图来表示他们之间的关系...spa
原型对象中能够存储不少成员属性和方法,多个实例对象之间就能共享这些属性和方法; 相似实现了面向对象中 继承 的效果...prototype
面向对象的三大特性:指针
封装:将功能代码封装到对象中,只暴露外部接口(API),使用者无需关心内部实现 继承:一个对象拥有另外一个对象全部的成员变量(属性和方法) 多态: 一个对象在不一样状况下的多种状态; 一个对象通过不一样操做后会有不一样的行为.... (js从语法的角度上来讲没有多态,由于js是基于对象的语言) js实现继承的方式: 1. 咱们能够遍历父对象,将父对象的属性动态添加到子对象中 (适用于一个子对象的继承) for (var key in father){ son[key] = father[key]; }; 2. 替换原型:将父对象做为子对象构造函数的原型(可是会丢失以前的原型对象的成员) // 子对象用构造函数来实例化 function Son(name, age) { this.name = name; this,age = age; } Son.prototype.father = { parent: 'laosong', age: 47, } // Son 原型对象中的成员 var son = new Son('xiaowang', 24) var father = { name: 'laowang', age: 48, } Son.prototype = father; // 至关于Son的原型被从新赋值,替换了,laosong不在了 3. 综合上面两种状况: 将父对象的成员动态添加到子对象的原型中, 这样就不会丢失了 for (var key in father){ Son.prototype[key] = father[key]; }; /**混合式继承封装 @param method:子对象的构造函数 @param father:要继承的父对象 */ function extendMehtd ( method,father ) { for (var key in father){ method.prototype[key] = father[key]; } }; 4. 构造函数实现继承 // 经过更改this的指向来实现 function Person(name, age) { this.name = name || 'hello'; this.age = age || 200; }; function Stu(sex, name, age) { this.sex = sex; // 调用Person构造函数,修改Person中的this指向为当前Student这个构造函数中new建立的对象 // 继承Person中默认的初始化属性 Person.call(this, name, age); }; var s = new Stu('male'); console.log(s); // age: 200,name: "hello",sex: "male"
js中, 每个实例对象都存在一个__proto__属性指向了本身的原型prototype; 可是原型自己也是一个对象,
也有本身的__proto__属性,指向本身的原型,以此类推就造成一个链式结构,称之为原型链...对象访问原型链中成员规则:就近原则
先看对象本身有没有,有则访问,没有则看原型有没有,有则访问,没有则看原型的原型有没有,以此类推...直到原型链的终点(null);
若是尚未 : 若是是访问属性:则返回undefined 若是访问的是方法:则会报错 xxxx is not a functioncode
以数组对象为例:对象
以上即是JS中完整的原型链图解了...
1.静态成员和实例成员 静态成员: 函数对象持有的成员(属性,方法) 实例成员: 构造函数实例化出来的对象持有的成员 2.instanceof 关键字 语法: 对象 instanceof 构造函数 做用: 用来检测右边函数的原型 是否 在左边对象的原型链中(true/false) 如: Object instanceof Object // true 3.Object.prototype(对象原型) --全部对象的原型链中都会指向它;因此全部的对象均可以访问Object.prototype原型中的成员 经常使用几个成员: 1.hasOwnProperty(): 检查对象是否包含某个成员; 条件: 本身的成员 2.isPrototypeOf(): 检查(左边)一个对象是否是(右边)另外一个对象的原型 3.propertyIsEnumerable(): 检查对象是否能够枚举某个属性 条件: (1)是本身的成员 (2)能够被for-in循环遍历 (本身的和原型的) 4.Function.prototype(函数对象Function的原型) --全部的函数对象原型都会指向Function构造函数的原型,全部的函数对象均可以访问Function.prototype中的成员 经常使用的一些成员: 1. name:获取函数名 (比较鸡肋) 2.caller:获取调用本函数的引用;经过console.log(fn.caller)能够知道本身在哪一个地方被人调用(全局调用函数,这里的caller指向null) 3.length:获取函数形参的数量; fun.length 能够知道函数设置的形参个数 4.arguments:获取函数全部的实参; 能够理解为函数内部一个隐藏的形参,做用是获取函数全部的实参,与形参一一对应... arguments对象的两个经常使用属性: 1.callee:指向函数自身, 应用于匿名函数的递归调用... arguments.callee === fn //true 2. length: 实参的个数 arguments是一个伪数组... 5.给内置的构造函数原型添加自定义成员 当内置构造函数自带的方法不够用,没法实现需求时,咱们就须要给添加自定义方法;直接添加可能会出现多我的员操做出现相同的方法名,致使被覆盖掉了 因此须要采用安全的方法添加来避免覆盖... 使用替换原型继承(自定义构造函数,将原型指向内置对象) // 经过构造函数的方式来添加; function NewArr(name) { this.name = name; }; NewArr.prototype = []; // 修改成一个空数组对象;此时NewArr的原型拥有数组对象全部的方法 NewArr.prototype.hello = { name: 'hello world', }; NewArr.prototype.min = function () { var min = Infinity; for(var i=0; i< this.length; i++) { if (this[i] < min) { min = this[i]; } }; return min; }; // 建立一个新对象 var arr1 = new NewArr('huhua'); var arr3 = new NewArr(); arr3.push(1,2,3,-1); console.log(arr3.min()); console.log(arr1); console.log(arr1.__proto__); console.log(NewArr); console.log(NewArr.prototype); console.log(NewArr.__proto__.constructor); var arr2 = [12,241,21]; console.log(arr2.min()); // 不能访问 Array.prototype:对象类型赋值的时候拷贝的是地址,修改了NewArr的原型以后,Array.prototype也会修改 []: 因为空数组的原型会指向Array.prototype,根据原型链中成员访问规则,NewArr实例对象能够访问数组成员的成员 而且,修改MyArr的原型对象,本质上是修改这个空数组,不会对Array.protpotype形成影响