作者: 她不美却常驻我心 博客地址: https://blog.csdn.net/qq_39506551 微信公众号:老王的前端分享 每篇文章纯属个人经验观点,如有错误疏漏欢迎指正。转载请附带作者信息及出处。
对象这一概念是初学者比较难以理解的点,理论性的东西较多,而且需要理解的思想也不少,所以初学者可以先将对象理解成一种特殊的数据存储方式,再慢慢理解。
对象 Object 是 JS 的一种特殊的基本数据类型。有一句话非常的有名,叫做 万物皆对象 ,也就是说,JS 中的所有事物都是对象,包括字符串、数字等。
var str = "字符串"; // 实际上创建了一个新的字符串对象,继承了 String 对象的属性和方法。 console.log(str.__proto__); // 指向 String 对象对象 Object 可以看做是拥有属性和方法的数据。我们来举个生活中的例子来详细说明什么是对象:
我们将动物 Animal 看做是一个类,而狗 dog 是属于动物这个类中的一个对象,狗的名字、年龄、性别可以看做是它的属性,而它会跑、会吃东西这些动作行为,可以看做是它的方法。( 类 + 对象 的形式是面向对象编程的基础,初学者可以慢慢理解)
var dog = { name : "旺财", age : "3", sex : "公", run : function(){ console.log("跑"); }, eat : function(){ console.log("吃"); } };我们简单的介绍了一下什么叫做对象,并且通过代码将它的属性和方法描述了出来,对象可以看做是属性方法的集合,通过键值对的方式储存起来,每个键名为这个对象的属性名和方法名。 然而对象并不只是一种数据存储方式,在 JS 中,它是一个极为特殊的存在,因为它除了这些属性外,还从原型对象上继承了一些属性和方法,对象的属性通常都是继承的属性。这种从原型上继承的行为,也是 JS 的核心特征。
Object同时也是一种复合类型的数据,可以将很多的数据通过键值对的形式表示出来。接下来我们通过对象的方式来对数据进行存储:
var obj = { author_name : "她不美却常驻我心" , Wechar : "老王的前端分享", "author age" : 18, "标题" : "从零开始学前端" , "if" : "使用关键字命名" }键名通常是字符串类型的数据,符合 JS 的命名标准。任何的字符都可以通过增加引号来作为对象的键名,但我们并不推荐使用中文字符、保留关键字等不符合命名规范的特殊的方式进行命名,比如说例子中的"键名"、"if"。 符合命名规范的字符可以直接作为对象的键名,不需要添加额外的引号,而对象的值可以是任意数据类型。
一般我们采用第一种方式来访问对象的属性,当属性名为中文等特殊情况时,可以使用第二种方式来访问。
语法:Object.assign(target, source...) 作用:将对象的可枚举属复制到目标对象,并返回目标对象。 实例:
var obj1 = {}; var obj2 = { a: 1, b: 2 }; var obj3 = { a: 2, c: 3 }; var newObj = Object.assign(obj1, obj2,obj3); console.log(obj1); // {a: 2, b: 2, c: 3} console.log(obj2); // {a: 1, b: 2} console.log(obj3); // {a: 2, c: 3} console.log(newObj); // {a: 2, b: 2, c: 3} 如果目标对象中具有相同的属性名称,则后面的源对象的属性将类似地覆盖前面的源对象的属性;该方法实现的是浅拷贝,继承属性和不可枚举属性是不能复制的;语法:Object.create(proto, {property}) 作用:创建一个新对象,使用现有的对象来提供新创建的对象的原型。 实例:
var obj = Object.create(Object.prototype, { a: { writable: false, // 设置值是否可更改 configurable: true, // 设置属性是否可配置 enumerable: true, // 设置属性是否可枚举 value: 1 // 值 }, b:{ } }) obj.a = 2; console.log(obj); // { a : 1}语法:Object.defineProperty(obj, key, descriptor) 作用:在一个对象上定义新的属性或修改现有属性,并返回该对象。 实例:
var obj = { a : 1 }; Object.defineProperty(obj, 'b',{ configurable : true , enumerable : true , writable: true , get: function(){}, set: function(){}, value : 2 })语法:Object.defineProperties(obj, props) 作用:在一个对象上定义新的属性或修改现有属性,并返回该对象。 实例:
var obj = { a: 1 }; Object.defineProperties(obj, { a: { value: 2, writable: false }, b: { value: 3, writable: true } }); obj.a = 4 ; obj.b = 5 ; console.log(obj); // { a : 2 , b : 5 }语法:Object.getOwnPropertyDescriptor(obj, key) 作用:返回对象中属性对应的属性描述。 实例:
var obj = { a: 1 }; var desc = Object.getOwnPropertyDescriptor(obj, "a"); console.log(desc); // {value: 1, writable: true, enumerable: true, configurable: true}语法:Object.getOwnPropertyNames(obj) 作用:返回一个包含对象中所有属性的数组。 实例:
var obj = Object.create(Object, { a: { value: 1, enumerable: false }, b: { value: 2, enumerable: true } }) var keys = Object.getOwnPropertyNames(obj); console.log(keys); // ["a", "b"]语法:Object.keys(obj) 作用:返回一个包含对象中所有可枚举属性的数组。 实例:
var obj = Object.create(Object, { a: { value: 1, enumerable: false }, b: { value: 2, enumerable: true } }) var keys = Object.keys(obj); console.log(keys); // ["b"]语法:Object.hasOwnProperty(key) 作用:检测对象中是否含有指定属性。 实例:
var obj = { a : 1 } obj.hasOwnProperty("a"); // true obj.hasOwnProperty("b"); // false语法:Object.freeze(obj) 作用:不允许对对象进行任何修改。 实例:
var obj = { a : 1 } Object.freeze(obj);更多关于 Object 的方法及属性,请 点击这里查看。
对象的每一个属性都可以看成是由键值对构成的,我们可以使用 getter 和 setter 方法来代替属性值。通过这种方法定义的属性被称为 存取器属性。
var obj = { _hour_: 0, get hour() { return "现在是" + this._hour_ + "点"; }, set hour(h) { this._hour_ = h < 10 ? '0' + h : '' + h; } } obj.hour = 22; console.log(obj.hour); // 现在是22点 obj.hour = 9; console.log(obj.hour); // 现在是09点当我们访问对象的属性时,会调用 getter 方法,给属性赋值时,会调用 setter 方法。 使用 getter 和 setter 可以在对象的赋值和读取前做一些预处理的工作,比如上方代码在读取和设置时间时对其进行了一些预处理,保证在使用时不需要在进行额外的处理。
当一个属性只存在 getter 方法时,这个属性就是只读属性,不允许对它的值进行修改;如果只存在 setter方法,则被称为只写属性,读取属性时会返回 undefined ;
JS 本身并不具有 “类” 的概念,所有的一切都是对象。对象与对象之间的关系是如何联系起来的呢?就是靠着原型链串联在一起的。 每一个对象都具有一个 __proto__ 属性,它指向的就是这个对象所继承的原型。而原型也拥有一个 prototype 属性与之相对应,也就是说:当前对象的 __proto__ 属性与它继承的原型对象的 prototype 相同。
var str1 = "字符串"; console.log(str1); console.log(str1.__proto__); var str2 = new String("字符串"); console.log(str2); console.log(str2.__proto__); console.log(str1.__proto__ === String.prototype);可以发现,我们通过直接赋值的方式创建的是一个普通的字符串类型的数据,而通过构造函数创建的则是一个对象类型的字符串数据,但他们的原型都指向了 String 对象。也就是说,他们都是从 String 这个 “父类” 下的 “子类” ,继承了父类的方法。 接下来我们在打印一下 String 的原型和 Object 的原型:
console.log(str1.__proto__.__proto__); console.log(Object.prototype); console.log(str1.__proto__.__proto__ === Object.prototype);这样的结果已经很明显了,我们声明的普通字符串继承自 String 对象,而 Striing 对象又继承了 Object 对象。这里的指向继承关系,我们就可以将其看做是 JS 的原型链。
JS 的一切都是基于对象进行的设计,要说的内容也太多了点,洋洋洒洒写了半天感觉连个大概也没说明白,内置方法更是一带而过,原型和原型链也只是说了个大概,还有对象的继承等等根本就没有提。这里先立个 flag ,等写完函数的相关内容之后,再来重新写一下对象。(如果没实现的话,我就返回来把这段话删掉。笑)
种一棵树,最好的时间是十年前,其次是现在。人的一生,总的来说就是不断学习的一生。 蚕吐丝,蜂酿蜜。人不学,不如物。与其纠结学不学,学了有没有用,不如学了再说。
每篇文章纯属个人经验观点,如有错误疏漏欢迎指正。转载请附带作者信息及出处。您的评论和关注是我更新的动力! 请大家关注我的微信公众号,我会定期更新前端的相关技术文章,欢迎大家前来讨论学习。 都看到这里了,三连一下呗~~~。点个收藏,少个 Bug 。
