方法
对象的属性可以是任何数据类型,也可以是函数(函数就是对象)
//创建一个对象
var obj = {
age = 99,
name = flat };
//向对象中添加一个函数作为其属性之一
obj.sayName = function(){
console.log("obj.name");
};
//调用方法
obj.sayName();
如果一个函数作为一个对象的属性保存,那么这个函数就是这个对象的方法,调用函数就是调用对象的方法(method)
枚举对象中的属性
对于别人创建的对象,需要知道对象中具体的属性。
//枚举的语法:
for(var 变量 in 对象){
语句
}
//对象有几个属性,循环体就会执行几次
for(n in obj){
console.log(n); //每次执行时,会将对象中的一个属性名字赋值给n
console.log(obj.[n]); //取出属性值
}
作用域(scope) :一个变量的作用范围
(1)全局作用域 — 直接编写在<script>标签中的JS代码,都在全局作用域;全局作用域在页面打开时创建,关闭时销毁;在全局作用域中有一个全局对象window,它代表的是浏览器窗口,由浏览器创建,可以直接使用;在全局作用域中,创建的变量都会作为window对象的属性保存
function fun(){
alert("hello");
}
//fun 作为函数保存在window这个对象中
window.fun(); //也可以直接调用函数
//变量的提前声明
//使用var关键字声明的变量,会在代码执行前被声明
console.log(a);
var a = 123; //返回undefined
//因为是这样的顺序:
var a;
console.log(a);
a = 123;
//但是声明变量的时候不使用var关键字,则变量不会被提前声明
//函数的声明提前
//使用函数声明 function(){}创建的函数会在所有代码执行前被创建
//所以可以在函数声明前先调用函数
fun();
function fun (){
console.log("你好");
}
//使用函数表达式创建的函数不会被提前声明
var fun = function (){
console.log("你好");
};
全局作用域中定义的变量是全局变量,在页面中的任意部分都可以访问
(2)函数作用域 — 调用函数时创建函数作用域,函数执行完毕后销毁;每调用一次函数就会创建一个新的函数作用域,他们之间时互相独立的;在函数作用域中可以访问到全局变量;
var a =10;
function fun(){
var a = "你好";
console.log(a);
}
fun();//返回“你好”
//当在函数作用域操作一个变量时,它会现在自身作用域中寻找
//如果当前作用域没有该变量,则向上一级寻找,上一级可能是函数作用域也可能是全局
//如果全局中还没有找到则会报ReferenceError
function fun3(){
console.log(a);
var a = 12;
}
fun3(); //返回undefined
//在函数作用域中也有声明提前的特性,使用var关键字声明的变量,会在函数中所有代码执行前被声明
function fun3 (){
fun4();
function fun4(){
alert("我是第四个函数");}
}
fun3();
//函数声明也会在函数作用域中所有代码执行之前执行
var c = 33;
function fun5(){
console.log(c);
c = 10;
}
fun5(); //这里输出的是33,因为局部的c在其之后复制且没有关键字var,就没有提前声明
console.log(c);//这里输出的是10,全局的c被二次赋值了
//函数内部不写var关键字会默认设置为全局变量
//定义形参就相当于在函数作用域中声明了变量
var e = 23;
function fun(e){
//相当于在这里var e;
alert(e);
} //返回undefined
🌟 全局作用域不可以访问函数作用域,但是反过来可以。一旦函数作用域中有var关键字,那么这个变量就是函数作用域中的变量,全局作用域的值不会被覆盖;如果函数作用域中没有使用var关键字,那么默认是在全局作用域创建了一个变量。
注意区别:
var a = 123;
function fun (){
alert(a);
var a = 456;
}
fun(); //返回undefined
alert(a); //返回123,因为函数作用域中使用var关键字声明了a,全局无法访问新声明的
var a = 123;
function fun (){
alert(a);
a = 456; //没有var关键字相当于在全局赋值
}
fun(); //返回123
alert(a); //返回456
var a = 123;
function fun (a){
alert(a);
a = 456; //这里不会对全局作用域的变量a造成影响因为函数作用域定义了形参a
}
fun(); //返回undefined,设置形参就相当于var a; 但是没有赋值
alert(a); //返回123
this
解析器在调用函数时,每次都会像函数内部传递一个隐含的参数,这个隐含的参数就是this
this指向一个对象,这个对象我们称为函数执行的上下文对象。
根据函数调用方式(和函数的创建方式无关)的不同,this会指向不同的对象。
function fun (){
alert("hello");}
var obj = {name:"lexic",
age:79,
sayName: fun};
obj.sayName(); // 以方法的形式调用时,this就是调用方法的那个对象
fun(); //以函数形式调用时,this永远都是window
function fun(){
console.log(this.name); //可以更加灵活,在使用不同函数的时候返回不同的值
}
var obj = {
name:"刘星",
age: 10,
sayName:fun
};
var obj2 = {
name:"夏雪",
age: 12,
sayName:fun
};
obj.sayName(); //返回刘星
obj2.sayName();//返回夏雪
使用工厂方式创造对象(大批量对象)
//使用函数创建对象
function createPerson(name, age, address){ //设置参数可以创建不同属性值的对象
//创建一个新对象
var obj = new Object;
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.address = address;
//将新的对象返回
return obj;
}
obj2 = createPerson("夏雨",29, "19号楼");
obj3 = createPerson("外星人",190, "Mars");
使用工厂方式创建的对象,使用的构造函数都是object,所以创建的对象都是object这个类型,就导致我们无法区分出不同类型的对象。
构造函数
构造函数就是一个普通的函数,创建方式和普通函数没有区别,但是函数名称最好首字母大写;调用方式需要new关键字调用
function Person(){}
var per = Person(); //普通函数的调用方法
var per = new Person(); //构造函数的调用方法
构造函数的执行流程:1.立即创建一个新的对象。2. 将新建的对象设置成函数中this,在构造函数中可以使用this来引用新建的对象。 3.逐行执行函数中的代码。4. 将新建的对象作为返回值返回。
function Person (name, age, gender){
this.name = name; //这里和上面一样不能写死
this.age = age;
this.gender = gender; //this 指的是新创建的对象
}
var per = new Person("lee", 26, "man");
console.log(per);//这里返回的不再是object,而是person
使用同一个构造函数创建的对象,我们称之为一类对象,也将一个构造函数称为类。通过一个构造函数创建的对象,是该类的实例。
使用instanceof可以检查一个对象是否是一个类的实例,如果是则返回true,否则返回false。
console.log(per instanceof Person);
//所有的对象都是object的后代,所以任何对象和object进行instanceof检查时都会返回true。
如果想在每个对象中都使用一样的函数,最好把函数创建在全局作用域而不是构造函数中。
//第一种将会造成很多无意义的函数
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function (){
alert(this.name);
};
}
var obj1 = new Person("小赵", 24, "woman");
obj1.sayName();//每次调用该方法,就会创建出一个一样的函数,完全可以共享代码
// 第二种方法就是把sayName定义在全局作用域
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = fun;
}
function fun (){
alert(this.name);} //只会执行一次
但是写在全局作用域会污染全局作用域的命名空间,而且定义在全局作用域中也不安全,很容易被其他程序员在不知情的情况下覆盖掉。