前提:
ディープコピーとシャローコピーは、オブジェクトや配列などの参照データ型専用です。
1.スタックメモリ
詳細については、別のブログのデータ型とスタックストレージを参照してください
2.浅いコピーと深いコピー
ディープコピーとシャローコピーの概略図はおおまかに次のとおりです。
浅いコピーは、オブジェクト自体ではなく、オブジェクトへのポインタのみをコピーします。古いオブジェクトと新しいオブジェクトは、同じメモリを共有します。ただし、ディープコピーを使用すると、まったく同じオブジェクトが作成されます。新しいオブジェクトは元のオブジェクトとメモリを共有しません。新しいオブジェクトを変更しても、元のオブジェクトは変更されません。
割り当てと浅いコピーの違い
割り当て:
オブジェクトを新しい変数に割り当てるとき、それは実際にはスタック上のオブジェクトのアドレスであり、ヒープ内のデータではありません。つまり、2つのオブジェクトが同じストレージスペースを指します。どちらのオブジェクトが変更されても、実際には変更されたストレージスペースのコンテンツであるため、2つのオブジェクトはリンクされます。
浅いコピー:
浅いコピーは、オブジェクトのビット単位のコピーであり、元のオブジェクトの属性値の正確なコピーを使用して新しいオブジェクトを作成します。属性が基本型の場合は基本型の値がコピーされます。属性がメモリアドレス(参照型)の場合はメモリアドレスがコピーされるため、一方のオブジェクトがこのアドレスを変更すると、もう一方のオブジェクトに影響します。つまり、デフォルトのコピーコンストラクターは、オブジェクトの浅いコピーコピー(メンバーごとに順番にコピー)のみを実行します。つまり、リソースをコピーせずにオブジェクトスペースのみをコピーします。
手書きのディープコピー(再帰的):
/**
* 深拷贝
*/
const obj1 = {
age: 20,
name: 'xxx',
address: {
city: 'beijing'
},
arr: ['a', 'b', 'c']
}
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {
}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {
}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
JavaScriptプロトタイプとプロトタイプチェーン
1.プロトタイプ
各関数には、表示プロトタイプと呼ばれるプロトタイププロパティがあります。
2._プロト_
各インスタンスオブジェクトには、暗黙的なプロトタイプと呼ばれる_ proto 属性があり
ます。各インスタンスオブジェクトの暗黙的なプロトタイプ 。proto_属性は、独自のコンストラクターの明示的なプロトタイププロトタイプを指します。
3.コンストラクター
各プロトタイプには、関連するコンストラクターを指すコンストラクター属性があります。
4.プロトタイプチェーン
オブジェクトのプロパティを取得するときに、オブジェクト自体にこのプロパティがない場合は、プロトタイプ__proto__に移動して検索します。それでも見つからない場合は、プロトタイプのプロトタイプを先頭(オブジェクト)まで検索します。プロトタイプ)が見つかりました。Object.prototypeオブジェクトの__proto__プロパティ値もnullです。
ここで、Objectはプロトタイプチェーンの最上位に属し、すべてのコンストラクターのプロトタイプはObject.prototypeを指していることに注意してください。
function Fun(){
}
// 我创造了一个函数Fn
// 这个函数由Function生成(Function作为构造函数)
var fn=new Fun()
// 我创建了一个函数fn
// 这个函数由构造函数Fun生成
console.log(fn.__proto__===Fun.prototype) //true
// fn的__proto__指向其构造函数Fun的prototype
console.log(Fun.__proto__===Function.prototype) //true
// Fun的__proto__指向其构造函数Function的prototype
console.log(Function.__proto__===Function.prototype) //true
// Function的__proto__指向其构造函数Function的prototype
// 构造函数自身是一个函数,他是被自身构造的
console.log(Function.prototype.__proto__===Object.prototype) //true
// Function.prototype的__proto__指向其构造函数Object的prototype
// Function.prototype是一个对象,同样是一个方法,方法是函数,所以它必须有自己的构造函数也就是Object
console.log(Fun.prototype.__proto__===Object.prototype) //true
// 与上条相同
// 此处可以知道一点,所有构造函数的的prototype方法的__都指向__Object.prototype(除了....Object.prototype自身)
console.log(Object.__proto__===Function.prototype) //true
// Object作为一个构造函数(是一个函数对象!!函数对象!!),所以他的__proto__指向Function.prototype
console.log(Object.prototype.__proto__===null) //true
// Object.prototype作为一切的源头,他的__proto__是null
// 下面是一个新的,额外的例子
var obj={
}
// 创建了一个obj
console.log(obj.__proto__===Object.prototype) //true
// obj作为一个直接以字面量创建的对象,所以obj__proto__直接指向了Object.prototype,而不需要经过Function了!!
// 下面是根据原型链延伸的内容
/*还有一个上文并未提到的constructor, constructor在原型链中,是作为对象prototype的一个属性存在的,它指向构造函数
(由于主要讲原型链,这个就没在意、);*/
console.log(obj.__proto__.__proto__===null) //true
console.log(obj.__proto__.constructor===Object) //true
console.log(obj.__proto__.constructor.__proto__===Function.prototype) //true
console.log(obj.__proto__.constructor.__proto__.__proto__===Object.prototype) //true
console.log(obj.__proto__.constructor.__proto__.__proto__.__proto__===null) //true
console.log(obj.__proto__.constructor.__proto__.__proto__.constructor.__proto__===Function.prototype) //true
// 以上,有兴趣的可以一一验证 F12搞起.
jsデータ型判定
4つの方法
typeof、instanceof、constructor、Object.prototype.toString.call()、jquery.type()
1 .typeof
console.log(
typeof 100, //"number"
typeof 'abc', //"string"
typeof false, //"boolean"
typeof undefined, //"undefined"
typeof null, //"object"
typeof [1,2,3], //"object"
typeof {
a:1,b:2,c:3}, //"object"
typeof function(){
console.log('aaa');}, //"function"
typeof new Date(), //"object"
typeof /^[a-zA-Z]{
5,20}$/, //"object"
typeof new Error() //"object"
typeof new Number(100), //'object'
typeof new String('abc'),// 'string'
typeof new Boolean(true),//'boolean'
);
基本データ型(参照データ型の数値、文字列、ブール値、未定義、関数)では、typeofを使用してデータ型を検出し、対応するデータ型の小文字をそれぞれ返すことができます。
もう1つ:typeof検出コンストラクターによって作成された数値、文字列、ブール値はすべて
、オブジェクトの基本データ型:nullに戻ります。参照データ型:配列、オブジェクト、日付、正規表現。typeof検出は使用できません。小文字のオブジェクトを返します
2。instanceof
typeofを使用して判断することに加えて、instanceofを使用することもできます。instanceof演算子は、コンストラクターを指定するか、特定のタイプを指定する必要があります。これは、このコンストラクターのプロトタイプが特定のオブジェクトのプロトタイプチェーン上にあるかどうかを判断するために使用されます。
console.log(
100 instanceof Number, //false
'dsfsf' instanceof String, //false
false instanceof Boolean, //false
undefined instanceof Object, //false
null instanceof Object, //false
[1,2,3] instanceof Array, //true
{
a:1,b:2,c:3} instanceof Object, //true
function(){
console.log('aaa');} instanceof Function, //true
new Date() instanceof Date, //true
/^[a-zA-Z]{
5,20}$/ instanceof RegExp, //true
new Error() instanceof Error //true
)
基本的なデータ型の中には、数値、文字列、ブール値があります。リテラル値はinstanceofで検出できませんが、コンストラクターで作成される値は次のようになります。
var num = new Number(123);
var str = new String('dsfsf');
var boolean = new Boolean(false);
また、nullとundefinedの両方がfalseを返すことに注意してください。これは、それらのタイプがそれ自体であり、Objectが作成したものではないため、falseが返されるためです。
3.コンストラクター
コンストラクターはプロトタイプオブジェクトのプロパティであり、コンストラクターを指します。インスタンスオブジェクトが属性を検索する順序に従って、インスタンスオブジェクトにインスタンス属性またはメソッドがない場合、それらはプロトタイプチェーンで検索されます。したがって、インスタンスオブジェクトはコンストラクター属性を使用することもできます。
型のインスタンスのコンストラクターを出力すると、次のようになります。
console.log(new Number(123).constructor)
//ƒ Number() { [native code] }
Numberのコンストラクターを指していることがわかります。したがって、num.constructor == Numberを使用して、変数がNumber型であるかどうかを判別できます。
var num = 123;
var str = 'abcdef';
var bool = true;
var arr = [1, 2, 3, 4];
var json = {
name:'wenzi', age:25};
var func = function(){
console.log('this is function'); }
var und = undefined;
var nul = null;
var date = new Date();
var reg = /^[a-zA-Z]{5,20}$/;
var error= new Error();
function Person(){
}
var tom = new Person();
// undefined和null没有constructor属性
console.log(
tom.constructor==Person,
num.constructor==Number,
str.constructor==String,
bool.constructor==Boolean,
arr.constructor==Array,
json.constructor==Object,
func.constructor==Function,
date.constructor==Date,
reg.constructor==RegExp,
error.constructor==Error
);
//所有结果均为true
undefinedとnullを除いて、他のタイプはコンストラクター属性によって判断できます。
4. Object.prototype.toString.call()を使用して、オブジェクトタイプを検出します
toString()を介して各オブジェクトのタイプを取得できます。Object.prototype.toString()によって各オブジェクトが検出されるためには、Function.prototype.call()またはFunction.prototype.apply()の形式で呼び出され、チェック対象のオブジェクトが最初のパラメーター、thisArgと呼ばれます。
var toString = Object.prototype.toString;
toString.call(123); //"[object Number]"
toString.call('abcdef'); //"[object String]"
toString.call(true); //"[object Boolean]"
toString.call([1, 2, 3, 4]); //"[object Array]"
toString.call({
name:'wenzi', age:25}); //"[object Object]"
toString.call(function(){
console.log('this is function'); }); //"[object Function]"
toString.call(undefined); //"[object Undefined]"
toString.call(null); //"[object Null]"
toString.call(new Date()); //"[object Date]"
toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]"
toString.call(new Error()); //"[object Error]"
このように、
Object.prototype.toString.call()
変数の型を決定する最も正確な方法は、変数の使用方法であることがわかります。
5.無敵の全能のメソッド:jquery.type()
オブジェクトが未定義またはnullの場合、対応する「undefined」または「null」が返されます
jQuery.type( undefined ) === "undefined"
jQuery.type() === "undefined"
jQuery.type( window.notDefined ) === "undefined"
jQuery.type( null ) === "null"
/*如果对象有一个内部的[[Class]]和一个浏览器的内置对象的 [[Class]] 相同,我们返回相应的 [[Class]] 名字。
(有关此技术的更多细节。 )*/
jQuery.type( true ) === "boolean"
jQuery.type( 3 ) === "number"
jQuery.type( "test" ) === "string"
jQuery.type( function(){
} ) === "function"
jQuery.type( [] ) === "array"
jQuery.type( new Date() ) === "date"
jQuery.type( new Error() ) === "error" // as of jQuery 1.9
jQuery.type( /test/ ) === "regexp"
其他一切都将返回它的类型“object”
6.関数をカプセル化して、変数の正確なタイプを取得することもできます
function gettype(obj){ var type = typeof obj;
if(type!== 'object'){ return type; } //オブジェクト型データでない場合は、typeofで直接判断できます
//オブジェクトタイプデータの場合は、Object.prototype.toString.call(obj)を使用してタイプを正確に判別し、
return Object.prototype.toString.call(obj).replace(/ ^ [object(\ S + )] $ /、 '$ 1');
}