目录
Object.defineProperty(obj, propertyName, 包含修改内容的对象)
[[Configurable]]
可否通过delete删除属性并重新定义[[Enumerable]]
可否枚举/通过for-in返回属性[[Writable]]
可写[[Value]]
值getter
和 setter
函数Object.definePropertyies(obj, {修改的属性})
Object.getOwnPropertyDescriptor()
---返回一个对象
定义函数,接收参数作为属性值,新建一个对象,并返回赋值后的对象。
function createCat(name, age, color){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.color = color;
return obj;
}
var cat1 = createCat("mimi", 2, "yellow");
function Cat(name, age, color){
this.name = name;
this.age = age;
this.color = color;
this.getName = function(){ return this.name; };
}
var cat2 = new Car("lucky", 1, "white");
var cat3 = new Car("cathy", 1, "black");
!!!new
操作符的步骤:
this
指向新对象(构造函数的作用域赋给这个对象)问题:
每个实例都会新建 Function
实例,实例的机制相同,但是作用域和标识符解析不同,是不必要的开销。
解决:将方法定义在外部。
function Cat(name, age, color){
this.name = name;
this.age = age;
this.color = color;
this.getName = getName;
}
function getName()
{
return this.name;
}
function Person(){};
Person.prototype.name = "jack";
通过 Person.prototype
可以给原型添加属性和方法,也可以通过定义对象字面量一次添加多个,但是会破坏 constructor
指向,可以再修改回来。而且通过定义对象字面量重写原型对象会导致原型链断开:
function Person(){};
var person = new Person();//先实例化
Person.prototype = {//再重写原型对象
constructor: Person,
name:john,
age: 20,
getName: function(){}
};
//person.getName()会报错,因为person指向的是旧的原型对象,其中没有这个方法
在构造函数中定义非引用数值属性,在原型中定义共享属性 constructor
和方法。
function Person(name, age, eyeColor){
this.name = name;
this.age = age;
this.eyeColor = eyeColor;
};
Person.prototype = {
constructor: Person,
getName: function(){}
};
function Person(name, age, eyeColor){
this.name = name;
this.age = age;
this.eyeColor = eyeColor;
if(typeof this.getName != "function"){//只有getName不存在的时候才会调用,就是初次调用构造函数的时候
Person.prototype.getName = function(){};
}
};
function createCat(name, age, color){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.color = color;
return obj;
}
var cat1 = new createCat("mimi", 2, "yellow");
对象和构造函数无关系
prototype
属性,【prototype】指向函数的【原型对象】prototype
原型对象中有【constructor属性】指回向【构造函数】。注: ES6 的箭头函数没有 prototype
属性,但是有 __proto__
属性。
prototype
是【基于构造函数构造的实例对象】的隐式原型([[prototype]]
,部分浏览器可以通过 __proto__
属性访问),即 [[prototype]]
指向【其构造函数的原型对象】。
prototype
】。所有的引用类型都有 __proto__
属性
原型链是继承的一种实现方法:利用原型使【引用类型A】继承【引用类型B】的属性和方法
引用类型值属性会被所有实例共享
__proto__
】指向【B prototype
原型对象】,【B prototype
的 constructor
属性】指向【构造函数B】,【B prototype
的 __proto__
】指向【A prototype
原型对象】。实际上是 __proto__
连接【实例】和【原型对象】形成原型链。
C.__proto__ === B.prototype //true
C.__proto__.__proto__ === A.prototype //true
//没有修改 constructor
function Animal(){
this.name = 'animal';
}
function Cat(){
this.name = 'Cat';
}
function ChinaCat(){
this.name='chinacat';
}
Cat.prototype = new Animal(); //继承Animal
ChinaCat.prototype = new Cat(); //继承Cat
//插入 constructor 修改语句
var a = new ChinaCat();
结果如图:
此时
constructor
都会指向【function Animal(){}
】a.__proto__
指向 ChinaCat 原型对象,ChinaCat 原型对象的__proto__
指向 Cat 原型对象,Cat 原型对象的__proto__
指向 Animal 原型对象,Animal 原型对象中的 constructor
指向【function Animal(){}
】.prototype
为空,因为 prototype
是函数有的属性//插入constructor修改语句
Cat.prototype.constructor = Cat;
ChinaCat.prototype.constructor = ChinaCat;
var a = new ChinaCat();
此时
a.constructor
】指向其【构造函数 function ChinaCat(){}
】,【a.__proto__
】等于其原型对象中的__proto__
所指向的【Cat原型对象】,ChinaCat
原型对象】缺点:父类型中定义的方法不可继承,对子类型不可见,只能通过构造函数,无法进行函数复用。
function Parent(){
this.color = ['red','blue','yellow'];
}
function Child(){
parent.call(this); //parent.apply(this,arguments);
}
var ins = new Child();
ins.color.push('white');//ins.color = ['red','blue','yellow','white'];
缺点:无法向父类构造函数中传递参数;子类原型链上定义的方法有先后顺序问题;引用类型值的原型属性会被共享。
需要注意的一点是要修改constructor的指向。
function Animal(species) {
this.species = species;
}
Animal.prototype.func = function() {
console.log("Animal");
};
function Cat() {}
/*func方法是无效的, 因为后面原型链被重新指向了Animal实例*/
Cat.prototype.func = function() {
console.log("Cat");
};
Cat.prototype = new Animal();//原型继承
//Cat.prototype.constructor属性会指向Animal,而不是Cat,需要手动修改
Cat.prototype.constructor = Cat; // 修复: 将Cat.prototype.constructor重新指向Cat
var cat = new Cat();
cat.func(); // output: Animal
console.log(cat.species); // undefined,不能传递参数
缺点:调用了两次父类构造函数
function Animal(type){//构造函数,定义属性
this.type = type;
this.deployment = [];
}
Animal.prototype.getType= function(){//原型对象定义方法
return this.type;
};
//继承属性
function Cat(name, age){//构造函数,继承并定义自己的属性
Animal.call(this, "cat");
this.name = name;
this.age = age;
}
//继承方法
Cat.prototype = new Animal(); //第一次调用 获得Animal的实例属性type\deployment
Cat.prototype.constructor = Cat; //修改constructor指向
//实例化对象
var cat1 = new Cat("lucky",2);//第二次在Cat构造函数中调用 会重新获得实例属性,从而屏蔽原型中的同名属性
cat1.deployment.push("china");
var cat2 = new Cat("lucy",1);//第二次在Cat构造函数中调用 会重新获得实例属性,从而屏蔽原型中的同名属性
cat2.deployment.push("canada");
//
console.log(cat1);
console.log(cat2);
实际上,就有了两组相同的属性:一组在cat1/cat2实例中,一组在Cat原型对象中。
解决组合继承的问题,是理想的继承方法
function inherentPro(subType, superType){
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
inherentPro(Cat, Animal);//替换Cat.prototype = new Animal();
原文:https://www.cnblogs.com/qiuqiubai/p/12539291.html