firstnote / blog Goto Github PK
View Code? Open in Web Editor NEW个人博客,内容在issue
个人博客,内容在issue
引自JavaScript高程设计4中对闭包的定义:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
对象是一组属性的无序集合,内容就是键值对,值可以是数据或者函数。
ECMA-262 使用一些内部特性描述属性的特征,这些特性由为 JavaScript 实现引擎的规范定义,因此开发者不能在 JavaScript 中直接访问这些属性。规范用两个中括号标记特性,如
[[Enumerable]]
属性分两种:数据属性和访问器属性
数据属性包含一个保存数据值的位置。读写都在这个位置,数据属性有 4 个特性描述它们的行为:
可通过 Object.defineProperty()修改默认特性,如下
let person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "mike",
});
configurable 设置为 false 后无法再通过 Object.defineProperty 定义特性。
同样是通过 Object.defineProperty 定义,获取函数和设置函数不一定都有定义。只定义 get 意味着属性是只读的,尝试修改会被忽略
在调用 Object.defineProperty()时,未指定的特性默认为 false/undefined,访问器属性和数据属性不可同时定义
字面量新建的对象属性默认是数据属性
Object.defineProperties
使用 Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。这个方法接受两个参数:属性所在的对象和要取得其描述符的属性名。返回值是一个对象,包含 configurable、enumberable、get 和 set 属性,对于数据属性包含 configurable、enumerable、writable 和 value 属性。
ECMAScript 2017 新增了 Object.getOwnPropertyDescriptions()静态方法。这个方法实际上会在每个自有属性上调用 Object.getOwnPropertyDescriptor()并在一个新对象中返回它们,如下
let person = {
name: 11,
age: 22,
};
Object.getOwnPropertyDescriptors(person);
{
"name": {
"value": 11,
"writable": true,
"enumerable": true,
"configurable": true
},
"age": {
"value": 22,
"writable": true,
"enumerable": true,
"configurable": true
}
}
let book = {}
Object.defineProperties(book,{
year_:{
value:2017
},
edition:{
value:1
},
year:{
get:function(){
return this.year_
},
set:function(newValue){
if(newValue>2017){
this.year_=newValue
this.edition += newValue - 2017
}
}
}
})
Object.getOwnPropertyDescriptors(book);
{
"year_": {
"value": 2017,
"writable": false,
"enumerable": false,
"configurable": false
},
"edition": {
"value": 1,
"writable": false,
"enumerable": false,
"configurable": false
},
"year": {
"enumerable": false,
"configurable": false,
get: ƒ (),
set: ƒ (newValue)
}
}
JavaScript 开发者经常觉得‘合并’(merge)两个对象很有用。更具体地说,就是把源对象所有的本地属性一起复制到目标对象上。有时候这种操作也被称为‘混入’(mixin),因为目标对象通过混入源对象的属性得到了增强。
ECMAScript6 专门为合并对象提供了 Object.assign()方法。这个方法接受一个目标对象和一个或多个源对象作为参数,然后将每个源对象中可枚举(Object.propertyIsEnumerable()返回 true)和自有(Obejct.hasOwnProperty()返回 true)属性复制到目标对象。以字符串和符号为键的属性会被复制。对每个符合条件的属性,这个方法会使用源对象上的[[Get]]取得属性的值,然后使用目标对象上的[[Set]]设置属性的值,不能在两个对象间转移获取函数和设置函数。
虽然使用 Object 构造函数或对象字面量可以方便地创建对象,但这些方式也有明显不足:创建具有同样接口的多个对象需要重复编写很多代码
es5.1 并没有正式支持面向对象的结构,比如类和继承。但是,正如接下来几节会介绍的,巧妙地运用原型式继承可以成功地模拟同样的行为
es6 正式支持类和继承。es6 的类旨在完全涵盖之前规范设计的基于原型的继承模式。不过,无论从哪方面来看,es6 的类都仅仅是封装了 es5.1 构造函数加原型继承的语法糖而已。
抽象创建特定对象的过程。
function createPerson(name, age, job) {
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
console.log(this.name);
};
return o;
}
let person1 = createPerson("Nicholas", 29, "Software Engineer");
let person2 = createPerson("Greg", 27, "Doctor");
这种工厂模式虽然可以解决多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)。
ECMAScript 中的构造函数是用于创建特定类型对象的。如 Object、Array。当然也可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法。
上面的例子可改造如下
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
};
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas 10
person2.sayName(); // Greg
按照管理,构造函数的首字母是要大写的,只是为了区分构造函数和普通函数
要创建 Person 实例,应使用 new 操作符。以这种方式调用构造函数会执行如下操作。
上一个例子的最后,person1 和 person2 分别保存着 Person 的不同实例。这两个对象都有一个
constructor 属性指向 Person,如下所示:
console.log(person1.constructor == Person); // true
console.log(person2.constructor == Person); // true
constructor 本来是用于标识对象类型的。不过,一般认为 instanceof 操作符是确定对象类型更可靠的方式。(instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。)
定义自定义构造函数可以确保实例被标识为特定类型,相比于工厂模式,这是一个很大的好处。
直接调用 Person,this 指向全局对象,可通过 call/apply 调用
构造函数定义的方法会在每个实例上都创建一遍。person1 和 person2 都有 sayName 方法,但却不是同一个实例。
解决方法:将函数定义转移到构造函数外部
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
console.log(this.name);
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg
这样虽然解决了相同逻辑的函数重复定义的问题,但是全局作用域也因此被搞乱,如果对象需要多个方法,全局作用域就要多定义这些函数,同时也会导致自定义类型引用的代码不能很好的聚集在以前。这个新问题可以通过原型模式来解决。
每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接复制给它们的原型,如下:
function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
console.log(this.name);
};
let person1 = new Person();
person1.sayName(); // "Nicholas"
let person2 = new Person();
person2.sayName(); // "Nicholas"
console.log(person1.sayName == person2.sayName); // true
过调用 hasOwnProperty()能够清楚地看到访问的是实例属性还是原型属性
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.