js原型(prototype)和面对对象
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js原型(prototype)和面对对象相关的知识,希望对你有一定的参考价值。
prototype对象就是让你有能力向对象添加属性和方法。__proto__相当于继承了prototype。
js创建对象的五种方式:
- 工厂模式
- 构造函数模式
- 原型模式
- 混合模式(原型+构造函数)
- 动态原型模式
首先工厂模式:
1 var fn=function(){ 2 return "啊打"; 3 }; 4 function Parent(){ 5 var Child = new Object(); 6 Child.name="李小龙"; 7 Child.age="30"; 8 Child.fn=fn; 9 return Child; 10 }; 11 12 var x = Parent();//实例化 13 alert(x.name);//调用 14 alert(x.fn());
var x = {name:‘张安‘,age:22,fn:function(){return "啊打"}};他跟这种写法一样
工厂模式就是在定义一个函数,在函数内部创建Object对象,然后创建属性和方法,最后将对象作为返回值返回给调用者。
在定义方法时最好在外部定义,这样可以避免重复创建该方法。
这种方式引用对象时不推荐使用new关键字,因为使用后可能会出现一些问题,所以这里不建议使用。
其次构造函数模式:
function person(name,age){ this.name = name; this.age = age; this.family = ["爸爸","妈妈","哥哥"]; this.sayName = function(){ console.log(this.name); }; this.myFamily = function(){ var size = this.family.length; var str = "家庭成员:"; for(var i = 0;i < size;i++){ str += this.family[i]+","; } console.log(str); }; } var p = new person("张三",22); p.sayName();//张三 p.family.push("弟弟"); p.myFamily();//家庭成员:爸爸,妈妈,哥哥,弟弟 var p1 = new person("李四",22); p1.sayName();//李四 p1.myFamily();//家庭成员:爸爸,妈妈,哥哥
构造函数模式在实例化时必须使用关键字new,不然无法作为构造函数调用而是普通的函数调用,所以不能把里面的属性赋给调用者。
同时内部this的属性还会映射到外部作用域,影响到window,不推荐使用。了解就可以
如果把方法定义到外部.
var fn = function(value){ return value; }; var fnList = function(value){ var size = value.length; var str = ""; for(var i = 0;i < size;i++){ str += value[i] + ","; } return str; }; function Parent(name,age){ this.name = name; this.age = age; this.list = ["爸爸","妈妈","哥哥"]; this.sayName = fn(this.name); this.fnList = fnList(this.list); } var x = new Parent("张三",22); console.log(x); alert(x.sayName);//张三 alert(x.fnList);//爸爸,妈妈,哥哥 var y = new Parent("张三",24); y.name = "李四"; y.list.push("弟弟"); alert(y.sayName);//张三 alert(y.fnList);//爸爸,妈妈,哥哥
这样的写法在Y重新赋值后无法内部没有受影响,不明白为什么。
原型模式:
function createObject(){} createObject.prototype.name="张三"; createObject.prototype.age="22"; createObject.prototype.family=["爸爸","妈妈","儿子"]; createObject.prototype.sayName=function(){ alert(this.name); }; createObject.prototype.fnFamily=function(){ var size = this.family.length; var str = "家庭成员:"; for(var i = 0;i < size;i++){ str += this.family[i] + ","; } alert(str); }; var x = new createObject(); console.log(x); x.name="李四"; x.family.push("闺女"); x.sayName(); //李四 x.fnFamily();//家庭成员:爸爸,妈妈,儿子,闺女 var y = new createObject(); console.log(y); y.sayName(); //张三 y.fnFamily();//家庭成员:爸爸,妈妈,儿子,闺女
原型模式,就是先创建一个函数,然后用函数的prototype属性给函数添加属性和方法。prototype特点是共享。
在实例化时,new createObject()生成一个createObject.__proto__,接着x和y的__proto__继承了createObject.__proto__,所以x,y都拥有了相同的属性。
然而x在自己的作用域把那么改成李四,所以输出的是自己的name属性而不是父类的name属性,但是family用的是push是改变的父类的值。而y没有在自己的作用域改变那么值,所以调用的是父类的name值所以是张三。
这里如果变成x.fanily = [,,,],那么就是在x自己的作用域重新赋值family,这样y的fanily就不会受影响。
混合模式(原型模式+构造函数模式)
function Person(name, age){ this.name = name; this.age = age; this.family = ["爸爸","妈妈","儿子"]; } Person.prototype.sayName = function(){ alert(this.name); }; Person.prototype.fnFamily = function(){ var size = this.family.length; var str = "家庭成员:"; for(var i = 0;i < size;i++){ str += this.family[i]+","; } alert(str); }; var a = new Person("张三",22); a.sayName();//张三 a.family=["闺女"]; a.fnFamily();//闺女 var b = new Person("李四",24); b.sayName();//李四 b.fnFamily();//爸爸,妈妈,儿子
这种模式就是现在比较常用的,并且这种模式跟原型模式是结果一样的。这里我们看a的属性,a.family = ["闺女"],跟上面说的一样,这个是在自己的作用域重新赋值,没有影响到父类,所有b输出的还是爸爸,妈妈,儿子。
最后动态原型模式:
function Person(name,age){ this.name = name; this.age = age; this.family = ["爸爸","妈妈","儿子"]; if(typeof this.fnFamily != "function"){ Person.prototype.fnFamily = function(){ var size = this.family.length; var str = "家庭成员:"; for(var i = 0;i < size;i++){ str += this.family[i]+","; } alert(str); } } if(typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); } } } var x = new Person(); x.name= "小明"; x.family.push("闺女"); x.sayName();//小明 x.fnFamily();//家庭成员:爸爸,妈妈,儿子,闺女 var y = new Person(); y.sayName();//undefined y.fnFamily();//家庭成员:爸爸,妈妈,儿子
这种模式将所有的信息都封装在了构造函数里,在实例化时,通过给里面赋值来实现动态操控属性的值。
中间的if判断是为了避免重复创建函数。
总结js原型链:
function xxx(){}...
var a = new xxx();
a.__proto__继承xxx.__proto__继承object.__proto__继承null
以上是关于js原型(prototype)和面对对象的主要内容,如果未能解决你的问题,请参考以下文章