资讯专栏INFORMATION COLUMN

JS-对象

kidsamong / 2074人阅读

摘要:一概述是一种面向对象的语言。除了基本数据类型,其他的都是对象。表示创建一个没有原型的空对象。模拟操作符注意返回值访问对象属性访问方式也就是。对象在作为值时,是作为引用传递的。假如判断对象是否为数组目前的很多库,中都是这样实现的。

一、概述

JS是一种面向对象的语言。除了基本数据类型number, string, boolean(true, false), null, undefined,其他的都是对象。对象就是一个"name-value"对集合。

二、操作对象 2.1 创建对象

JS有三种创建对象的方式:字面量,Object.create,new构造方式。

2.1.1 Object.create(null | object)

严格来说调用Object.create方法是创建JS对象的唯一方式(其他两种方式内部实现都是基于该方法的)。该方法功能是创建一个对象,并且该对象的原型指向create的参数对象。
参数:必须是null或者对象,否则报错。null表示创建一个没有原型的空对象。

var p = { a: 1}; // 对象字面量
var c1 = Object.create(p); // 对象c1的原型指向p
var c2 = Object.create(null);// 对象c2没有原型

2.1.2 对象字面量

对象字面量是一种创建对象的便捷方式,见上例。其中对象p的创建方式就是对象字面量。JS解释器会对它进行处理的,等价于:

var p = Object.create(Object.prototype);
p.a = 1;

所以说对象字面量内部也是通过Object.create方式创建对象的,并且所有对象字面量方式创建的对象的原型都执行Object.prototype(如上图)。

思考:JS解释器如何区分语句块花括号{}和空对象花括号{}的?
先看看这两条语句执行的结果?

{} + [] // 0
[] + {} // "[object Object]"

{}作为右值(赋值表达式右侧),实参,在运算符的右侧,被括号()包裹则作为对象,其他则视为语句块:
下面输出都是:"[object Object]"

console.log({} + []) // 作为实参了

({}) + [] // 被括号包裹

var a = {} + [] //作为右值
console.log(a) 

我们知道当ES6箭头函数的函数体只有一条语句时可以省略语句块花括号,但是如果箭头函数返回的是一个对象该如何书写呢?

var func1 = () => {age: 12} // 本意是想返回对象{age:12},显然这样写就不对了,花括号会被作为语句块解析
var func2 = () => ({age: 12}) // 可以用括号包裹下
var func3 = () => { return {age: 12}} // 或显示的写全

2.1.3 new构造方式

JS的作者为了讨好类语言的开发者,引入了第三者创建对象方式,即new构造方式。这使得JS对象的创建有点像类语言的对象创建。

1) 格式
new关键字 + 空格 + 函数名字 + [(参数)]

其中参数是可选的,当没有参数传递时,可以省略括号。如:

function Func(){}
var c1 = new Func();
var c2 = new Func; // 如果没有参数传递,可以省略括号。
function Func(name){
  this.name = name;
}
Func.prototype.say = function(){
};
var c = new Func("q");

2) 内部原理

这种方式的内部也是通过Object.create方式构建的。new方式创建对象大致分为三步:
Step1:创建一个对象A,并且对象A的原型指向构造函数的prototype属性
Step2:以对象A绑定到构造函数上调用构造函数
Step3:如果构造函数返回值不是个非null的对象,则返回构造函数的返回值作为new表达式的值,否则以对象A作为new表达式的值。

function Func(name){
  this.name = name;
}
Func.prototype.say = function(){
};
function create(){ // 模拟new操作符
  var func = arguments[0];
  var args = Array.prototype.slice.call(arguments, 1);
  var other = Object.create(func.prototype); // Step 1
  var result = func.apply(other, args); // Step 2
  return typeof result === "object" && result ? result: other; // Step3 注意返回值
}
var c = create(Func, "q");
2.2 访问对象属性

访问方式也就是get/set/delete。在get访问中会涉及原型链,set/delete访问不会。

var Obj = {
  name: "john"
};
// Get操作
var n = Obj.name; // 等价var n = Obj["name"];
// Set操作
Obj.age = 12; 
2.2.1 Get操作流程:

2.2.2 Set操作流程:

2.2.3 delete操作

可以通过delete操作符删除对象的属性,只能删除对象本身的属性。

var p = {
  age: 26
}
var obj = Object.create(p);
obj.name = "john";
console.log(obj.name); // john
console.log(obj.age); // 26
delete obj.name; // 删除属性
delete obj.age; // 删除属性
console.log(obj.name); // undefined
console.log(obj.age); // undefined

2.3 引用对象

JS中对象是引用类型的。对象在作为值时,是作为引用传递的。

var a={}, b={}; // a,b分别指向不同的对象
var c = d = {}; // c,d指向同一个对象
三、反射

确定对象的类型有时很有必要。

3.1 typeof 操作符

通过typeof操作符可以获取值的类型:

console.log(typeof 1); // number
console.log(typeof ""); // string
console.log(typeof null); // object
console.log(typeof undefined); // undefined
console.log(typeof true); // boolean
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof function(){}); // function

但是发现这种方式中null, 数组也都是返回“object”。原因是JS中没有原生数组类型,数组是通过对象模拟的,所以数组也是对象。但是如何区分数组和对象呢???

3.2 Object.prototype.toString

typeof是有缺陷的,在实际应用中常通过Object.prototype.toString方法确定对象类型的。

console.log(Object.prototype.toString.call(1)); // [object Number]
console.log(Object.prototype.toString.call("")); // [object String]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call( {})); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(function(){})); // [object Function]

看例子中输出结果中发现不同之处了吧。假如判断对象是否为数组:

var isArray = function(val){
  return Object.prototype.toString.call(val) === "[object Array]";
}

目前的很多库zeptojs,underscorejs中都是这样实现的。

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

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

相关文章

  • JS中数据类型、内置对象、包装类型对象、typeof关系

    摘要:平时在复习基础知识时,经常会遇到数据类型基础数据类型内置对象包装类型对象,检测数据类型时,用到的值,感觉都差不多,但是又有差异。值与数据类型关系对比下图,即可知值相较于基础数据类型少多 平时在复习JS基础知识时,经常会遇到JS数据类型、基础数据类型、内置对象、包装类型对象,检测数据类型时,用到的typeof值,感觉都差不多,但是又有差异。今天特地整理下,方便理解。 JS数据类型 基础数...

    OldPanda 评论0 收藏0
  • 精读《JS 引擎基础之 Shapes and Inline Caches》

    摘要:概述的解释器优化器代码可能在字节码或者优化后的机器码状态下执行,而生成字节码速度很快,而生成机器码就要慢一些了。比如有一个函数,从获取值引擎生成的字节码结构是这样的指令是获取参数指向的对象,并存储在,第二步则返回。 1 引言 本期精读的文章是:JS 引擎基础之 Shapes and Inline Caches 一起了解下 JS 引擎是如何运作的吧! JS 的运作机制可以分为 AST 分...

    Tecode 评论0 收藏0
  • jQuery Deferred对象

    摘要:给普通的操作指定回调函数对象的最大优点,就是它把这一套回调函数接口,从操作扩展到了所有操作。方法用于指定对象状态为已失败时的回调函数。执行完毕执行成功执行失败接收一个或多个对象作为参数,为其指定回调函数。 什么是deferred对象 开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型...

    baoxl 评论0 收藏0
  • [译]执行上下文、作用域链和JS内部机制

    摘要:执行上下文作用域链和内部机制一执行上下文执行上下文是代码的执行环境,它包括的值变量对象和函数。创建作用域链一旦可变对象创建完,引擎就开始初始化作用域链。 执行上下文、作用域链和JS内部机制(Execution context, Scope chain and JavaScript internals) 一、执行上下文 执行上下文(Execution context EC)是js代码的执...

    caozhijian 评论0 收藏0

发表评论

0条评论

kidsamong

|高级讲师

TA的文章

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