创建一个对象最简单的方法莫不就是使用字面量来创建,
简洁明了,
这篇文章感觉有些无敌: 很全的知识点
验证一个属性在实例中,还是原型对象中:
in与hasOwnproperty(),的方法区别与使用
因此只要 in 操作符返回 true 而 hasOwnProperty()返回 false,
就可以确定属性是原型中的属性。
var person = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function(){
alert(this.name);
}
};
ES中有两种属性: 数据属性与访问器的属性
对象的数据属性: 包含一个数据值的位置,可以读取与写入;
有四个描述其行为的特性:
[[Configurable]], [[Enumberable]], [[Writeable]],[[Value]]
Confugurable: 是描述能否通过 delect 从而修改对象的属性;
Enumberable: 描述能否通过for in 来遍历对象的属性
Writeable: 描述能否修改对象的属性;
Value : (包含这个属性的数据值) 描述写入属性值得时候,能否将新值保留在这个位置; 除了这个以外其他的值默认为true;
而要修改对象的默认属性需要使用 Object.defineProperty()
这个方法可以传入3个参数; 一个为对象, 二为 对象的属性, 三为 描述属性描述符;
2.访问器的属性;
访问器属性不包含数据值, 有getter ()与setter() 这两个方法;
读取使用 getter() , 处理数据使用 setter( ) ; 分别对应 读取与写入
get与set的理解:添加链接描述
访问器属性的4个特性:
[[Configurable]], [[Enumberable]], [[get]], [[set]]
get 与 set 默认是undefined; 其他均与 上面一样
对于定义对象的多个属性 则是使用 Object.defineProperties()
这个只能接收两个 参数 第一个是修改的对象, 第二个是 对应对象属性的修改
创建一个对象 ( 一个类, 模板)
** ES6的新写法 **
- es6中类的静态方法可以被子类继承,但是没法被实例继承
class SparseArr {
//构造函数为默认方法
constructor(n,m) {
//代表为属性,为new的新props
this.n=n;
this.m=m;
let arrTwo = [];
for (let i = 0; i < n; i++) {
arrTwo[i] = [] //这一步很重要
for (let j = 0; j < m; j++) {
arrTwo[i][j] = 0
}
}
console.log(arrTwo);
// return arrTwo
}
//二维数组的创建,类的方法
arr22(n, m) {
let arrTwo = [];
for (let i = 0; i < n; i++) {
arrTwo[i] = [] //这一步很重要
for (let j = 0; j < m; j++) {
arrTwo[i][j] = 0
}
}
console.log(arrTwo);
return arrTwo
}
}
let newArr=new SparseArr(2,2)
newArr.arr22(3,3)
其中的construstor就像是默认的构造函数,使用new 的时候直接会执行
- 工厂模式
缺点: 无法识别对象,长得都一样;
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o; //将这一句去掉会怎么样呢
}
这里还有一个需要注意的点就是最后需要return 出去
- 构造函数模式
需要new
来创建一个对象实例;
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
如果将其方法抽离出来, 则是相当于将函数名的指针赋值给构造函数,这个函数则是一个全局的方法
常问问题: new实现的过程,(练习普通对象怎么创建的,直接将其说出来就好了)
在全局作用域中定义的函数实际上只
能被某个对象调用,这让全局作用域有点名不副实。而更让人无法接受的是:如果对象需要定义很多方法,
那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了。
好在,这些问题可以通过使用原型模式来解决
缺点:每个创建都需要重新创建一个实例,都会跟着创建一个方法
- 使用构造函数当做函数;
可分为三个 方式,
一个使用new , 第二个直接使用这个函数, 第三个 使用 call() call与apply 用法
3. 原型模式
我们创建的函数都有一个 prototype 的属性, 这是一个指针,
prototype 就是通过调用构造函数而创建的那个对象实例的原型对象;
将这些信息直接添加到对象原型上去;
当然所有的原型对象都会获得一个constructor 属性
而在实例中 又会 生成一个新的指针[[Prototype]] : _proto_
keyi 使用 isPrototypeOf() 的方法来判断实例与对象原型的关系;
function Person(){
} // prototype指向 Object()
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
单独使用 in 可以判断属性 // alert( "name" in person1) // true;
hasOwnProperty() 判断
当使用 字面量的模式的时候;
两者的区别;
function Person(){
}
var friend = new Person();
Person.prototype = {
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
friend.sayName(); //error
\这两个例子要仔细体会
//顺序不同会产生完全不一样的结果
function Person(){
}
Person.prototype = {
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
var friend = new Person();
friend.sayName(); //error
在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。
最终结果相同,但有一个例外:constructor 属性不再指向 Person 了。前面曾经介绍过,每创建一 个函数,就会同时创建它的
prototype 对象,这个对象也会自动获得 constructor 属性。而我们在 这里使用的语法,本质上完全重写了默认的
prototype 对象,因此 constructor 属性也就变成了新 对象的 constructor 属性(指向 Object
构造函数),不再指向 Person 函数。此时,尽管 instanceof 操作符还能返回正确的结果,但通过 constructor
已经无法确定对象的类型了,如下所示。
(在Person.propotype添加属性constructor改变指向)
注意,以这种方式重设 constructor 属性会导致它的[[Enumerable]]特性被设置为 true
缺点也是十分明显: 所有的实例,都会共享所有的属性
这里使用这个方式的,与以往不同的是,此时的consrtuctor
,
会发生改变与以往的有些不同, 如果需要不发生改变的话,
可以constructor
先进行指向如下面所示
4. 构造函数与原型模式(最佳的一种方式)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
5. 动态原型模式
将所有的信息都封装在了构造函数之中,
可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型
/**
*
* @param {*} name
* @param {*} age
* @param {*} job
*/
function Person(name, age, job){
//属性
this.name = name;
this.age = age;
this.job = job;
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this.name);
};
}
}
6. 寄生构造函数模式
跟工厂模式其实是一样的
7. 稳妥构造函数模式
这是一种在创建对象实例的方法中,
不使用this,不使用 new 方式的一种创建函数的方法;
function Person(name, age, job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}
继承: