创建对象三种方式
1.字面量的方式
var per1={ name:"沐风", age:20, sex:"男", eat:function () { console.log("吃"); }, readBook:function () { console.log(""); } };
2.调用系统的构造函数
var per2=new Object(); per2.name="沐风"; per2.age=30; per2.sex="男"; per2.eat=function () { console.log("吃"); }; per2.play=function () { console.log("玩"); };
3.自定义构造函数方式(推荐)
function Person(name,age,sex) { this.name=name; this.age=age; this.sex=sex; this.play=function () { console.log("天天打游戏"); }; } var per=new Person("沐风",18,"男"); console.log(per instanceof Person);
工厂模式
function createObject(name,age) { var obj=new Object(); obj.name=name; obj.age=age; obj.sayHi=function () { console.log("您好"); }; return obj; }
原型
1.构造函数方法很好用,但是存在一个浪费内存的问题
function Cat(name, color) { this.name = name; this.color = color; this.type = "猫科动物"; this.eat = function () { alert("吃老鼠"); }; } var cat1 = new Cat("大毛", "黄色"); var cat2 = new Cat("二毛", "黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠
2.Prototype模式,所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function () { alert("吃老鼠") }; var cat1 = new Cat("大毛", "黄色"); var cat2 = new Cat("二毛", "黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠 alert(cat1.eat == cat2.eat); //true
简单的原型写法
Student.prototype = { //手动修改构造器的指向 constructor:Student, height: "188", weight: "55kg", study: function () { console.log("学习好开心啊"); }, eat: function () { console.log("我要吃好吃的"); } }; var stu=new Student("段飞",20,"男"); stu.eat(); stu.study(); console.dir(Student); console.dir(stu);
我们可以为系统的对象的原型中添加方法,相当于在改变源码
//我希望字符串中有一个倒序字符串的方法 String.prototype.myReverse=function () { for(var i=this.length-1;i>=0;i--){ console.log(this[i]); } }; var str="abcdefg"; str.myReverse();
回调函数
当我们将函数A传递给函数B,并由B来执行A时,A就成了一个回调函数(callback ftmctions)。如果这时A还是一个无名函数,我们就称它为匿名回调函数。
function FunA(a,b,callback) { return callback(a, b); } function FunB(a,b) { return a + b; } alert(FunA(1,2,FunB));
还可以用匿名函数代替FunB
function FunA(a,b,callback) { return callback(a, b); } alert(FunA(1,2,function(a,b){return a + b}));
自调函数
(function (name) { alert("我的名字是:"+name) })("mf")
缺点:无法重复利用
优点:不会产生任何全局变量,适合一次执行或初始化任务
如何把局部变量变成全局变量?
把局部变量给window就可以了
(function (win) { var num=10;//局部变量 //js是一门动态类型的语言,对象没有属性,点了就有了 win.num=num; })(window); console.log(num);
通过自调用函数产生一个随机数对象,在自调用函数外面,调用该随机数对象方法产生随机数
(function (window) { //产生随机数的构造函数 function Random() { } //在原型对象中添加方法 Random.prototype.getRandom = function (min,max) { return Math.floor(Math.random()*(max-min)+min); }; //把Random对象暴露给顶级对象window--->外部可以直接使用这个对象 window.Random=Random; })(window); //实例化随机数对象 var rm=new Random(); //调用方法产生随机数 console.log(rm.getRandom(0,5));
内部私有函数
var FunA = function (parmA) { var FunB = function (parmB) { return parmB * 2; } return "结果是:" + FunB(2); }
优点:有助于我们确保全局名字空间的纯净性,命名冲突的机会更小
私有性:可以选择将必要的函数暴露给外界,并保留属于自己的函数
返回函数的函数
var FunA = function () { alert("A"); return function () { alert("B"); }; } var A = FunA();//第一次输出A 返回的是函数引用,并不会产生函数调用 A();//第二次输出B
能重写自己的函数
function FunA() { alert("A"); //全局变量A被重新定义并被赋予新的函数 A= function () { alert("B"); }; } FunA();//第一次输出A A();//第二次输出B
闭包
1.闭包概念
作用域链
词法作用域
利用闭包突破作用域链
2.闭包的用途
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。而反过来我们有时候需要得到函数内的局部变量,出于种种原因,正常情况下,这是办不到的,只有通过变通方法才能实现。