构造函数的相关概念和理解

构造函数的相关概念和理解

构造函数

构造函数其实也是普通函数的一种,只不过主要功能与普通函数略有差别,普通函数是用来执行一段代码的,而构造函数是用来实例化具有想同属性和方法的对象。

实例

以下所有的代码都是基于该实例的

function Person(uname, age) {
    this.uname = uname;
    this.age = age;
    this.sayHi = function(arg) {
        console.log('我说' + arg);
    }
};
var p1 = new Person('张三', 18);
// 实例化成员
console.log(p1.age);//18
p1.sayHi('你好');//我说你好
// 静态成员
Person.gender = '女';
//这个不仅是静态成员,还是我们对构造函数的拓展
Person.studying = function() {
    console.log('我爱学习');
};

console.log(Person.gender);//女
Person.studying();//我爱学习

原型对象

每一个构造函数都有一个prototype属性,属性值是一个对象,叫原型对象

每一个实例化对象都有一个__ proto__,用来指向构造函数的prototype属性原型对象

原型链

因为构造函数都有prototype属性,并且相关的实例化的对象

实例化成员

实例化成员就是在实例化对象的时候赋给实例的数据属性和访问器属性,比较典型的Array

var arr = new Array(1,2,3,4);
//那么arr.slice(),arr.length,arr.split(),arr.join(),均为实例化成员

静态成员

构造函数本身的数据属性和访问器属性就是静态成员

var arr = new Array(4,5,6,7,8);
Arr.isArray(arr);//true

类似Array.isArray()的方法还有Arr.form() Array.of();

构造函数的拓展

原型的拓展

在函数拓展的而过程中,我们会遇到很多问题,在原型上的拓展可以在实例对象中应用

常见的两种封装方式为

//1.可以直接从原型上进行拓展
Person.prototype.sayName = function(){
    console.log(this.name);
}
/**
* 也是在原型上进行配置,不过该方法三个参数都需要
* 第一个参数:目标对象
* 第二个参数:需要定义的属性或方法的名字
* 第三个参数:目标属性所拥有的特性
* 第三个参数是个对象:
* value:属性或者方法的值(名字);
* writable:如果为false,属性的值就不能被重写,只能为只读了;
* configurable:总开关,一旦为false,就不能再设置他的(value,writable,configurable);
* enumerable:是否能可以枚举(遍历)出来。
*/
//2.建议使用该方式进行拓展
Object.defineProperty(Person.prototype, 'sayName', {
	value: function() {
		return this.mName;
	},
	writable: false,
	configurable: false,
	enumerable: false
});
//3.Object.defineProperties(obj, props)和第二个一致,只不过可以拓展多个方法或者属性
function obj(){
	console.log('123');
}
Object.defineProperties(obj, {
  'sayName': {
    value: function() {
		return this.mName;
	},
    writable: true
  }
});
console.dir(obj);

构造函数静态成员的封装

我们不建议对原生的对象进行拓展属性和方法,尤其是覆盖掉原生方法和属性的拓展。下边的代码是对Array的静态成员的拓展,实例化出来的对象并无该方法!

不建议下边的拓展方式!!!

Array.sum = function(arr) {
	// arr是个数组
	var sum = 0;
	for (var i = 0; i < arr.length; i++) {
		console.log(arr[i]);
		sum += arr[i];
	}
	return sum;
}
let arr = [1, 2, 3, 4, 5, 6]
console.log(Array.sum(arr));

原型链

因为我们知道函数中,如果内部函数没有某个变量,他会层层往上找。

var num = 1;
function fun1(){
	var num = 0;
	function fun11(){
		console.log(num);
	};
	fun11();
};
fun1();//0

同样原型中也是的,如果该实例化对象下没有的方法,会向他的原型进行查找,如果没有接着想上找,这个查找的过程就变成了下方的例子

p1.__proto__.__proto__.__proto__
function Person(name) {
    this.mName = name;
}

var p1 = new Person('wangyuan');

console.log(p1);
console.log(p1.__proto__); //Person
console.log(p1.__proto__.__proto__); //object
console.log(p1.__proto__.__proto__.__proto__); //null

原型链中最底部的原型指向null

原型中的this指向

这涉及到了this只想问题,圆形中的this统统指向构造函数的实例化对象

this指向问题详见https://blog.csdn.net/weixin_45888429/article/details/106388974

涉及到原型的方法

hasOwnProperty()

该方法是用来查找该构造函数下是否有该属性或者方法,如果没在当前函数的成员里,如果在则返回true否则返回false

var Person = {
    uname: 'zhangsan',
    sayHi: function() {
		console.log('我是大咖');
    }
};
console.log(Person.hasOwnProperty('uname'));//true
console.log(Person.hasOwnProperty('toString'));//false

类似hasOwnProperty()方法的有in方法,但是in方法会查找原型链中的属性或者方法

console.log('toString' in Person);//true

对象的继承

构造函数的继承就是对该构造函数的原型继承

Object.create();里有两个参数,第一个参数为要继承的父类。第二个可选,如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。

var person1 = {
    uname: 'zhangsan'
};
// Object.create():方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
var person2 = Object.create(person1, {
    mName: {
		value: 'lisi',
		configurable: true,
		writable: true,
		enumerable: true
    }
});

console.log(person1);//
console.log(person2);

在这里插入图片描述
下边是用构造方法来继承

function Father(name, age) {
    this.uname = name;
    this.age = age;
}
// 定义子类
function Son(name, age, height) {
    // 通过this指向子构造函数了
    Father.call(this, name, age);
    this.height = height;
}
var son = new Son('小豆', 5, 120);
console.log(son);

关于对象的遍历

上文也说过在属性里边配置不可枚举属性,会导致不可遍历,其中for…in、Object.keys()是不可遍历的

for (var key in obj) {
    console.log(key);
}

Object.getOwnPropertyNames(obj)方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。参数是要遍历的对象。

var obj = {
	uname: 'zhangsan',
	sayHi: function() {
		console.log('nihao');
	}
};
Object.defineProperty(obj, 'age', {
	value: '18',
	configurable: true,
	enumerable: false,
	writable: true
});
Object.getOwnPropertyNames(obj);//["uname", "sayHi", "age"]

Object.keys() 返回一个所有元素为字符串的数组,其元素来自于从给定的object上面可直接枚举的属性。这些属性的顺序与手动遍历该对象属性时的一致。参数也是obj。效果类似普通的数组遍历。

var obj = {
	uname: 'zhangsan',
	sayHi: function() {
		console.log('nihao');
	}
};
Object.defineProperty(obj, 'age', {
	value: '18',
	configurable: true,
	enumerable: false,
	writable: true
});
console.log(Object.keys(obj));//["uname", "sayHi"]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值