原型
JavaScript三大基础——原型链,闭包,作用域
今天!原型它来了!
原型(object.prototype)是函数function的一个属性,它定义了该构造函数new出来对象的公共属性,new出来的对象可以继承该原型的属性和方法。(原型是该构造函数new出来对象的爹或者说祖先)
构造函数和普通函数的区别只有书写的区别(大驼峰式书写方法:所有单词首字母大写),普通函数用小驼峰书写方法(第一个单词首字母小写,剩下单词首字母大写)。
构造函数new出来的对象实例是相互独立且相同的(同一个模子刻出来的,构造函数就是模子,new出来的对象实例就是工艺品,长得都一样,但是相互独立,是不同的个体)
注意!!宇神曾教导我:
(1)函数function是对象,但是对象不是函数!而原型本身也是个对象 。
(2)当实例对象new出来以后,constructor就只是指向构造函数的指针指向存储构造函数的空间,[[proto]]就是指向原型prototype的指针指向存储原型的空间。
(3)[[proto]]是在es规范里的写法,而__ proto__是个别浏览器的实现,但指代的都是指向原型的指针
ps:根据数据来源得知现在基本所有浏览器都可以接受__ proto__这个写法
但是这是一种可能要被废弃的写法,还是早点改吧hhhhhh
使用原型提取构造函数公有属性可以减少new对象时代码的冗余:
//不使用原型时
function Car(color, ownerName){
/*下面三行就是每new一次对象都要执行一次的用于代码*/
this.carName = "Honda";
this.height = "1400";
this.length = "4900";
this.color = color;
this.ownerName = ownerName;
}
var a = new Car(red, ZJX);
var b = new Car(black ,Eason);
//使用原型后
Car.prototype = {
carName = "Honda",
height = "1400",
length = "4900",
}
function Car(color, ownerName){
this.color = color;
this.ownerName = ownerName;
}
var a = new Car(red, ZJX);
var b = new Car(black ,Eason);
检测方法
isPrototypeOf(原型于…)
作用:检测一个对象是否是另一个对象的原型。或者说一个对象是否被包含在另一个对象的原型链中
例子:
(用new创建对象)
function Grand(){
//一些属性或方法
}
var grand = new Grand;
Father.prototype = grand;
function Father(){
//一些属性或方法
}
var father = new Father;
Son.prototype = father;
function Son(){
//一些属性或方法
}
var son = new Son;
Son.prototype.isPrototypeof(son) ---->true
Father.prototype.isPrototypeof(son) ---->true
Grand.prototype.isPrototypeof(son) ---->true
Object.prototype.isPrototypeOf(son) ---->true
(用create创建对象)
var p = {x:1};//定义一个原型对象
var o = Object.create(p);//使用这个原型创建一个对象
//这就没有构造函数的概念了,直接用p去create o,o继承于p
p.isPrototypeOf(o);//=>true: o继承于p
Object.prototype.isPrototypeOf(p);//=> true p继承自Object.prototype
综合上面的两个例子,我们发现在调用isPrototypeOf()
的时候有三种方式
p.isPrototypeOf(o);//=>true
Object.prototype.isPrototypeOf(p);
Animal.prototype.isPrototypeOf(eh)//=>true
总结一下就是:
通过Object.create()
创建的对象使用第一个参数作为原型
通过对象直接量的对象使用Object.prototype
作为原型
通过new
创建的对象使用构造函数的prototype
属性作为原型
instanceof(实例于…)
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
instanceof运算符希望左操作数是一个对象实例,右操作数是一个构造函数。如果左侧对象是右侧的实例,则表达式返回为true,否则返回false。
// 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo();//JavaScript 原型继承
var foo = new Foo();
console.log(foo instanceof Foo)//true
console.log(foo instanceof Aoo)//true
上面的代码中是判断了一层继承关系中的父类,在多层继承关系中,instanceof 运算符同样适用。
instanceOf与isPrototypeOf简单总结
- 如果实例A instanceof 构造函数B为
True
,那么B.prototype.isPrototypeof(A)一定为True
(针对于用构造函数new出来产生的原型链) - 由于isPrototypeof是prototype上的属性,所以new Object()和Object.create()出来对象的结果在isPrototypeof会有不同。
hasOwnProperty
hasOwnProperty()
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
const object1 = {};
object1.property1 = 42;
console.log(object1.hasOwnProperty('property1')); // expected output: true
console.log(object1.hasOwnProperty('toString')); // expected output: false
原型链
注意:Object.prototype是所有对象原型链的终端!!
function Grand(){
//一些属性或方法
}
var grand = new Grand;
Father.prototype = grand;
function Father(){
//一些属性或方法
}
var father = new Father;
Son.prototype = father;
function Son(){
//一些属性或方法
}
var son = new Son;
原型链的增删改只能自身权限增删改,下级(子辈)没有权限增删改,下级的增删改只能增删改自身的(晚辈没权利玩弄祖先的玩意儿,只能看看)
原生JS实现new的过程
/**
*
* @param fn 构造函数
* @param arg 传入的形参
*/
function _mynew(fn, ...args) {
const t = typeof(fn)
//判断fn是否为一个函数(先判断为函数再判断是否能被new的函数)
if(t !== "function"){
throw new TypeError('${t} must be a function')
}
//1. 新建一个对象
let _this = Object.create(fn.prototype); //由fn.prototype作为原型去新建一个对象
//2. 将实例的__proto__指向构造函数的prototype
Object.setPrototypeOf(_this, fn.prototype);
//3. 设置实例的constructor
_this.constructor = fn;
//4. 通过apply构造函数来传参
const result = fn.apply (_this,args);
//5.返回值判断(return值如果为引用值,则改变为其本身)
if(result&&(typeof result === "object"||typeof result === "function")){
return result
}
return _this;
}