闭包是指有权访问另一个函数作用域中的变量的一个函数。简单的说,你可以认为闭包是一个特别的函数,他能够读取其他函数内部变量的函数。
正常的函数,在执行完之后,函数里面声明的变量就会被垃圾回收处理掉。但是闭包可以让一个函数作用域中的变量,在执行完之后依旧没有被垃圾回收处理掉。
内存泄漏导致变量无法被释放
栗子:
function fn2() {
const c = 3 ;
return function () {
console.log(c);
}
}
// 闭包:一个函数可以访问另一个函数的变量
// 缺点:内存泄漏导致变量无法被释放
const res = fn2() ;
res() ; //打印结果 3
编程思想分为面向过程和面向对象:
而JS并不是一个真正的面向对象的语言,js在模拟面向对象。
在对象的创建过程中,我们发现Object就是构造函数;new关键字调用构造函数就会得到一个对象。
var a=new Object('666');
console.log(typeof a); //打印结果 object
所有实例化的对象都共享方法:
var arr1 = new Array() ;
var arr2 = new Array() ;
console.log(arr1.forEach == arr2.forEach); // true
function fn() {
console.log(this);
console.log(666);
}
var res = fn() ; // this指向window
console.log(res); // 函数没有返回值 undefined
var res2 = new fn() ; // this指向了对象
console.log(res2); // 返回了这个对象
任何一个函数都有可能成为一个构造函数,只要有new就可以
为了区分普通函数和构造函数,js建议构造函数使用大驼峰命名
JS 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log('喵');
};
}
var cat1 = new Cat('大胖', '白色');
var cat2 = new Cat('二胖', '黑色');
console.log(cat1.meow === cat2.meow); //false
上面代码中,Cat函数是一个构造函数,函数内部定义了name属性和color属性,所有实例对象(上例是cat1)都会生成这两个属性,即这两个属性会定义在实例对象上面。
通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
原型:任何一个对象都有原型 __ proto __ , 也就是这个构造函数,它指向对应的构造函数的原型对象;
__ proto __ 可以用于查找一个对象是否有某个属性或方法;
function Dog(type){
this.type=type;
this.say='wang';
}
Dog.prototype.name='阿牧';
const dog=new Dog('德牧')
console.log(dog.__proto__==Dog.prototype);//true
原型对象:任何一个函数都有原型对象 prototype ,它的作用是给所有的实例化对象提供共有的属性和方法
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……(原型链的尽头就是null)
// prototype 原型对象 --- 解决属性和方法共享的问题
function person(type , age) {
// this.species = '人'
this.type = type
this.age = age
this.speak = function () {
console.log(this.age);
}
// this.say = function () {
// console.log('我是人');
// }
}
person.prototype.species = '人'
person.prototype.say = function () {
console.log('我是人');
}
var fangZong = new person('男人' , 38)
var keZong = new person('男人' , 18)
console.log(fangZong.say == keZong.say); // true
console.log(fangZong.species == keZong.species); // true
console.log(fangZong.constructor); // f person
var arr = new Array()
console.log(arr.constructor); // f array
constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的,实际上是返回自身的实例对象。由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。
上面代码中,x是构造函数Constr的实例,可以从x.constructor间接调用构造函数。这使得在实例方法中,调用自身的构造函数成为可能。
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true
instanceof运算符返回一个布尔值,用于判断一个对象是否是一个构造函数的实例化对象。
*注:instanceof运算符只能用于对象,不适用原始类型的值。
对于undefined和null,instanceOf运算符总是返回false。
undefined instanceof Object // false
null instanceof Object // false
工厂模式 创建一个对象,给对象加工(添加属性和方法) , 返回这个对象
缺点:创建出来的对象和函数没有关系 ,方法也不共享
new (创建对象,把this指向了这个对象和返回对象都由new完成了)
解决的关系问题 , 方法依然不共享
prototype 原型对象:提供共享的属性和方法
js面向对象的模拟最终版
function Fn(type) {
this.type = type ;
this.age = age ;
// this.say = function () {
// console.log('汪');
// }
}
Fn.prototype.species = '狗' ;
Fn.prototype.say = function () {
console.log('汪');
}
var dog = new Fn('狗子') ;
console.log(dog);
var dog2 = new Fn('柯基') ;
console.log(dog);
dog.say()
// 每一个实例化对象都共享say方法
console.log(dog.say == dog2.say); // true
// console.log(dog.__proto__); // 指向这个构造函数
// console.log(dog.constructor); // Fn