资讯专栏INFORMATION COLUMN

深入理解 Javascript 之 对象

neroneroffy / 2021人阅读

摘要:返回如下仔细分析下面的图,将会加深你的理解和我们有一个类对象有一个属性,其指向构造器的原型是一个类构造器是之后产生的。

撸js基础之对象 图例

先谈谈 ECMAScript 中的数据类型

ES6 之前 ECMAScript 中有 5 种简单数据类型(也称为【基本数据类型】):UndefinedNullBooleanNumberString

还有一种复杂的【引用数据类型】Object

ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型。它也是基本数据类型。

特点

基本数据类型的值是按值访问的
基本类型的值是不可变的
基本类型的比较是它们的值的比较
基本类型的变量是存放在栈内存(Stack)里的

引用类型的值是按引用访问的
引用类型的值是可变的
引用类型的比较是引用的比较
引用类型的值是保存在堆内存(Heap)中的对象(Object) 与其他编程语言不同,JavaScript 不能直接操作对象的内存空间(堆内存)

图解:

检测变量类型

typeof

适合判断基本数据类型和function的判断
typeof "sss" ===> "string"
typeof 123 ===> "Number"
typeof [1,2,3] ===> "object"
typeof new Date() ===> "object"
typeof function(){alert("111");}  ===> "function"
typeof undefined ===> "undefined"
typeof NaN ===> "number"
typeof null ===> "object"

instanceof

判断已知的对象类型或者是自定义的对象

目标对象 + instanceof + 函数构造器[可以理解为是某个对象是否是某个构造器的实例]

原理: 判断左边的对象的原型链上是否有右侧的构造函数的prototype属性

[1,3] instanceof Array === true
new Array("1, 3,4") instanceof Array === true
new Object() instanceof Object === true
new String("string") instanceof String === true
function(){this.name="22";} instanceof Function === true

// 定义一个构造函数
function Person(){
    
}
// 定义一个构造函数
function Student(){

}
// 每一个构造函数都有一个prototype对象属性, 这个对象属性将会作为通过new Person()创建的对象的一个原型。
// 也就是当我们在new 一个对象的时候,这个对象的原型就指向了这个构造函数的prototype。

Student.prototype = new Person(); // student继承至person

var bson = new Student();
bson instanceof Student
// false

bson instanceof Person
// true

Object.prototype.toString.apply()

判断基本数据类型和内置对象
Object.prototype.toString.apply([]) === "[object Array]"
Object.prototype.toString.apply(function(){}) === "[object Function]"

Object.prototype.toString.apply(new Function); // "[object Function]"
Object.prototype.toString.apply(new Object);       // "[object Object]"
Object.prototype.toString.apply(new Date);         // "[object Date]"
Object.prototype.toString.apply(new Array);        // "[object Array]"
Object.prototype.toString.apply(new RegExp);       // "[object RegExp]"
Object.prototype.toString.apply(new ArrayBuffer);  // "[object ArrayBuffer]"
Object.prototype.toString.apply(Math);             // "[object Math]"
Object.prototype.toString.apply(JSON);             // "[object JSON]"
var promise = new Promise(function(resolve, reject) {
    resolve();
});
Object.prototype.toString.apply(promise);          // "[object Promise]"
Object.prototype.toString.apply(124)
// "[object Number]"
Object.prototype.toString.apply("222")
// "[object String]"
Object.prototype.toString.apply(true)
// "[object Boolean]"
Object.prototype.toString.apply(null)
// "[object Null]"
Object.prototype.toString.apply(null) === "[object Null]"   // 在IE6/7/8下存在有兼容性问题
创建对象

使用 Object 构造函数创建

// 对象实例的创建
var obj = new Object() 
obj.key = "value"   //使用构造函数创建一个空对象,并赋值

使用对象字面量表示法创建

//使用字面量创建一个对象
var obj = {
    key1: "value1",
    key2: "value2"
}  

ES6中还有更简洁的

var age = 20
var sex = "sexy"
 
var a = {
    name: "jack",
 
    // 简洁表示法,等同于 age: age
    age, 
 
    // 简洁表示法,等同于 sayName: function() {}
    sayName(){}, 
 
    // 属性名表达式,等同于 lover: "rose"
    ["lo" + "ver"]: "rose", 
 
    // 属性名表达式,等同于 sexy: "male"
    [sex]: "male"
}
工厂模式[创建多个相似的对象]
var createPerson (name, age){
    var o = {};
    o.name = name;
    o.age = age;
    o.sayName = function(){
        console.log(this);
    }
    return o;
}

var a = createPerson ("zjj", 20);
var b = createPerson ("zmf", 30);

工厂模式虽然解决多创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。

模仿“类”的设计

构造函数模式

function Person (name, age) {
    this.name = name;
    thia.age = age;
    this.sayName = function() { alert(this.age) }
}
Person.prototype.count = 2;
var a = new Person("a", 20)
var b = new Person("b", 22)
 
a instanceof Person // true

构造函数与其他函数唯一的区别就在于调用他们的方式不同。任何函数只要通过new 操作符来调用,那它就可以作为构造函数。

使用new操作符调用函数

function CO(){  
    this.p = “I’m in constructed object”;  
    this.alertP = function(){  
        alert(this.p);  
    }  
}  

var o2 = new CO();  


var obj = {}; // 第一步创建一个空对象
obj.__proto__ = CO.prototype; // 该对象的原型链指向构造函数的 prototype 所指向的对象。
CO.call(obj); // 第三步,将构造函数的作用域赋值给新的对象
return obj; // 返回新的对象

自定义一个new()

function Person(name, age) {
  this.name = name;
  this.age = age;
}

function New(f) {

  return function() {
    var o = {"__proto__": f.prototype}
    f.apply(o, arguments);
    return o;
  }
}

上面这种构造函数解决了对象类型识别的问题,但是每个方法都要在每个实例上重新创建一遍,在上面的例子中,a 和 b 都有个名为sayName()的方法,这两个方法虽然名字、内容、功能相同,但却分别在 a 和 b 中都重新创建了一次,这是没有必要的。

更好的方法应该是将公用的方法放到他们的原型上,也就是接下来要说的原型模式。

原型模式

所有函数都有一个不可枚举的 prototype(原型)属性,这个属性是一个指针,指向一个对象。

Person.prototype

返回如下:

仔细分析下面的图,将会加深你的理解

prototype 和 proto

我们有一个person类

function Person (name, age) {
    this.name = name;
    thia.age = age;
    this.sayName = function() { alert(this.age) }
}
Person.prototype.count = 2;
var p = new Person("zjj", 10);

对象p有一个__proto__属性,其指向构造器的原型

p.__proto__ == Person.prototype

foo 是一个类(构造器)
fooObj是new foo() 之后产生的。
fooObj的 __proto__ 指向构造器原型(foo.prototype)
foo 通过prototype 指向 构造器原型(foo.prototype)
构造器原型(foo.prototype)的构造器属性constructor 指向 foo

Person.__proto__ === Function.prototype

__proto__究竟指向谁

原型链

由于Person.prototype.__proto__ === Object.prototype,这就

相信看了上面两幅图,大家一定对原型链有了更深的理解和认识了吧!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96762.html

相关文章

  • 【进阶1-2期】JavaScript深入执行上下文栈和变量对象

    摘要:本计划一共期,每期重点攻克一个面试重难点,如果你还不了解本进阶计划,点击查看前端进阶的破冰之旅本期推荐文章深入之执行上下文栈和深入之变量对象,由于微信不能访问外链,点击阅读原文就可以啦。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第二天。 本计划一共28期,每期...

    Richard_Gao 评论0 收藏0
  • JavaScript深入参数按值传递

    摘要:深入系列第九篇,除了按值传递引用传递,还有第三种传递方式按共享传递定义在高级程序设计第三版,讲到传递参数中所有函数的参数都是按值传递的。 JavaScript深入系列第九篇,除了按值传递、引用传递,还有第三种传递方式 —— 按共享传递 定义 在《JavaScript高级程序设计》第三版 4.1.3,讲到传递参数: ECMAScript中所有函数的参数都是按值传递的。 什么是按值传递呢?...

    DataPipeline 评论0 收藏0
  • 深入理解JavaScript系列9:S.O.L.I.D五大原则接口隔离原则

    摘要:前言本章我们要讲解的是五大原则语言实现的第篇,接口隔离原则。接口隔离原则和单一职责有点类似,都是用于聚集功能职责的,实际上可以被理解才具有单一职责的程序转化到一个具有公共接口的对象。与我们下面讨论的一些小节是里关于违反接口隔离原则的影响。 前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第4篇,接口隔离原则ISP(The Interface Segreg...

    piglei 评论0 收藏0
  • 【进阶2-3期】JavaScript深入闭包面试题解

    摘要:闭包面试题解由于作用域链机制的影响,闭包只能取得内部函数的最后一个值,这引起的一个副作用就是如果内部函数在一个循环中,那么变量的值始终为最后一个值。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第二期,本周的主题是作用域闭包,今天是第8天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了...

    alanoddsoff 评论0 收藏0
  • 【进阶2-2期】JavaScript深入从作用域链理解闭包

    摘要:使用上一篇文章的例子来说明下自由变量进阶期深入浅出图解作用域链和闭包访问外部的今天是今天是其中既不是参数,也不是局部变量,所以是自由变量。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第二期,本周的主题是作用域闭包,今天是第7天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了解本进阶计...

    simpleapples 评论0 收藏0
  • 【进阶1-3期】JavaScript深入内存空间详细图解

    摘要:进阶期理解中的执行上下文和执行栈进阶期深入之执行上下文栈和变量对象但是今天补充一个知识点某些情况下,调用堆栈中函数调用的数量超出了调用堆栈的实际大小,浏览器会抛出一个错误终止运行。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第3天。 本计划一共28期,每期重点攻...

    coordinate35 评论0 收藏0

发表评论

0条评论

neroneroffy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<