当前位置: 首页 > 工具软件 > react-assign > 使用案例 >

react源码阅读:object-assign

金飞
2023-12-01
var _assign = require('object-assign');

对应es6的Object.assign合并两个对象的属性。

/*
object-assign
(c) Sindre Sorhus
@license MIT
*/

'use strict';
/* eslint-disable no-unused-vars */
// 获取对象的Symbols属性方法
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
// 用来判断某个对象是否含有指定的属性,和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
var hasOwnProperty = Object.prototype.hasOwnProperty;
// propertyIsEnumerable() 方法返回一个布尔值,表示指定的属性是否可枚举。通过原型链继承的属性除外。
var propIsEnumerable = Object.prototype.propertyIsEnumerable;

// 构造函数创建一个对象包装器。
function toObject(val) {
	// 如果值是null或undefined抛出错误,否则会创建一个空对象
	// 下面的例子将一个空的 Object 对象存到 o 中:
	// var o = new Object();
	// var o = new Object(undefined);
	// var o = new Object(null);
	if (val === null || val === undefined) {
		throw new TypeError('Object.assign cannot be called with null or undefined');
	}
	// 返回转换后的对象
	return Object(val);
}

// 是否使用原生属性
function shouldUseNative() {
	try {
		// 如果不支持es6的Object.assign语法返回false
		if (!Object.assign) {
			return false;
		}

		// 检测老V8版本中有bug的属性枚举顺序。
		// Detect buggy property enumeration order in older V8 versions.
		// Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名
		// (包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
		// https://bugs.chromium.org/p/v8/issues/detail?id=4118
		var test1 = new String('abc');  // eslint-disable-line no-new-wrappers
		// Object.getOwnPropertyNames(test1) = ["0", "1", "2", "length"]
		test1[5] = 'de';
		// Object.getOwnPropertyNames(test1) = ["0", "1", "2", "5", "length"]
		if (Object.getOwnPropertyNames(test1)[0] === '5') {
			return false;
		}

		// https://bugs.chromium.org/p/v8/issues/detail?id=3056
		var test2 = {};
		// 给对象test2添加属性,对应的val值是从0~10
		for (var i = 0; i < 10; i++) {
			// 静态 String.fromCharCode() 方法返回由指定的UTF-16代码单元序列创建的字符串。
			test2['_' + String.fromCharCode(i)] = i;
		}
		// 遍历test2的属性名,返回对应的值,生成一个新的数组order2
		// order2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
			return test2[n];
		});
		// 如果属性名和值不能一一对应,返回false
		if (order2.join('') !== '0123456789') {
			return false;
		}

		// https://bugs.chromium.org/p/v8/issues/detail?id=3056
		var test3 = {};
		// test3是一个属性名和值相等的对象
		'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
			test3[letter] = letter;
		});
		// 获取根据test3与一个空对象合并生成的新对象的所有key值,并转换成字符串
		if (Object.keys(Object.assign({}, test3)).join('') !==
				'abcdefghijklmnopqrst') {
			return false;
		}

		return true;
	} catch (err) {
		// We don't expect any of the above to throw, but better to be safe.
		return false;
	}
}

// 如果浏览器支持es6,就使用原生的,否则需要兼容处理
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
	var from;
	var to = toObject(target);
	var symbols;
	// arguments:[target,[...source]]
	// arguments[0]=target
	for (var s = 1; s < arguments.length; s++) {
		// from = source,注意s=1
		// to = target
		from = Object(arguments[s]);

		// 遍历第s个source的key值
		for (var key in from) {
			// 直接从原型链调用hasOwnProperty,防止对象上有同名自定义属性hasOwnProperty出错
			// 只拷贝或覆盖自身的属性,将source的属性添加到target或者把target中同名的属性名的值给覆盖掉
			if (hasOwnProperty.call(from, key)) {
				to[key] = from[key];
			}
		}

		if (getOwnPropertySymbols) {
			// 获取source中的符号属性名
			symbols = getOwnPropertySymbols(from);
			for (var i = 0; i < symbols.length; i++) {
				// 如果对应得符号属性可枚举,将可枚举的符号属性添加到target
				if (propIsEnumerable.call(from, symbols[i])) {
					to[symbols[i]] = from[symbols[i]];
				}
			}
		}
	}

	return to;
};

 类似资料: