目录
更多
方法
- 函数也可以成为对象的属性
- 如果一个函数作为一个对象的属性保存
- 那么我们称这个函数是这个对象的方法
- 调用函数我们就说调用对象的方法
- 但是它只是名称上的区别,没有其他的不同
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
/*
创建一个对象
*/
var obj =new Object();
//向对象中添加属性
obj.name = "孙悟空";
obj.age = 18;
//对象的属性值可以是任何的数据类型,也可以是个函数
obj.sayName = function(){
console.log(obj.name);
}
function fun(){
console.log(obj.name);
}
// console.log(obj.sayName);
//调方法
obj.sayName();
//调函数
fun();
</script>
</head>
<body>
</body>
</html>
枚举对象中的属性
- 想知道一个已创建好的对象中都有哪些属性
- 使用
for...in 语句
- 对象有几个属性,循环就会执行几次
- 每次执行时,都会将对象的一个属性的名字赋值给变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
var obj ={
name :"孙悟空",
age :18,
gender :"男",
address:"花果山"
}
//枚举对象中的属性
//使用for...in 语句
//for...in 语句 对象中有几个属性,循环就会执行几次
//每次执行时,都会将对象的一个属性的名字赋值给变量
for(var n in obj){
console.log("hello");
console.log(n);
console.log(obj.n);
console.log(obj[n]); //用这种方式可以传递变量
console.log("***************");
}
</script>
</head>
<body>
</body>
</html>
使用 in 检查对象中是否含有某个属性
"属性名" in 对象名
作用域
- 作用域是指一个变量的作用的范围
全局作用域
- 直接编写在 script 标签中的 JS 代码,都在全局作用域
- 全局作用域在 页面打开时 创建,在 页面关闭时 销毁
- 在全局作用域中有一个全局对象 window,
- 它代表的时一个浏览器的窗口,它是由浏览器创建,我们可以直接使用
- 在全局作用域中
- 创建的变量都会作为window对象的属性保存
- 创建的函数都会作为window对象的方法保存
- 全局作用域中的变量都是全局变量
- 在页面的任意部分都可以访问的到
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script>
/*
在全局作用域中,有一个全局对象window,
创建的变量都会作为window对象的属性保存
*/
var a =10;
console.log(window);
console.log(a);
console.log(window.a);
//在全局作用域中,创建的函数都会作为window的方法保存
function fun(){
console.log("我是fun函数");
}
fun();
window.fun();
alert("hello");
window.alert("hello");
</script>
</head>
<body>
</body>
</html>
函数(局部)作用域
- 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
- 每调用一次函数,就会创建一个新的函数作用域,他们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量
- 在全局作用域中访问不到局部的变量
- 在函数中被创建的变量没办法在全局中被直接访问
- 当在函数作用域中直接操作一个变量时,它会先看看自身作用域中是否有该变量,如果有就直接使用,如果没有就在上一级的作用域中寻找
- 直到找到全局作用域(最终)中还未找到时,就会报错
- 如果在函数中想要直接访问全局的变量,而自身作用域也有该变量时,使用
window.变量
的方式直接访问(使用window对象来访问全局变量)
- 函数作用域也有声明提前的特性
- 在函数中,不使用var声明的变量,都会成为全局变量(前提时内部函数没有声明(var)过该变量)
- 在函数中定义形参,就相当于在函数中已经声明了函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
/*
1-函数作用域
*/
function fun(){
var a= "我是fun函数中的变量a";
function fun2(){
var a = "我是fun2函数中的变量a";
console.log("a = "+a);
}
fun2();
}
fun();
/*
2- 函数作用域也有声明提前的特性
*/
//【1】在全局作用域中创建一个变量c
var c = 50;
//【2】创建一个函数
function fun(){
//(1)操作变量,优先考虑自身作用域内变量
console.log("c = "+c);
console.log("c = "+window.c);
//(2)在函数作用域中也声明一个变量c
//有以下两种形式
//-1- 使用var关键字声明,声明提前
// var c =10;
/*
在函数中,不使用var声明的变量 ,都会成为全局变量
*/
//-2- 使用这种方式,不会被声明提前,相当于函数内部没声明过该变量
c=10; //变相的修改了全局变量c
}
//【3】调用函数
fun();
//【4】在全局输出c
console.log("c ="+c);
/*
3-定义形参就相当于在函数作用域中声明了变量
*/
var e = 3;
function fun(e){
console.log("e = "+e);
}
fun();
</script>
</head>
<body>
</body>
</html>
声明提前
- 全局作用域和函数作用域都有声明提前的特性
- 变量的声明提前
- 使用var 关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
- 但是如果声明变量时不使用var关键字,则变量不会被声明提前
- 函数的声明提前
- 使用函数声明形式创建的函数创建的函数
function 函数(){}
- 它会在所有代码执行之前就被创建,所以我们可以在函数声明前来调用函数
- 使用函数表达式创建的函数,不会被声明提前,所以不能在函数声明前调用
- 使用函数声明形式创建的函数创建的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
/*
变量的声明提前
- 使用var 关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
但是如果声明变量时不使用var关键字,则变量不会被声明提前
函数的声明提前
- 使用函数声明形式创建的函数创建的函数function 函数(){}
它会在所有代码执行之前就被创建,所以我们可以在函数声明前来调用函数
- 使用函数表达式创建的函数,不会被声明提前,所以不能在函数声明前调用
*/
console.log("a = "+a);
var a ; //用var关键词声明变量 声明提前
a = 123; //赋值不一定提前
//var a = 123; //该形式域上面两行作用相同
fun();
fun2();
//函数声明,会被提前创建
function fun(){ //函数声明方式创建函数
console.log("我是一个fun 函数");
}
//函数表达式,不会被提前创建
var fun2 = function(){
console.log("我是fun2函数");
}
</script>
</head>
<body>
</body>
</html>
this
- 解析器在调用函数时,每次都会向函数内部传递进一个隐含的参数,
- 这个隐含的参数就是this,this指向的就是一个对象
- 这个对象我们称为函数执行的上下文对象
- 根据函数调用方式的不同,this 会指向不同的对象
- 以函数的形式调用,this永远都是window
-
fun()
-
- 以方法的形式调用时,this就是调用方法的那个对象
- 以函数的形式调用,this永远都是window
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function fun(){
console.log(this);
}
//创建一个对象
var obj = {
name :"孙悟空",
sayName: fun
}
//以函数形式调用
fun();
//以方法的形式调用
obj.sayName();
console.log("********");
/*
补充
*/
var name = "全局";
function fun(){
console.log(name);
console.log(this.name);
}
var obj = {
name : "孙悟空",
sayName:fun
}
var obj2 = {
name : "沙和尚",
sayName:fun
}
obj.sayName();
obj2.sayName();
</script>
</head>
<body>
</body>
</html>
工厂方法创建对象
- 使用工厂方法创建对象(为将大量重复性代码提取至一个对象或方法中)
- 通过该方法可以大批量的创建对象
- 所谓工厂,就是将属性传进去,返回一个对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
/*
创建一个对象
*/
// var obj = {
// name:"孙悟空",
// age:18,
// gender:"男",
// sayName:function(){
// alert(this.name);
// }
// }
// obj.sayName();
/*
使用工厂方法创建对象(为将大量重复性代码提取至一个对象或方法中)
通过该方法可以大批量的创建对象
所谓工厂,就是将属性传进去,返回一个对象
*/
function createPerson(name,age,gender){
//创建一个新的对象
var obj = new Object();
//向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName=function(){
alert(this.name);
}
//将新的对象返回
return obj;
}
//传入属性,返回对象
var obj2 =createPerson("至尊宝",18,"男");
var obj3 =createPerson("孙悟空",18,"男");
var obj4 =createPerson("白晶晶",18,"女");
console.log(obj2);
obj2.sayName();
console.log(obj3);
obj3.sayName();
console.log(obj4);
obj4.sayName();
</script>
</head>
<body>
</body>
</html>
- 使用工厂方法创建的对象,使用的构造函数都是 Object
- 所以创建的对象都是Object这个类型,就导致我们无法区分出多种不同类型的对象(这种情况考虑下面构造函数的方式来引用对象)
构造函数
创建一个构造函数,专门用来创建不同名称的对象
var per = new Person();
构造函数就是一个普通的函数,创建方式和普通函数没有区别
不同的是构造函数习惯上首字母大写
构造函数的执行流程(系统)
- 立即创建一个新的对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用创建的对象
- 逐渐执行函数中的代码
- 将新建的对象作为返回值返回()
- 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
- 我们通过一个构造函数创建的对象,称为是该类的实例
- 使用
instanceof
可以检查一个对象是否是一个类的实例- 语法:
对象 instanceof 构造函数
- 如果是,返回true,否则返回false
- 所有的对象都是Object的后代,
- 所以任何对象和Object做instanceof检查时都会反会true。Object类似一个父类
- 语法:
this的情况
- 当以函数的形式调用时,this是window,
- 当以方法的形式调用时,谁调用方法this就是谁
- 当以构造函数的形式调用时,this就是新创建的那个对象
初始练习代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>构造函数</title>
<script>
//Person 类
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName=function(){
alert(this.name);
}
}
//创建对象
var per =new Person("至尊宝",18,"男");
var son =new Person("孙悟空",17,"男");
// console.log(per);
// console.log(son);
console.log(per instanceof Person);
//Dog 类
function Dog(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayHello=function(){
alert("汪汪~~");
}
}
var dog = new Dog("Harry",3,"雄");
// console.log(dog);
// dog.sayHello();
</script>
</head>
<body>
</body>
</html>
构造函数修改
- 创建一 个Person构造函数
- 在Person构造函数中,为每一个对象都添加了一个
sayName
方法,- 目前我们的方法是在构造函数内部创建的,
- 也就是构造函数每执行一次就会创建一个新的sayName方法
- 也是所有实例的sayName都是唯一的。
- 这样就导致了构造函数执行一次就会创建一 个新的方法,
- 执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的
- 占内存,这是完全没有必要的,完全可以使所有的对象共享同一个方法
- 目前我们的方法是在构造函数内部创建的,
- 在Person构造函数中,为每一个对象都添加了一个
- 解决方法:
- 可以将syaName方法在全局作用域中定义
- 但是:
- 将函数定义在全局作用域,污染了全局作用域的命名空间
- 而且定义在全局作用域中也很不安全
初步修改后练习代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>构造函数修改版</title>
<script>
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName=fun;
}
//将sayName方法在全局作用域中定义
function fun(){
alert("大家好,我是" + this.name);
}
var per =new Person("至尊宝",18,"男");
var son =new Person("孙悟空",17,"男");
//检验使用的方法是不是共用的同一个方法
console.log(per.sayName==son.sayName);
per.sayName();
son.sayName();
</script>
</head>
<body>
</body>
</body>
</html>
原型对象
原型 prototype
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性
prototype
- 这个属性对应着一个对象(存有该对象的地址,或者说指向该对象),这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用prototype没有任何作用
- 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
- 指向该构造函数的原型对象,我们可以通过
__proto__
来访问该属性
- 指向该构造函数的原型对象,我们可以通过
- 原型对象就相当于一块公共区域,所有同一个类的实例都可以访问到这个原型对象,
- 我们可以将对象中共用的内容,统一设置到原型对象中
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
- 如果没有则会去原型对象中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
- 这样不用分别为每一个对象添加, 也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型</title>
<script>
/*
原型 prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
这个属性对应着一个对象(存有该对象的地址,或者说指向该对象),这个对象就是我们所谓的原型对象
如果函数作为普通函数调用prototype没有任何作用
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
指向该构造函数的原型对象,我们可以通过 __proto__ 来访问该属性
原型对象就相当于一块公共区域,所有同一个类的实例都可以访问到这个原型对象,
我们可以将对象中共用的内容,统一设置到原型对象中
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果找到则直接使用
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
这样不用分别为每一个对象添加, 也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
*/
function MyClass(name){
this.name = name;
}
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
MyClass.prototype.sayName = function(){
alert("我是一只"+this.name);
}
var mc = new MyClass("猫");
var mc2 = new MyClass("狗");
console.log(MyClass.prototype);
console.log(mc.__proto__);
//判断MyClass的Prototype属性和MyClass创建的实例对象的隐含属性__proto__指向的是不是同一个对象(原型对象)
console.log(MyClass.prototype==mc.__proto__);
//判断此时它们的sayName方法是不是共用的同一个
console.log(mc.sayName==mc2.sayName);
</script>
</head>
<body>
</body>
</html>
- 使用 in 检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回 true
- 语法:
"属性名" in 对象名
- 可以使用对象的
hasOwnProperty()
来检查对象自身中是否含有该属性- 使用该方法只有当对象自身中含有属性时,才会返回 true
- 语法:
对象名.hasOwnProperty("属性名")
hasOwnProperty
方法在原型对象中
- 原型对象也是对象,所以它也有原型 ,
- 当我们使用一个对象的属性或方法时,会先在自身中寻找,
- 自身中如果有,则直接使用,
- 如果没有则去原型对象中寻找,如果原型对象中有,则使用
- 如果没有则去原型的原型中寻找,直到找到Object对象的原型
- Object对象的原型没有原型,找到这里还没找到,直接返回undefined
- 调取原型对象,如果某级没有原型对象,会返回null ,
mc.__proto__.__proto__.__proto__
,返回null时,证明mc对象的原型的原型没有原型对象,或者说原型的值是null,
- 当我们使用一个对象的属性或方法时,会先在自身中寻找,
toString
- 当我们直接在页面中打印一个对象时,事实上是输出对象的toString()方法的返回值
- 如果我们希望在输出对象时不输出[object Object], 可以为对象添加一个toString( )方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>toString</title>
<script>
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.toString = function(){
return "Person[name = "+this.name+",age = "+this.age+",gender = "+this.gender+"]";
}
var per =new Person("至尊宝",18,"男");
//当我们直接在页面中打印一个对象时,事实上是输出对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[object Object], 可以为对象添加一-个toString( )方法
// per.toString = function(){
// return "Person[name = "+this.name+",age = "+this.age+",gender = "+this.gender+"]";
// }
console.log(per);
console.log(per.toString());
console.log(per.toString()==per);
</script>
</head>
<body>
</body>
</html>
垃圾回收(GC)
- 就像人生活的时间长了会产生垃圾一样,程序运行过程中也会产生垃圾 这些垃圾积攒过多以后,会导致程序运行的速度过慢,
- 所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象, 此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
- 我们不需要也不能进行垃圾回收的操作 - 我们需要做的只是要将不再使用的对象设置null即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>垃圾回收</title>
<script>
/*
垃圾回收(GC)
- 就像人生活的时间长了会产生垃圾一样,程序运行过程中也会产生垃圾
这些垃圾积攒过多以后,会导致程序运行的速度过慢,
所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,
此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,
我们不需要也不能进行垃圾回收的操作
- 我们需要做的只是要将不再使用的对象设置null即可
*/
var obj = new Object();
//想将这个对象回收
//令这个对象的引用等于0
obj = null;
console.log(obj);
</script>
</head>
<body>
</body>
</html>