- 对象的由来以及衍生(
JavaScript 万物诞生记
) - new 到底做了多少事情
- 对象的基本概念
- 对象的构造函数
A. JavaScript 万物诞生记(印象笔记)
null 为 无中生有。
__proto__
是什么意思呢?那是“生”的意思,官方名称叫做“继承”-
Object (对象的大类)--- 能够制造对象的机器,
这个并不是真正的对象,你可以理解他是一个 Object 类(类似于能够生成对象的 function)
1. 此处的 NO.1 对象 是为 Object.prototype (真正的万物始祖,亦是始祖模板) 2. 这个机器又叫做构造函数, (用来构造对象的嘛) 3. new 命令是这个构造函数的开关
prototype 对象制造器需要根据模板来制造子对象,
而这个模板却是一个真正的对象
-
var obj = new Object({ flag: 10 });
1. 对象机器根据 No.1 模板 做成了 falg 对象。flag 是 No.1 对象的儿子,Object 机器只是负责了接生和描绘的作用 2. 注意 prototype 和 __proto__ 各自指向的方向不同
-
** 制造机器的机器 Function **
No.2 是所有机器的 父亲。
所有的机器对象的 __proto__ 都指向 No.2 对象,但是各个机器的模板各有各的不同和指向
Function.__proto__ === Function.prototype 简直太奇妙了有木有
从这张图上,我们会发现:所有的函数(包括Function)的proto都指向 No.2 对象,而同时Function.prototype也是No.2 对象。这说明了:
从逻辑上,我们可以认为所有机器(包括Function自己)都是由Function制造出来的。
同时,如果再仔细瞧瞧,你会发现:
Object作为一个机器可以看做是有由Function制造出来的,而Function作为一个对象可以看做是由Object制造出来的。
这就是JavaScript世界的“鸡生蛋,蛋生鸡”问题。那么到底是谁生了谁呢?Whatever!
-
世界最终的样子
所有对象的始祖是 No.1 对象,即所有的对象的 proto 是 No.1
所有的机器的始祖是 No.2 机器,即所有的 机器的 proto 是 No.1
No.2 机器对象和 Function 机器另有图谋
对象的始祖是对象,机器的始祖是机器。另外两个取不同
B. 对象和构造函数
1. es6 中的 class 只能用来声明作为构造函数使用,箭头函数只能作为普通函数使用
- 使用new 命令进行创建对象
-
构造函数既可以当做对象构造函数使用,也可作普通函数使用,
but 构造函数中当做普通函数使用时的 this 的指向是个值得注意的大问题
// 将构造函数当做普通函数使用 function Vehicle() { this.price = 1000; } var v = Vehicle(); console.log(v.price); // 报错 console.log(price); // 1000
这里的 v.price 访问报错,并且 price 泄露成为全局变量
-
解决问题的办法
-
在构造函数
内部
使用 严格模式use strict
function Fubar() { 'use strict'; this.price = 1000; this.number = 10; } console.log(Fubar()); // 报错
-
使用兼容性构造函数
function Fubar(foo, bar) { if(!(this instanceof Fubar)) return new Fubar(foo, bar); // 这里有一层递归, 递归有时也很好用 this._foo = foo; this._bar = bar; } console.log(Fubar(123, 456)._bar); // 456 var f = new Fubar(123, 456); console.log(f._foo); // 123
-
- new 命令的原理
-
使用new 命令构造对象的函数调用并不是正常的函数调用,依次按顺序执行下列的步骤
创建一个空对象,作为将要返回的对象的实例
将此空对象的原型 prototype 指向构造函数的 prototype 属性
使用 该对象 调用构造函数,绑定和指定构造函数内部的this
开始执行构造函数内部的代码有个问题:
普通函数和构造函数人为的指定 prototype 会产生什么样的结果??
构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子
构造函数默认是没有 return 语句的,带有 return 语句的构造函数会返回什么东西
??
-
将普通函数使用 new 命令得到什么结果
??
function fubar(foo) { return 'this is fun'; } var f = new fubar('123'); console.log(f); // fubar {} console.log(typeof f); // object
** new 总是会返回一个对象,实例对象(默认的 this 对象) 或者是 return 出来的对象构造函数人为的return 对象
,new 命令会对 return 的非对象(eg: 字符串),进行忽略 **
-
** new 命令的执行一览 **
// new 命令执行的 4 个步骤 function _new(constructorFun, params) { var obj = {}; obj = Object.create(constructorFun.prototype); // 创建一个空对象, 目前为止 这个对象本身还是 空的只不过他的 父链有东西 var result = constructorFun.apply(obj, params); if (typeof result == 'object' && result != null) return result else return obj; // 这个对象本身是空的,但是 他的父链是有东西的 } // params 必须是一个参数数组 function Person(name, age) { this.name = name; this.age = age; } var person = _new(Person, ['zhangsan', 23]); console.log(person.name);
对象是什么
- 对象的拷贝 ( 所有不可枚举和可枚举的对象 )
由对象的拷贝引出对象的各种属性和方法
确保拷贝后的对象,与原对象具有同样的prototype原型对象。
确保拷贝后的对象,与原对象具有同样的属性
function copyObjAllProperty (obj) {
var target = Object.create(Object.getPrototypeOf(obj)); // 第一步
Object.getOwnPropertyNames(obj).forEach(function(item) { // 第二步
Object.defineProperty(target, item, Object.getOwnPropertyDescriptor(obj, item));
});
return target;
}
var bar = new Date();
var foo = copyObjAllProperty(bar);
getAllPropertyNames(foo); // 下面的方法
-
对象的属性和方法
Object.defineProperty(target, attr, value); // 为 target 设置对象的值 Object.getOwnPropertyDescriptor(obj, item) // 返回属性的值 Object.key() // 返回本对象中所有的可枚举的属性 Object.getOwnPropertyNames(obj)
返回一个数组,包含本对象的所有属性(
包括不可枚举的
),没有继承下来的属性Class.hasOwnProperty(attr); eg: Date.hasOwnProperty('length'); // true Date.hasOwnProperty('toString'); // false
返回一个 boolean 值,判断某个属性在类中是否存在(不包括继承下来的
)
in 运算符 和 for in 操作
eg:
'length' in Date // true;
'toString' in Date // false
遍历本对象的可枚举属性
(包括继承下来的
)
// 获取对象的所有属性(继承的,可枚举的,不可枚举的)
function getAllPropertyNames(obj) {
var target = {};
while(obj) {
Object.getOwnPropertyNames(obj).forEach(function(item){
target[item] = true;
});
obj = Object.getPrototypeOf(obj);
}
return Object.getOwnPropertyNames(target);
}
var d = getAllPropertyNames(Date);
.