js的对象与函数详解
一、对象
就是人们要研究的任何事物,不仅能表示具体事物,还能表示抽象的规则,计划或事件。
属性的无序集合,每个属性可以存一个值(原始值,对象,函数)
对象的特性:封装,尽可能的隐藏对象的部分细节,使其受到保护。只保留有限的接口和外部发生联系。
js 中{},[] 来定义数组和对象
1.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数。
2.[ ]中括号,表示一个数组,也可以理解为一个数组对象。
3.{ } 和[ ] 一起使用,我们前面说到,{ } 是一个对象,[ ] 是一个数组,我们可以组成一个对象数组
调用起来对象的属性用.(点)叠加/对象名['属性名称'],数组用 [下标] 来访问。
二、Js自定义对象的2种方式
1、对象初始化器构造对象
var marry={ name:"marry", age:2, shout:function(){ alert("我是:"+this.name+",今年:"+this.age); }, action:function(){ alert("会吃"); } }; alert(marry.name); alert(marry.age); marry.shout(); marry.action();
2.定义对象的内存分别
当我们创建一个对象 ren,会在栈内存中保存一个地址,栈为长度不可变的地址。
而栈中的地址就对应堆中的存储地址。堆中的存储地址,只要实例化会在堆中开辟一块空间,地址就是栈的地址,内容就是实例化对象里面的内容,如name,sex,eat。可以通过地址引用,访问里面的属性和方法。
当我们再实例化一个对象,又会保存另一个地址及开辟一块空间。
代码段,共同的属性或方法放在代码段中,不在堆中。只执行一次,节省内存空间。代码段会一直存在内存的空间中,知道浏览器关闭。使用prototype方法创建
var ren ={}; ren.name="张三"; ren.sex="男"; ren.eat=function () { alert("吃饭"); } alert(ren.name); alert(ren["name"]);
3.工厂模式
工厂模式虽然解决多次创建相似对象的重复性问题,但是并没有解决对象识别问题,也就是typeof之后他都显示object,具体的对象是什么并没有显示。
function createPerson(name,age,job) { var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name);//this指的是o } return o; } var person1=createPerson("Tom",23,"厨师"); person1.sayName();
4、构造函数方式
构造函数模式和工厂模式的区别
1.没有显式的创建对象。
2.将属性和方法赋给了this对象。
3.没有return语句。
4.函数名第一个字母大写。
构造函数模式优于工厂模式的原因就是,构造函数模式中的对象实例(person1)通过constructor属性或instanceof操作符可以验证person1既是Object的实例,也是Person的实例,同时也证明所有对象均来自于Object。
function Person(name,age,job) { this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name);//this是Person } } var person1=new Person("Tom",23,"厨师"); person1.sayName();
function Dog(name,age){ this.name=name; this.age=age; this.shout=function(){ alert("我是:"+this.name+",今年:"+this.age); }; this.action=function(){ alert("会吃"); }; } var jack=new Dog("jack",1); alert(jack.name); alert(jack.age); jack.shout(); jack.action();
5.全局作用域
但是构造函数也有缺点,对象是引用类型,对象实例化不是指针的改变,而是简单的复制,复制对象的方法和属性,假设一个对象有上千个实例,它就会复制上千个功能相同的方法,这显然是不可取的。
我们也可以把sayName()函数的定义战役到构造函数的外部,这样我们就将sayName属性设置成等于全局的sayName函数,这样实例化对象就共享全局作用域中的同一个sayName(),解决了构造函数对象方法的多次创建问题。但是全局作用域定义的sayName()函数只能被某个对象调用谈什么全局作用域,而且如果构造函数对象的方法有很多,就需要定义很多全局函数,封装性又从何谈起,于是原型模式应运而生。
function Person(name,age,job) { this.name=name; this.age=age; this.job=job; this.sayName=sayName; } function sayName(){ alert(this.name) } var person1=new Person("Tom",23,"厨师"); person1.sayName();
6.构造函数创建对象
定义对象模拟数组,arguments为js内置的对象。
function myArray () { var lengs= arguments.length; for (var i=0; i<lengs; i++) { this[i]=arguments[i]; } } var arr=new myArray(1,2,3); alert(arr[0]);
7.js动态构造对象
<script type="text/javascript"> /* function speak(something){ alert(something); } */ /* var p=new Object(); p.name="Jack"; // 动态的添加属性 p.func=speak; // 动态的添加方法 alert(p.name); p.func("Hello,Hello,大家好!"); */ /* delete p.name; //删除属性 输出undefine alert(p.name); delete p.func; p.func("Hello,Hello,大家好!"); */ /* p.name=undefined; p.func=undefined; alert(p.name); p.func("Hello,Hello,大家好!"); */ function person(name,age){//构造方法 this.name2=name;//给当前对象动态添加属性 this.age2=age; function speak(something){ alert(something); } this.func=speak; } var p1=new person("Jack",12); alert(p1.name2); p1.func("Hello,EveryOne!"); </script>
三、原型模式创建对象
我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象中包含着所有对象实例的属性和方法,这个对象就是原型对象。通俗的说,原型对象中的方法和属性可以被所有对象的实例所共享,对象实例就不用多次创建相同的方法和属性。
function Person(){ }; Person.prototype={ name:"Tom", age:23, job:"web前端工程师", sayName:function(){ alert(this.name); } } var person1=new Person(); person1.sayName();
1.工厂函数封装,通过一个函数封装起来
function dianshi (color,size,brand) { var Tv={}; Tv.color=color; Tv.size=size; Tv.brand=brand; Tv.look=function () { alert("看电视"); } Tv.play=function () { alert("玩游戏"); } Tv.dvd=function () { alert("DVD"); } return Tv; } var ds=dianshi("red","30inch","sony"); //alert(typeof ds)//返回object alert(ds.color) var ds1=dianshi("blue","40inch","changh"); alert(ds1["size"])//传递参数
2.构造函数
function Tv(color,size,brand) { this.color=color;//那个对象引用this就代表那个对象 this.size=size; this.brand=brand; this.play=function () { alert("玩游戏"); } this.look=function () { alert("看电视"); } } var sony=new Tv("red","20 inch","sony"); alert(sony.color)
3.prototype方法
共同的属性与方法放在代码段,节省内存空间
function Tv(color,size,brand) { this.color=color; this.size=size; this.brand=brand; this.play=function () { alert("玩游戏"); } } Tv.prototype.look=function () { alert("看电视"); } Tv.prototype.dvd=function () { alert("DVD"); } Tv.prototype.aaa={name:"张三"};//只能共享属性或函数,不能共享对象 var sony=new Tv("red","20 inch","sony"); var changhong =new Tv("red","20 inch","CH"); delete sony.color delete sony.play//undefine delete sony.look//能访问到 sony.look(); changhong.look(); sony.aaa.name="李四"//李四 changhong.aaa.name//李四 全局对象Array扩展增加removeByValue方法 Array.prototype.removeByValue = function(val) { for(var i=0; i<this.length; i++) { if(this[i] == val) { this.splice(i, 1); break; } } }
虽然可以通过对象实例访问保存在原型对象中的值,但却不能通过对象实例重写原型的值。其实对象实例获取某一属性的值是从本身开始寻找,然后是原型对象,最后是构造函数对象,所以重写对象实例的属性值(这个值可以通过delete操作符删除)仅仅是阻断了获取原型属性值的途径,但是没有改变其中的值。
function Person(){ }; Person.prototype.name="Tom"; Person.prototype.age=23; Person.prototype.job="厨师"; Person.prototype.sayName=function(){ alert(this.name); } var person1=new Person(); var person2=new Person(); person1.name="Mike"; alert(person1.name); alert(person2.name); alert(person1.name); alert(person2.name);
4.面向对象创建对象
用面向对象语法表示的时候,原型对象的constructor属性不在指向Person,因为每创建一个函数,同时会创建它的prototype对象,用面向对象语法本质上相当于重写了prototype对象,constructor属性也会变成新对象的constructor属性(这里指向Object)
function Person(){ }; Person.prototype={ constructor:Person, name:"Tom", age:23, job:"厨师", sayName:function(){ alert(this.name); } } var person1=new Person(); var person2=new Person(); person1.name="Mike"; alert(person1.name); alert(person2.name);
原型模式的缺点:因为所以对象实例共享原型对象的方法和属性,但是往往实例都有他自己私有的属性,这时候原型模式就不适用了,所以我们可以混合使用构造函数模式和原型模式。
5.混合方法
组合使用构造函数模式和原型模式结合了构造函数和原型模式的优点,构造函数定义实例的私有属性,原型模式定义共享属性和方法。
function Tv(color,size,brand) { this.color=color; this.size=size; this.brand=brand; this.play=function () { alert("玩游戏"); } Tv.prototype.aaa={name:"张三"}; } Tv.prototype.look=function () { alert("看电视"); } Tv.prototype.dvd=function () { alert("DVD"); } }
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; }; Person.prototype={ constructor:Person, sayName:function(){ alert(this.name); } } var person1=new Person("Tom"); var person2=new Person("Mike"); alert(person1.name); alert(person2.name);
四、js对象属性
如果属性的值是函数,我们叫做他是对象的方法,否则叫做是属性。
1.私有属性,对象属性,类属性
<script type="text/javascript"> function C(){ this.objPro="对象属性"; C.prototype.objPro2="对象属性2";//原型 var privatePro="私有属性";//只能在方法内部使用 } C.classPro="类属性"; alert(C.classPro); var c=new C(); alert(c.objPro); alert(c.objPro2); </script>
2.私有方法,对象方法,类方法
<script type="text/javascript"> function C(){ var privateFunc=function(){ alert("私有方法"); }; privateFunc(); this.objFunc=function(){ alert("对象方法"); }; C.prototype.objFunc2=function(){ alert("对象方法2"); }; } C.classFunc=function(){ alert("类方法"); }; C.classFunc(); var c=new C(); c.objFunc(); c.objFunc2(); </script>
五、js函数
1. 函数的定义:
1.采用关键字function来定义
function fun(){ alert("大家好") } // fun() ;
2.采用匿名函数的方式(采用function作为名字)
var a = function(){ alert("我是匿名函数") ; } // a() ;
3.采用new Function()的方式
小括号中最后一个参数是函数体,之前所有的参数都是形参.
var b = new Function("x","y","z","alert(x+y+z)") ; // b(3,4,5) ;
前面是参数,最后的是方法体
var sayFunc=new Function("name","age","alert(name+'今年'+age+'岁了')"); // sayFunc("李四",4); alert("sayFunc方法对象的方法参数个数:"+sayFunc.length); alert(sayFunc.toString());//获取源码 alert(sayFunc.valueOf());//获取源码
2.调用函数:
调用函数的时候是用函数名来寻找的,函数名(参数)
初始化函数/自调函数
(function () {alert("函数调用");})();
3.函数劫持
函数劫持:改变javascript的预定义的函数预定义好的功能
window.alert = function(x){ document.write(x) ; } alert("abc") ;
4.函数表达式
var fun = function(){ alert('我是函数表达式的形式') } fun();//函数调用
注意:
1.如果两个函数的命名相同,后面的将会覆盖前面的函数。
2.以基本语法声明的函数,会在代码运行的时候,提前加载到内存当中,以供以后使用,但是匿名函数形式命名的函数,会在执行到的时候,才进行赋值
3.在不同的<script></script>块中的函数,使用和调用的时候,应该先定义,后执行。
4.函数参数arguments对象
每创建一个函数,该函数就会隐式创建一个arguments数组对象,他包含有实际传入参数的信息。
- 1.length 检测实际传入参数的个数
- 2.callee 对本身的调用
访问传入参数的具体的值:([下标])
function fun (a,b) { for (var i=0; i<arguments.length; i++) { alert(arguments[i]) } }
若有不足请多多指教!希望给您带来帮助!
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接
下一篇:JS实现求5的阶乘示例