箭头函数、普通函数、构造函数
js构造函数详解
js中箭头函数和普通函数的区别
箭头函数特点:
1)箭头函数内部的this对象,就是函数上下文中的对象,而不是调用时的对象,不能用call,appply等方法改变this指向。
2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
3)不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替。
4)不可以使用yield命令,因此箭头函数不能用作Generator函数。
箭头函数用法:
1)使回调函数更简洁
2)搭配数组方法使用
不能使用的场景:需要用到函数方法中this的情况,不可作为构造函数使用
箭头函数没有函数名,不可以像普通函数一样作为构造函数使用,也不能用new创建实例类型。原因在于箭头函数中的this是固定的,在普通函数中this指向调用它的对象,而在箭头函数中,this永远指向其上下文。它的固定不是因为this绑定,是在于因为箭头函数没有自己的this,导致内部代码块的this就是外层代码块的this。因此箭头函数不能作为构造函数。箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
构造函数通过“new 函数名”来实例化函数,任何的普通函数都可以作为构造函数使用,它们主要是从功能上来区分的。普通函数作为可以复用的代码,构造函数主要用来创建实例对象,特点是和new一起使用。在实践中通常使用首字母大写来区分。class 为构造函数的语法糖,即 class 的本质是构造函数,在执行时会转换为构造函数执行。
匿名函数
匿名函数是一个function关键字后没有标识符的函数表达式。通过匿名函数可以实现闭包。匿名函数模拟了块级作用域,执行完匿名函数后,存储在内存中的相应变量会被销毁。使用匿名函数可以减少全局变量,降低命名冲突。
缺点:调试困难,降低代码可读性。
this对象是在运行时基于函数执行环境绑定的,在全局函数中,this=window,在函数被作为某个对象的方法调用时,this等于这个对象。
匿名函数立即执行,也称为立即执行函数表达式(IIFE)
// 无参数的匿名函数
(function () {
console.log('zxx')
})();
// 推荐使用
(function () {
console.log('zxx')
}())
// 带参数的匿名函数
(function (a, b, c) {
console.log('参数一:', a) // 参数一: 这是普通函数传参的地方
console.log('参数二:', b) // 参数二: 我是参数二
console.log('参数三:', c) // 参数三: zxx
})('这是普通函数传参的地方', '我是参数二', 'zxx')
//匿名函数赋值
let zxx = function (zxx) {
console.log(zxx)
}('zxx')
匿名函数用法
1.事件
$('#zxx').onclick = function () {
console.log('给按钮添加点击事件')
}
2.对象
var obj = {
name: 'zxx',
zxx: function () {
return this.name + ' is' + ' good girl'
}
}
console.log(obj.zxx()) // zxx is good girl
3.函数表达式
var zxx = function () {
return 'zxx is good girl'
}
console.log(zxx()) // zxx is good girl
4.回调函数
setInterval(function () {
console.log('zxx is good girl')
}, 1000)
5.作为函数的返回值
function zxx () {
// 返回匿名函数
return function () {
return 'zxx'
}
}
console.log(zxx()()) // zxx
new实现了什么
1、首先创一个新的空对象。
2、根据原型链,设置空对象的 _proto_为构造函数的 prototype ,并将this指向新创建的对象。
3、执行构造函数的代码(为这个新对象添加属性)。
4、返回这个对象。
对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通过new创建的字符串、数字是引用类型,而是非值类型。
new 被调用后大致做了哪几件事情?
📒 让实例可以访问到私有属性;
📒 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性;
📒 构造函数返回的最后结果是引用数据类型。
原型和原型链
为了将所有的对象关联起来,引入了prototype函数对象来包含所有实例对象的构造函数的属性和方法,引入了proto和原型链的概念解决继承的问题。
原型:构造函数的 prototype 属性指向了一个对象,它是调用该构造函数而创建的实例的原型,也就是原型对象,由实例对象的内置属性_proto_指向。每个原型都有一个 constructor 属性指向关联的构造函数。
原型用法:构造函数创建的实例可以访问实例的属性和方法,也可以访问原型的属性和方法。原型可以让所有实例对象共享原型包含的方法和属性,利用这个特性我们可以提取对象的公共属性和方法放在原型中。
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。
原型链:子类构造函数的prototype的__proto__指向父类构造器的prototype,通过_proto_将原型对象链接起来。原型链是多个原型的关联,本质是一串顺序指向原型对象的指针列表。
原型链用法:当实例对象访问某个属性或方法时,首先会在自己的属性里查找,找不到就会沿着_proto_指针向上查找原型对象中的属性和方法。
问题:1、由于原型的属性和方法变成实例对象的共有属性和方法,因此对原型对象属性的修改会引起其他实例的变化。2、如果重写原型对象,相当于构造函数指定了新的原型对象,而已创建的实例的_proto_仍指向旧的原型,访问不到新原型的方法。
function SuperType(){
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.Fun = function(){
};
function SubType(){
}
//继承了SuperType
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"
JS中的继承
一篇文章理解JS继承
原型链继承、构造函数继承、组合继承、原型式继承、寄生继承、寄生组合继承。ES6中新增extends继承方法。
原型链继承,将父类的实例作为子类的原型。会共享引用属性。
构造函数继承,将父类构造函数的内容复制给了子类的构造函数。会独享所有属性,包括引用属性(重点是函数)。
组合继承,利用原型链继承要共享的属性,利用构造函数继承要独享的属性,实现相对完美的继承。
原型链继承与构造函数继承恰好相反,结合使用弥补缺点,用构造函数继承属性,用原型链继承函数,形成组合继承。
原型式继承,与原型链继承优缺点相同,本质是对象的浅复制。没有方法复用。
寄生组合继承:通过借用构造函数来继承属性,通过原型链形式来继承方法,复制父类构造函数的原型作为子类的原型,解决2次调用父类函数以及复用率的问题,是一种理想的继承方法。
ES6继承的结果和寄生组合继承相似,本质上,ES6继承是一种语法糖。使用Object.setPrototypeOf()。
class 为 构造函数的语法糖,即 class 的本质是 构造函数。class的继承 extends 本质 为构造函数的原型链的继承。
两者不同点:
ES6有子类到父类的原型链指向,而ES5中是构造函数复制,没有原型链指向。
ES6中子类实例基于父类实例构建,ES5不是。
静态方法、实例方法、原型方法
静态方法:静态方法属于类,实例对象不能调用。类的静态方法只能访问静态属性。
使用上:直接在类(构造函数)上定义,或通过static关键字在类(构造函数)内部定义。
实例方法:实例方法属于对象,只有在创建了实例的情况下才可以通过实例访问。
使用上:在类(构造函数)的实例上定义,在构造函数中通过this指针定义。
原型方法:实例和构造函数(通过prototype)都可以调用,是共享的方法。
使用上:通过类的prototype定义。
实例对象不能调用静态方法,类不能调用实例方法。
使用实例方法的目的是为了更好的面向对象。
//创建一个类(构造函数,构造函数是定义类的一个方法)
var Person=function(){
console.log("person");
}
//创建这个类(构造函数)的静态方法
Person.say=function (){
console.log("aaaaa");
}
Person.say();//aaaaa
//创建这个类(构造函数)的对象实例
var zym=new Person();
console.log(zym);//Person {}
//创建实例方法
zym.sayMe=function (){
console.log("zym");
}
zym.sayMe();//zym
zym.say();//报错,实例方法无法访问静态方法
//使用class和static关键字的静态方法
class Person2{
static say(){
console.log("person2");
}
}
var zym2=new Person2();
console.log(zym2);//Person2 {}
Person2.say();//person2
//使用prototype实现原型方法
Person2.prototype.sayAge=function (age){