创建对象可以用
1.object构造函数方法
person=new Object();
person.firstname="Bill";
person.lastname="Gates";
person.age=56;
person.eyecolor="blue";
2.对象字面量
var person ={
name:xxx,
...
}
上述两种方法都会产生大量重复的代码,解决该问题可抽象创建具体对象的过程(因为js在没有类的概念,所以用函数来封装)
3.工厂模式
function a(name){
var b = new object();
b.name = name;
b.say = function(){
alert(this.name);
}
return b
}
缺陷:创建两个完成同样任务的function实例没有必要,改进:
4.构造函数方法
function person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
this.changeName=changeName;
function changeName(name)
{
this.lastname=name;
}
}
缺陷:如果对象有多个方法就需要定义多个全局函数,就没有封装性可言了,改进
5.原型模式
每个函数都有一个Prototype(原型属性),这个属性是一个指针,指向一个对象。
使用原型对象的好处就是让所有对象实例共享它所包含的属性和方法。换句话说:不必在构造函数中定义对象实例的信息,而是可以把这些信息添加到原型链中。
function Person(){
}
Person.prototype.name = "bill";
Person.prototype.address = "GuangZhou";
Person.prototype.sayName = function (){
alert(this.name);
}
var person1 = new Person();
//测试代码
alert(person1.name); // bill
person1.sayName(); //bill
每个函数都有 prototype 属性,除了 Function.prototype.bind(),该属性指向原型。
每个对象都有 proto 属性,指向了创建该对象的构造函数的原型。其实这个属性指向了 [[prototype]],但是 [[prototype]] 是内部属性,我们并不能访问到,所以使用 proto 来访问。
对象可以通过 proto 来寻找不属于该对象的属性,proto 将对象连接起来组成了原型链。
原型、构造函数、实例三者之间的关系
-
1、构造函数通过 new 生成实例
-
2、构造函数也是函数,构造函数的
prototype
指向原型。(所有的函数有prototype
属性,但实例没有prototype
属性) -
3、原型对象中有 constructor,指向该原型的构造函数。
-
4、实例的
__proto__
指向原型。也就是说,Foo.__proto__ === M.prototype
。 -
声明:所有的引用类型(数组、对象、函数)都有
__proto__
这个属性。Foo.__proto__ === Function.prototype
的结果为true,说明Foo这个普通的函数,是Function构造函数的一个实例。
原型链
看一下什么是原型链。
原型链就是通过原型对象,原型链与实例之间组成的链条。
原型链的基本原理:任何一个实例,通过原型链,找到它上面的原型,该原型对象中的方法和属性,可以被所有的原型实例共享。
Object是原型链的顶端。
原型可以起到继承的作用。原型里的方法都可以被不同的实例共享:
原型链的关键:在访问一个实例的时候,如果实例本身没找到此方法或属性,就往原型上找。如果还是找不到,继续往上一级的原型上找。
通过原型理解instantceOf
和 new
instanceof
的原理
instanceof
的作用:用于判断实例属于哪个构造函数。
instanceof
的原理:判断实例对象的__proto__
属性,和构造函数的prototype
属性,是否为同一个引用(是否指向同一个地址)。
注意1:虽然说,实例是由构造函数 new 出来的,但是实例的__proto__
属性引用的是构造函数的prototype
。也就是说,实例的__proto__
属性与构造函数本身无关。
注意2:在原型链上,原型的上面可能还会有原型,以此类推往上走,继续找__proto__
属性。这条链上如果能找到, instanceof 的返回结果也是 true。
比如说:
foo instance of Foo
的结果为true,因为foo.__proto__ === M.prototype
为true。foo instance of Objecet
的结果也为true,因为Foo.prototype.__proto__ === Object.prototype
为true。
但我们不能轻易的说:foo 一定是 由Object创建的实例
。这句话是错误的。我们来看下一个问题就明白了。
分析一个问题
问题:已知A继承了B,B继承了C。怎么判断 a 是由A直接生成的实例,还是B直接生成的实例呢?还是C直接生成的实例呢?
分析:这就要用到原型的constructor
属性了。
foo.__proto__.constructor === M
的结果为true,但是foo.__proto__.constructor === Object
的结果为false。
所以,用 consturctor判断就比用 instanceof判断,更为严谨。
new 运算符
当new Foo()时发生了什么:
(1)创建一个新的空对象实例。
(2)将此空对象的隐式原型指向其构造函数的显示原型。
(3)执行构造函数(传入相应的参数,如果没有参数就不用传),同时 this 指向这个新实例。
(4)如果返回值是一个新对象,那么直接返回该对象;如果无返回值或者返回一个非对象值,那么就将步骤(1)创建的对象返回。
function create() {
// 创建一个空的对象
let obj = new Object()
// 获得构造函数
let Con = [].shift.call(arguments)
// 链接到原型
obj.__proto__ = Con.prototype
// 绑定 this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result === 'object' ? result : obj
}
参考文章
https://baijiahao.baidu.com/sid=1615168823913070039&wfr=spider&for=pc
https://yuchengkai.cn/docs/frontend/#new