JS的对象的深入理解(对象 对象 ES6类)

创建一个对象最简单的方法莫不就是使用字面量来创建,
简洁明了,
这篇文章感觉有些无敌: 很全的知识点

验证一个属性在实例中,还是原型对象中:

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 的时候直接会执行

  1. 工厂模式
    缺点: 无法识别对象,长得都一样;
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 出去


  1. 构造函数模式
    需要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;
} 

继承:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值