构造函数
之前写过一次这个内容,但是过来复习这方面知识的时候感觉写的不好,所以决定在写一次来复习一下。但是看了好几篇文章。是每个人说的风格都不太一样。知识点的起点都不太一样。所以我觉得都简单提一下。
先看一下构造函数的创建方式
function obj(name){
this.name = name;
}
obj.add = (x,y) =>{
return x+y
}
var Person = new obj('lly');
console.log(Person.name)
console.log(Person.name)
上面的代码中 obj就是一个构造函数,通过new的方式创建了一个对象。
还有俩个知识点需要了解一下。实例成员和静态成员
实例成员:是构造函数的内部通过this添加的属性,我们把他叫做实例成员。实例成员只能通过new创建对象的方式去访问。
静态成员:是构造函数在外部添加的属性,我们叫静态成员;静态成员不能通过new的方式去访问,但是可以直接通过构造函数去调用
看代码
function obj(name){
this.name = name; //实例成员
}
obj.age = 20; //静态成员
let o = new obj('cyd');
console.log(o.age) //undefind
console.log(o.name) // cyd
console.log(obj.name) //obj
console.log(obj.age) //20
这里有一点需要我们注意的是实例成员直接构造函数访问的时候,返回构造函数的名称。上代码中obj。
javascript原型
在开始说之前,先把几个关键的点说一下。记住好方便后面理解
prototype :这个只有函数才会有的属性,称之为原型。后面的继承也是需要它。
proto:对象中会有的属性指向原型,函数中也有,因为函数也是一个对象。
constructor构造函数,为啥说叫构造函数那,因为通过它可以获取构造函数
上面我们就先简单记一下这几个关键字。下面我们在详细的说明一下。
prototype
我们看下面的代码
function obj(name){
this.name = name;
}
obj.prototype.printName = function(x,y){
return x+y
}
var Person = new obj('lly');
console.log(obj.prototype)
//打印如下图
之前说到prototype说是原型,why?因为他指向的原型,我们通过obj.prototype获得的就是原型,而原型是一个对象展示出来的。
上面的代码中有一句obj.prototype.printName这句,这个的意思就是在原型上增加一个printName方法所以在下面打印的原型上会看到printName这个方法。
那我们接着看这个原型上还有俩个其他的属性。constructor和__proto__这里为了对应上面的顺序,就先说__proto__。
proto
上面我们说过,它会是对象都会有的一个属性。在对象访问这个属性的时候指向是原型对象,小二上代码。
function obj(name){
this.name = name;
}
obj.prototype.printName = function(x,y){
return x+y
}
let o = new obj('cyd');
console.log(o.__proto__)
一模一样啊,这就证实了__proto__这个也指向原型对象。那就可以的出一个结果
console.log(o.__proto__ == obj.prototype) //true
constructor
上面我们说过constructor是构造函数。why?小二上代码
function obj(name){
this.name = name;
}
obj.prototype.printName = function(x,y){
return x+y
}
let o = new obj('cyd');
console.log(o.__proto__.constructor)
console.log(obj.prototype.constructor)
//结果如下
看到这我们就明白了吧,为啥叫构造函数,因为用原型对象去访问constructor我们又可以获得其构造函数obj。所以我们叫他构造函数。我们又的到一个结果
console.log(o.__proto__.constructor == obj) //true
console.log(obj.prototype.constructor == obj) //true
问我们上面还说过,函数也是可以访问__proto__那函数去直接访问没啥实际意义,就不做讨论了。
原型链
理解了上面的内容,在理解原型链就很简单了。我们可以知道的是每一个对象都有一个__proto__,而我们的原型也是一个对象,那原型对象的__proto__是指向什么地方的那。小二上代码
function obj(name){
this.name = name;
}
obj.prototype.printName = function(x,y){
return x+y
}
let o = new obj('cyd');
console.log(o.__proto__.__proto__)
console.log(o.__proto__.__proto__.constructor)
哦嘛噶,返回的还是一个原型对象,构造函数是Object(这边说明一下,Object是根本原型对象,所有我们访问的一些对象方法都来源这边,比如object.create、assign等)就像是我们没有创建这个方法但是我们却能访问的到。
我们先接着看这个Object的原型对象的__proto__是什么东西。
console.log(o.__proto__.__proto__.__proto__) // null
null空。原来Object就是就是原型的老大了。上面没有比他更大的了。所以我们去找的时候只能是null了。这样一层一层的去找就形成了原型链。
看图
小剧场:
一个三代之家,小明想要一个苹果,他就去找他爸爸要,但是爸爸没有,他就向他的爸爸的爸爸要。结果他爸爸的爸爸有,也就是他爷爷有一个苹果,就给他了。
对象其他知识点
继承
上面说到,prototype可以用来继承。到底是怎么继承的那。小二上代码
function obj(name){
this.name = name;
this.add = function(x,y){
return x+y
}
}
obj.prototype.product = function(x,y){
return x*y
}
function obj2(age,name){
obj.call(this,name);
this.age = age
}
let a = new obj('lly');
let b = new obj2(20,'cyd');
console.log(a.name) //lly
console.log(b.name) // cyd
console.log(b.add(5,5)) //10
console.log(b.product(2,5)) //Uncaught TypeError: b.product is not a function
上面代码中我们使用call实现了实例成员的继承。但是看到原型上的就没办法进行继承。那原型对象上的怎么可以进行继承那。我们上面说过prototype继承需要它,那我们试一下。
function obj(name){
this.name = name;
this.add = function(x,y){
return x+y
}
}
obj.prototype.product = function(x,y){
return x*y
}
function obj2(age,name){
obj.call(this,name);
this.age = age
}
obj2.prototype = Object.create(obj.prototype);
obj2.prototype.ls = function(x){
return x
}
let a = new obj('lly');
let b = new obj2(20,'cyd');
console.log(a.name) //lly
console.log(b.name) //cyd
console.log(b.add(5,5)) // 10
console.log(b.ls(3)) // 3
console.log(b.product(2,5)) //10
只要加上一句 **obj2.prototype = obj.prototype;**就可以实现原型的继承。
说了这么多都还是es5,下面说说es6吧
es6就引入了类的概念。class 。先看一下使用方法吧。小二上代码
class obj{
constructor(name){
this.name = name
}
add(x,y){
return x+y
}
}
let a = new obj('lly');
console.log(a.name) //lly
console.log(a.add(5,2)) // 7
上面就是class基本的使用。class必须使用new的方式去使用。类中的方法全部都是放在原型上。
可以打印出来看一下
class obj{
constructor(name){
this.name = name
}
add(x,y){
return x+y
}
}
let a = new obj('lly');
let b = new obj('cyd');
console.log(a.__proto__ == b.__proto__) //true
Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
lass obj{
constructor(name){
this.name = name
}
add(x,y){
return x+y
}
}
class obj2 extends obj{ }
let p = new obj2('cyd');
console.log(p.name) // cyd
总结
不好意思没有总结,总结的事交给你了。