沙雕爹爹

Stay foolish, stay humble.


  • Home

  • Archives

函数式编程第一章——走近函数式

Posted on 2019-05-17

1.1 什么是函数式编程

函数式编程的目标是使用函数来抽象作用在数据智商的控制流与操作,从而在系统中消除副作用并减少对状态的改变。

1.2 函数式编程是声明式编程

函数式编程属于声明式编程范式:这种范式会描述一系列的操作,但并不会暴露它们是如何实现的或是数据流如何穿过它们。

目前,更加主流的是命令式的或过程式的编程范式,如Java、C#、C++和其它大多数结构化语言和面向对象语言都对其提供支持。

命令式编程将计算机程序视为一系列自上而下的断言,通过修改系统的各个状态来计算最终的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 命令式具体告诉计算机如何执行某个任务
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (let i = 0; i < array.length; i++) {
array[i] = Math.pow(array[i], 2);
}
array; // -> [0, 1, 4, 9, ...]

// 声明式将程序的描述与求值分离开来
// 它关注于如何用各种表达式来描述程序逻辑,而不一定要指明其控制流或状态的变化
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(
function(num) {
return Math.pow(num, 2);
}
);

副作用带来的问题和纯函数

函数式编程基于一个前提,即使用纯函数构建具有不变性的程序。纯函数的性质:

  • 仅取决于提供的输入,而不依赖于任何在函数求值期间或调用间隔时可能变化的隐藏状态和外部状态
  • 不会造成超出其作用域的变化,例如修改全局对象或引用传递的参数

副作用:

  • 改变一个全局的变量、属性或数据结构
  • 改变一个函数参数的原始值
  • 处理用户输入
  • 抛出一个异常,除非它又被当前函数捕获了
  • 屏幕打印或记录日志
  • 查询HTML文档、浏览器的cookie或访问数据库

引用透明和可置换性

如果一个函数对于相同的输入始终产生相同的结果,那么就说它是引用透明的。

构建这样的程序更容易推理,因为可以在心中形成一个状态系统的模型,并通过重写或替换来达到期望的输出。

存储不可变数据

函数式编程是指为创建不可变的程序,通过消除外部可见的副作用,来对纯函数的声明式的求职过程。

1.3 函数式编程的优点

  • 促使将任务分解成简单的函数
  • 使用流式的调用链来处理数据
  • 通过响应式范式降低事件驱动代码的复杂性

鼓励复杂任务的分解

宏观上将,函数式编程实际上是分解和组合之间的相互作用。

函数式编程的模块化概念与单一职责原则息息相关,也就是说,函数都应该拥有单一的目的。

使用流式链来处理数据

函数链是一种惰性计算程序。这意味着当需要时才会执行。

复杂异步应用中的响应

1
2
3
4
5
6
7
8
9
// Rx.js 函数式响应式编程FRP
Rx.Observable.fromEvent(document.querySelector('#student-ssn'), 'keyup')
.map(input => input.srcElement.value)
.filter(ssn => ssn !== null && ssn.length !== 0)
.map(ssn => ssn.replace(/^\s*|\s*$|\-/g, ''))
.skipWhile(ssn => ssn.length !== 9)
.subscribe(
validSSN => console.log(`Valid SSN ${validSSN}`)
);

tasks-microtasks-queues-and-schedules

Posted on 2019-05-17

article

每个线程都有自己的event loop,因此每个web worker都有自己的event loop。

相同域名的窗口共享一个event loop,以实现窗口间的同步通信。

浏览器和Node.js不同的事件循环(EventLoop)

Posted on 2019-05-17

原文地址

浏览器环境

js执行为单线程(不考虑web worker),所有代码皆在执行线程调用栈完成执行。当执行线程任务清空后才会去轮询取任务队列中任务。

Node.js核心模块Timers详解

Posted on 2019-05-17

article
github

Javascript引擎是如何工作的?从调用栈到Promise你需要知道的一切

Posted on 2019-05-17

JavaScript引擎和全局内存

全局内存(也称为堆)是JavaScript引擎用来保存变量和函数声明的区域。在浏览器或在Node.js中,有许多预定义的函数和变量,被称为全局。全局内存将比我们的代码所占用的空间多。

全局执行上下文和调用栈

每个JavaScript引擎都有一个基本组件,称为调用栈。

当调用foo()时,引擎会将该函数压入调用堆栈中。

引擎同时还分配了全局执行上下文,这是JavaScript代码运行的全局环境。

对于嵌套函数中的每个嵌套函数,引擎都会创建本地执行上下文。

单线程的JavaScript

当浏览器加载某些JavaScript代码时,引擎会逐行读取并执行一下步骤:

  • 使用变量和函数声明填充全局内存(堆)
  • 将每个函数调用送到调用栈
  • 创建一个全局执行上下文
  • (如果有内部变量或嵌套函数)创建本地执行上下文

异步JavaScript,回调队列和事件循环

setTimeout是浏览器提供的API,该函数由浏览器直接运行(它会暂时出现在调用栈中,但会立即删除)。当时间过期后,浏览器接受我们传入的回调函数并将其移动到回调队列。

每个异步函数在被送入调用栈之前,必须通过回调队列。

由事件循环(Event Loop)组件,推动函数进入调用栈。事件循环只做一件事,检查调用栈是否为空。

事件队列

注意:浏览器API、回调队列、事件循环是异步JavaScript的支柱。

Promise

  • Promise.all: 当任何一个Promise rejected时,Promise.all就会rejects
  • Promise.race: 有一个Promise resolve/reject后立即resolve/reject
  • Promise.any: 表明任何Promise是否fullfilled,即使其中有的Promise已经rejected
  • Promise.allSettled: 检查是否全部Promise都结束

错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
async function getData() {
try {
if (true) {
throw new Error('error happens');
}
} catch (err) {
console.log('error catched in the catch block');
}
}

getData().catch(err => console.log('error catched in the promise .catch'));

// error catched in the catch block

使用async定义的函数会包裹在Promise里,抛出的错误在内部的catch块被捕获,不会再传播到.catch里。

jest笔记

Posted on 2019-05-17

支持的Matchers

  • toBe&& toEqual
  • 真值,结果同if(/*statement*/)
  • 数值,toBeGreaterThan, toBeGreaterThanOrEqual, toBeLessThan, toBeLessThanOrEqual, toBe, toEqual
  • String,toMatch
  • 数组和Iterables,toContain
  • 异常,toThrow

异步测试

  • 回调,done
  • Promise,then里直接expect,catch需要加一条语句expect.assertions(1);
  • .resolves/.rejects
  • Async/Await,类似于Promise

describe

jest会先调用describe,因此一些有意义的逻辑应该放在beforeEach、afterEach里。
jest会按照test定义的顺序来执行test。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
describe('1', () => {
console.log('1-describe');
beforeAll(() => console.log('1-once-before'));
afterAll(() => console.log('1-once-after'));
beforeEach(() => console.log('1-each-before'));
afterEach(() => console.log('1-each-after'));

test('1', () => {
console.log('1-test');
expect(1).toBe(1);
})

describe('2', () => {
console.log('2-describe');
beforeAll(() => console.log('2-once-before'));
afterAll(() => console.log('2-once-after'));
beforeEach(() => console.log('2-each-before'));
afterEach(() => console.log('2-each-after'));

test('2', () => {
console.log('2-test');
expect(2).toBe(2);
})
});
})

// 1-describe
// 2-describe
// 1-once-before
// 1-each-before
// 1-test
// 1-each-after
// 2-once-before
// 1-each-before
// 2-each-before
// 2-test
// 2-each-after
// 1-each-after
// 2-once-after
// 1-once-after

调试技巧

当某个test出错时,可以使用test.only来检查是它本身的错误,还是与其他test有关。

如果test.only时通过,和其他test一起就不通过,猜测很可能与共享状态有关。可以在beforeEach里重置共享状态来验证。

1
2
3
4
5
6
7
test.only(() => {
expect(1).toBe(1);
})

test(() => {
expect('aaa').toMatch(/a/);
})

Introducing d3-scale

Posted on 2019-05-13

原文链接

espouse: 支持,拥护
tyranny: 暴政,专制统治
inevitably: 必然地,不可避免地
amplify: 放大,增强,扩展
cognition: 认识,认知
spatial: 空间的
quantitative: 量化的
ordinal: 序数词
categorical: 绝对的,明确的
planar: 平面的
luminous: 发光的,鲜亮的
mass: 堆,团;大量,大群;大多数,主体;质量;体积
carat: 克拉
scatterplot: 散布图
trivial: 不重要的,微不足道的,琐碎的;无聊的;狭隘的
logarithmic: 对数
preserve: 保护;保养,保持,维护;拯救;保藏
proportionality: 相称
alleviate: 减轻,缓解
tedium: 单调乏味
legible: 清晰的
axes: axis轴
bidirectional: 双向的
brush: 刷子,画笔;刷;轻拂;小冲突;灌木丛;断落的树枝;狐狸尾巴;电刷
interpolate: 插入;添加;插嘴说

学习es-shims

Posted on 2019-05-07

github

ArrayBufferView

Posted on 2019-05-07

MDN

Function && Object

Posted on 2019-05-05

Function

  • AsyncFunction
  • GeneratorFunction
  • ArrowFunctions

Function构造函数可以用来创建Function对象,直接调用Function构造函数可以动态创建函数,但有安全性和与eval相同的性能问题。不同于eval的是,Function构造函数只能在全局作用域创建函数。

每个JavaScript函数实际上都是一个Function对象。

1
(function() {}).constructor === Function; // true

Properties

  • Function.prototype.caller
  • Function.prototype.length
  • Function.prototype.name
  • Function.prototype.displayName
  • Function.prototype.constructor

Methods

  • Function.prototype.apply()
  • Function.prototype.bind()
  • Function.prototype.call()
  • Function.prototype.isGenerator()
  • Function.prototype.toSource()
  • Function.prototype.toString()

Object

  • Object.assign()
  • Object.create()
  • Object.defineProperty()
  • Object.defineProperties()
  • Object.entries()
  • Object.entries()
  • Object.freeze()
  • Object.fromEntries()
  • Object.getOwnPropertyDescriptor()
  • Object.getOwnPropertyDescriptors()

  • Object.prototype.hasOwnProperty()

  • Object.prototype.isPrototypeOf()
  • Object.prototype.propertyIsEnumerable()
  • Object.prototype.toSource()
  • Object.prototype.toString()
  • Object.prototype.toLocaleString()
  • Object.prototype.unwatch()
  • Object.prototype.valueOf()
  • Object.prototype.watch()

Object literal notation vs JSON

  • JSON的属性名必须用双引号扩起来,并且不能使用简写,如{ x }
  • JSON的值只能是strings、numbers、arrays、true、false、null、或者另一个JSON对象
  • 函数不能作为JSON的值
  • Date对象会被parse为string
  • JSON.parse()遇到计算属性(getter、setter)会报错

Object.assgin()

只复制enumerable和own的properties。在source上使用[[Get]],在target上使用[[Set]],因此会调用getters和setters方法。

不适用于包含getters的source的merge。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var foo = {
get bar() {
return 1;
},
set bar(val) {
this.bar = val;
},
set baz(val) {
this.baz = val;
}
}
var obj = {};

Object.assign(obj, foo);
console.log(obj); // {bar: 1, baz: undefined}

如果需要copy属性的定义,如enumerability,需要使用Object.getOwnPropertyDescriptor()和Object.defineProperty()。

String和Symbol类型的属性都会被复制。

Object.assign不接收参数null和undefined,会报错。原始类型会被包装成对象。

1
2
3
4
var v1 = 'abc';
var obj = Object.assign({}, v1);

console.log(obj); // {"0": "a", "1": "b", "2": "c"}

如果assign过程中报错,之前的改变会保留在target上:

1
2
3
4
5
6
7
8
9
10
11
var target = Object.defineProperty({}, 'foo', {
value: 1,
writable: false
}); // target.foo 是read-only的属性

Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 在尝试 assign target.foo的时候报错

console.log(target); // {bar: 2, foo2: 3, foo: 1}
// foo assign的时候报错,foo3和baz都没有assign

polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target === null || target === undefined) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}

var to = Object(target);

for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];

if (nextSource !== null && nextSource !== undefined) { // Skip if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}

return to;
},
writable: true,
configurable: true
})
}

Object.create()

创建一个新对象,并将传入的对象参数作为新对象的原型。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Shape
function Shape() {
this.x = 0;
this.y = 0;
}

// method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved. ');
}

// Rectangle
function Rectangle() {
Shape.call(this); // call super constructor
}

// extends
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 2); // Shape moved.

继承多个对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}

// inherit one
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// re-assign constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
// do something
}

使用Object.create()的propertiesObject参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
var o;

o = Object.create(null); // null 作为原型

o = {};
// 等于
o = Object.create(Object.prototype);

o = Object.create(Object.prototype, { // 创建一个带有示例属性的对象
foo: { // 普通属性
writable: true,
configurable: true,
value: 'hello'
},
bar: { // getter-setter 属性
configurable: false,
get: function() {return 10;},
set: function(val) {
console.log("Setting 'o.bar' to", value);
}
}
});

function Constructor() {}

o = new Constructor();
// 等于
o = Object.create(Constructor.prototype);
// 这里不会调用constructor内部的初始化代码,如果有的话,如this.x = 1

o = Object.create({}, {p: {value: 42}});
// 创建一个对象,原型是一个新的空的对象,并给它添加属性'p'

// 默认属性是不可写、枚举、配置的
o.p = 24;
o.p; // 42

o.q = 12;
for (var prop in o) {
console.log(prop);
}
// 'q'

delete o.p; // false

var o2;

o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
// 等于
o2 = Object.create({p: 42});

继承自null的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var oco = Object.create({}); // 普通对象
var ocn = Object.create(null); // null 对象

console.log(oco); // {}
console.log(ocn); // {}

oco.p = 1; // {p: 1}
ocn.p = 0; // {p: 0}

console.log('oco is ' + oco); // oco is [object Object]
console.log('ocn is ' + ocn); // throws error: Cannot convert object to primitive value

alert(oco); // [object Object]
alert(ocn); // throws error: Cannot convert object to primitive value

oco.toString(); // [object Object]
ocn.toString(); // throws error: ocn.toString is not a function
// 同样,valueOf、hasOwnProperty 都会报错

oco.constructor; // Object() { [native code] }
ocn.constructor; // undefined
1
2
3
4
5
6
7
8
var ocn = Object.create(null);

ocn.toString = toString;
// 或者
Object.setPrototypeOf(ocn, Object.prototype);

ocn.toString(); // [object Object]
ocn.constructor(); // Object() { [native code] }

polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (typeof Object.create !== 'function') {
Object.create = function(proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}

if (typeof propertiesObject !== 'undefined') {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
}

function F() {}
F.prototype = proto;

return new F();
}
}

Object.defineProperty()

在一个对象上,定义一个新属性,或修改一个已存在的属性。不能重复调用,重复调用会报错。

Syntax

Object.defineProperty(obj, prop, descriptor)

默认值:

  • configurable: false
  • enumerable: false
  • value: undefined
  • writable: false
  • get: undefined
  • set: undefined

当descriptor有value和writable,或者get和set之一时,被视为data descriptor。

相反的,当descriptor同时有value或writable,和get或set时,会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 对
Object.defineProperty(obj, 'key', {
value: 'static',
writable: true
});

// 对
Object.defineProperty(obj, 'key', {
get() { return 'static'; }
});

// 报错
Object.defineProperty(obj, 'key', {
value: 'static',
get() {return 'static'; }
})

其他例子。

Object.defineProperties()

Syntax

Object.defineProperties(obj, props)

polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function defineProperties(obj, properties) {
function convertToDescriptor(desc) {
function hasProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}

function isCallable(v) {
// NB: modify as necessary if other values than functions are callable
return typeof v === 'function';
}

var d = {};

if (hasProperty(desc, 'enumerable'))
d.enumerable = !!desc.enumerable;
if (hasProperty(desc, 'configurable'))
d.configurable = !!desc.configurable;
if (hasProperty(desc, 'value'))
d.value = desc.value;
if (hasProperty(desc, 'writable'))
d.writable = !!desc.writable;
if (hasProperty(desc, 'get')) {
var g = desc.get;

if (!isCallable(g) && typeof g !== 'undefined')
throw new TypeError('bad get');
d.get = g;
}
if (hasProperty(desc, 'set')) {
var s = desc.set;

if (!isCallable(s) && typeof s !== 'undefined')
throw new TypeError('bad set');
d.set = s;
}

if (('get' in d || 'set' in d) && ('value' in d || 'writable' in d))
throw new TypeError('identity-confused descriptor');

return d;
}

if (typeof obj !== 'object' || obj === null)
throw new TypeError('bad obj');

properties = Object(properties);

var keys = Object.keys(properties);
var descs = [];

for (var i = 0; i < keys.length; i++)
descs.push(keys[i], convertToDescriptor(properties[keys[i]]));

for (var i = 0; i < descs.length; i++)
Object.defineProperty(obj, descs[i][0], descs[i][1]);

return obj;
}

Object.entries()

返回给定对象的own enumerable string-keyed属性[key, value]对的数组。和for...in循环的顺序是一致的。

如果需要返回特定顺序,可以做个sort:

Object.entries(obj).sort((a, b) => b[0].localCompare(a[0]));

Syntax

Object.entries(obj)

polyfill

1
2
3
4
5
6
7
8
9
10
11
if (!Object.entries) {
Object.entries = function (obj) {
var ownProps = Object.keys(obj),
i = ownProps.length,
resArray = new Array(i); // prealocate the Array
while(i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];

return resArray;
}
}

Object.fromEntries()

Object.entries()作用相反的方法。

Object.freeze()

一个被冷冻的对象不能再修改。它的原型,即__proto__属性也不能被修改。

Syntax

Object.freeze(obj)

冷冻有元素的ArrayBufferView会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> Object.freeze(new Unit8Array(0)) // No elements
Unit8Array []

> Object.freeze(new Unit8Array(1)) // Has elements
TypeError: Cannot freeze array buffer views with elements

> Object.freeze(new DataView(new ArrayBuffer(32))) // No elements
DataView {}

> Object.freeze(new Float64Array(new ArrayBuffer(64), 63, 0)) // No elements
Float64Array []

> Object.freeze(new Float64Array(new ArrayBuffer(64), 32, 2)) // Has elements
TypeError: Cannot freeze array buffer views with elements

Object.seal()

禁止添加新的属性,已有属性被设置为non-configurable。现有属性如果writable为true,则仍可修改。

Syntax

Object.seal(obj)

Object.preventExtensions()

不能再添加新的属性。

Object.isExtensible()

Object.isFrozen()

Object.isSealed()

Object.getOwnPropertyDescriptor()

返回own property的descriptor。

Syntax

Object.getOwnPropertyDescriptor(obj, prop)

Object.getOwnPropertyDescriptors()

应用:

浅复制

1
2
3
4
Object.create(
Object.getPrototypeof(obj),
Object.getOwnPropertyDescriptors(obj)
)

创建子类

1
2
3
4
5
6
7
8
function SuperClass() {}
SuperClass.prototype = {};

function SubClass() {}
SubClass.prototype = Object.create(
SuperClass.prototype,
{}
)

Object.getOwnPropertyNames()

返回一个包含所有属性的数组(包括non-enumerable属性,不包括Symbol类型).

Object.getOwnPropertySymbols()

返回一个包含所有Symbol类型属性的数组。

Object.keys()

返回一个包含所有own、enumerable、string属性的数组。

polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;

return function(obj) {
if (typeof obj !== 'function' && (tyoeof obj !== 'object' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}

var result = [], prop, i;

for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}

if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}

return result;
}
}())
}

Object.values()

返回一个包含own enumerable string属性的值的数组。

Object.is()

比较两个值。

1
2
3
4
5
6
7
8
9
10
11
12
Object.is('foo', 'foo'); // true
Object.is(window, window); // true

Object.is([], []); // false
Object.is(obj1, obj2); // false

Object.is(null, null); // true

// 特殊例子
Object.is(0, -0); // false
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true

polyfill

1
2
3
4
5
6
7
8
9
10
11
12
if (!Object.is) {
Object.is = function(x, y) {
// SameValue algorithm
if (x === y) { // Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
}

Object.getPrototypeOf()

返回内部[[Prototype]]属性的值。

Object.setPrototypeOf()

给一个对象设置原型(内部[[Prototype]]属性的值)。

注意: 更改一个对象的[[Prototype]]是一个非常慢的操作,即使现代Javascript引擎做了优化。如果对性能有要求的话,避免修改[[Prototype]],使用Object.create()方法创建一个新对象。

polyfill

1
2
3
4
5
// Only works in Chrome and FireFox, does not work in IE:
Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
obj.__proto__ = proto;
return obj;
}
123…6

沙雕爹爹

Personal tech blog.

55 posts
45 tags
© 2019 沙雕爹爹
Powered by Hexo
|
Theme — NexT.Muse v5.1.4