【志远JS逆向学习笔记】JS中的对象

162 阅读3分钟

当我们在JS中打出这样的一段代码时

let Person = {}
console.log(Person)

我们就成功创建了一个名字叫做Person的对象,对象中包含两块内容(属性, 方法),一个只有属性没有方法的对象我们一般称为数据结构。例如下面这样:

let Person = {
    "name":"张三",
    "age":18
}
console.log(Person.name)

注意,此时我们Person对象里面是没有方法的,有的只是一个名叫name和一个名叫age的属性,此时这个对象我们也可以称为数据结构(只是用来保存数据,而不进行任何操作的对象)。当然我们也可以为对象添加方法,具体操作如下:

let Person = {
    "name":"张三",
    "age":18,
    Printf:function(){
        console.log("我的名字是:"+ this.name)
    }
}
console.log(Person.name)
Person.Printf()

此时我们为这个对象添加了一个名为Printf的方法。 此时的Person是一个实例对象

实例对象

实例对象有两种创建方式,一种是上面那样,通过直接在{}给定属性方法来直接进行创建,还有一种是通过new关键字来进行创建。

let Person = {
    "name":"张三",
    "age":18,
    Printf:function(){
        console.log("我的名字是:"+ this.name)
    }
}
console.log(Person.name)
Person.Printf()
let XMLHTTP = new XMLHttpRequest()
console.log(XMLHTTP)

原型对象

首先要明确一定,在JS中,函数也属于对象,原型对象是通过构造函数来实现的,例如,下面我们创建一个名为Person的原型对象:

function Person(name, age){
    this.name = name,
    this.age = age
}
let P = new Person("李四", 18)

此时我们便创建一个名为Person的原型对象,可以通过new来创建不同的实例对象,例如P就是通过Person创建的一个实例对象。

关于this指向问题

用最简单的话说,当一个函数被调用时,谁调用的这个方法,this就指向谁,例如下面这样的内容:

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.Printf = function() {
        console.log(this);  // `this` 将指向调用 `Printf` 的对象
    };
}

const P = new Person("张三", 18);
const L = new Person("李四", 19);

L.Printf();  // 输出 L 对象 {name: "李四", age: 19, Printf: f}
P.Printf();  // 输出 P 对象 {name: "张三", age: 18, Printf: f}

this在Person原型中被使用,但是这里this指的并不是原型,而是实例。当我们后面在某个函数中看到this时,要检查这个函数是被那个实例调用的,this指向的就是它。

原型链(__proto__)

当我们创建一个对象(实例对象和原型对象都有这个方法),可以通过__proto__去向上查看它的父亲。例如下面这段代码:

function Person(name, age){
    this.name = name
    this.age = age
}
P = new Person("张三", 18)
console.log(P.__proto__)

此时我们可以获取到实例对象P的父亲(其实也就是Person这个原型对象),当然我们也可以通过Person.__proto__获取原型对象的父亲,也就是Object对象。

function Person(name, age){
    this.name = name
    this.age = age
}
P = new Person("张三", 18)
console.log(Person.prototype.__proto__)

我们可以对一个实例对象,逐级使用__proto__来寻找最早的父级对象(也就是最早的原型对象)。 同时,当我们调用一个实例属性或者方法时,如果实例中不存在这个属性或方法,也是通过__proto__逐级向上查找的

prototype

prototype是一个函数才具备的属性,也即是实例对象是没有这个属性的,它用于定义该函数创建的所有实例共享的属性和方法,一般情况下,除了构造方法外,不会再其他方法上使用该属性。通过这个属性,我们可以给原型对象添加更多的属性和方法。

function Person(){
    
}
function printf(){
    console.log(this)
}
Person.prototype.name = "张三"
Person.prototype.printf = printf
P = new Person()
L = new Person()
L.name = "李四"
P.printf()
L.printf()
console.log(P.__proto__ === Person.prototype)