this
- 解析器在调用函数每次都会向函数内部传递一个隐含的参数
- 这个隐含的参数就是this,this指向的是一个对象
- 这个对象我们称为函数执行的上下文对象
- 根据函数的调用方式不同,this指向不同的对象
function fun(a){
console.log(a);
console.log(this); // object window obj
}
fun(3);
function fun(){
console.log(this.name);
}
var obj = {
name:'bob',
say:fun
}
var obj2 = {
name:'tom',
say:fun
}
fun(); // 以函数的形式调用,this永远都是 window
obj.say(); // bob 以方法的形式进行调用时,this就是调用方法的那个对象 this -》 obj
obj2.say(); // tom
function fun(){
console.log(obj.name);
}
var obj = {
name:'bob',
say:fun
}
var obj2 = {
name:'tom',
say:fun
}
obj.say(); // bob,但是如果在创建一个对象
obj2.say(); // bob 在这里面写死了,就不行
使用工厂方法创建对象
- 通过该方法大批量创建对象
function box(){
// 创建一个新对象
var obj = new Object();
// 向对象中添加属性
obj.name = 'tom',
obj.ahe = 13,
obj.gender = 'man',
obj.say = function(){
alert(this.name);
}
// 将新的对象返回
return obj;
}
var box1 = box();
var box2 = box(); // 虽然创建方便但是比较固定,每次返回的属性都是相同
// 传参会灵活
function box(name,age,gender,){
// 创建一个新对象
var obj = new Object();
// 向对象中添加属性
obj.name = name,
obj.age = age,
obj.gender = gender,
obj.say = function(){
alert(this.name);
}
// 将新的对象返回
return obj;
}
构造函数
-
使用工厂方法虽然可以节省代码冗余,但是使用构造的函数都是Object这个类型,导致我们无法准确的去区分类。
-
构造函数:就是一个普通的函数,不同是构造函数习惯首字母大写
-
普通函数与构造函数的区别
- 普通函数直接调用,而构造函数需要使用new关键字来调用
-
构造函数的执行过程
- 1.立即创建一个新的对象
- 2.将新建的对象设置为函数中的this
- 3.逐行执行函数中的代码
- 4.将新建的对象作为返回值返回
-
使用同一个构造函数所创建的对象,我们称为一类对象,也将一个构造函数称为一个类
- 将通过一个构造函数创建的对象,称为该类的实例
-
function Box(){ this.name = 'tom', // this就代表新建box这个对象,name加入到新对象中 this.age = 18, this.say = function(){ alert(this.name); } } var box = Box(); // 改造 function Box(name,age){ this.name = name, // this就代表新建box这个对象,name加入到新对象中 this.age = age, this.say = function(){ alert(this.name); } } var box1 = Box('bob',12); var box2 = Box('tom',13); // 箱子类的实例
-
使用instanceof检查一个对象是否是一个类的实例
-
console.log(box instanceof Box); // true console.log(box instanceof Object); // 所有对象都是Object的后代
-
构造函数的修改
-
创建Box构造方法
-
构造函数每执行一次就会创建一个新的say方法
-
但是大量的对象创建的say方法都是一样的方法,可以实现共享方法
-
将say方法在全局作用域中创建
-
// 在全局作用域中定义 function fun(){ alert(this.name); } function Box(name,age){ this.name = name, this.age = age, // 向对象中添加方法 节省了大量的空间 this.say = fun; } var box1 = Box('bob',12); var box2 = Box('tom',13); console.log(box1.say == box2.say); // true
-
原型对象
-
引出原因:
- 将say方法在全局作用域中定义
- 污染了命名空间,在全局作用域中不安全,有局限
-
原型:prototype
-
我们所创建的每一个函数解析器都会向函数中添加一个属性prototype
-
这个属性对应着一个对象,这个对象就是我们说的原型对象
-
普通函数调用prototype没有任何作用
-
当函数以构造函数调用时,它所创建的对象中都会有一个隐含的属性
-
指向该函数的原型对象,我们可以通过
__proto__
来访问该属性function Box(){ } var box = new Box(); console.log(Box.prototype); console.log(box.__proto__); console.log(box.__proto__ == Box.prototype ); // true
-
-
原型对象相当于一个公共的区域,所有同一个类的实例都以访问到这个原型对象
-
当我们访问对象的一个属性或方法时,它会先在对象的自身中寻找,如果没有则回去原型对象中去查找
-
这样接解决构造函数中,防止污染去全局中的命名空间
-
function Box(name,age){ this.name = name, this.age = age } Box.prototype.a = 123; Box.prototype.say = function(){this.name} var box1 = Box('bob',12); var box2 = Box('tom',13); console.log(box1.say == box2.say); // true box1.say(); // bob 去原型对象中取 // hasOwnProperty()来检查对象自身中是否含有该属性 console.log(box1.hasOwnProperty('age'); // true console.log(box1.hasOwnProperty('a'); // false
-
-
总结:以后我们在创建构造函数时,可以将这些对象共有的属性和方法,同一添加到构造函数的原型对象中,不会影响全局作用域
扩展原型对象
原型对象也是对象,它也有原型
- 知道找到Object原型停止,如果在Object中仍然找不到我们使用对象的属性或者方法时,则会返回undefined
console.log(box1.__proto__.hasOwnProperty("hasOwnProperty")); // false
console.log(box1.__proto__..__proto__.hasOwnProperty("hasOwnProperty")); // true
toString() 方法:
当我们直接在页面中打印一个对象,实际上是输出的对象的toString()方法的返回值
可以改变返回值
function Box(name,age){
this.name = name,
this.age = age
}
var box1 = Box('tonm',12);
box1.toString = function(){
return 'hello world';
}
var res = per.toString();
console.log(res); // 控制台将会返回'hello world' ,而不是[object Object]
box1.toString = function(){
return "Box[name="+this.name+",age="+this.age+"]";
}
console.log(box1); // 这样就可以打印具体的信息
// 修改原型对象中的toString()方法,这样以后创建的对象返回的值都会改变
Box.prototype.toString = function(){
return "Box[name="+this.name+",age="+this.age+"]";
}
垃圾回收(GC)
程序运行时间长了,就会产生垃圾,这些垃圾积攒之后,会导致程序运行速度缓慢
我们需要一个垃圾回收机制,来处理运行程序中的产生的垃圾
当一个对象没有任何的变量或者属性对它引用,此时将无法操作该对象
这种垃圾太多,会占用大量的内存空间,导致程序运行时间变慢,必须进行清理
在Js中有自动的垃圾回收机制,自动将垃圾对象从内存中销毁,浏览器引擎处理
var obj = new Object();
obj = null;// 浏览器就可以识别