91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript對象的基礎知識點有哪些

發布時間:2021-12-20 15:35:54 來源:億速云 閱讀:148 作者:小新 欄目:web開發

這篇文章給大家分享的是有關JavaScript對象的基礎知識點有哪些的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

1 、對象的基礎

1.1 類型

JavaScript有六種主要語言類型:

string , number , boolean ,undefined , null , object

基本類型:string,number,boolean,undefined,null;基本類型本身不是對象。

null

但是 null有時會被當成對象,typeof null 會返回object,實際上null是基本類型。原因是不同對象在底層都是表示為二進制,在JavaScript中二進制前三位都為0會被判斷為object類型,null表示全 0,所以typeof時會返回object。

特殊對象子類型

數組

數組也是對象的一種類型,具備一些額外的行為。數組的組織方式比一般的對象要復雜。

函數

函數本質上和普通函數一樣,只是可以調用,所以可以操作對象一樣操作函數。

1.2 內置對象

String
Number
Date
Boolean
Object
Function
Array

1.3 內容

.a 稱之為屬性訪問,[‘a’]稱之為操作符訪問。

//對象中的屬性名始終是字符串
myobj={}

myobj[myobj]='bar'//賦值

myobj['[object object]'] //'bar'

1.4 可計算屬性名

es6 增加可計算屬性名,可以在文字形式中使用 [] 包裹一個表達式來當作屬性名

var perfix = 'foo'

var myobj={
    [perfix + 'bar'] :'hello'
}

myobj['foobar']//hello

1.5 屬性描述符

es5開始,所有屬性具備了屬性描述符,比如可以直接判斷屬性是否可讀可寫等。

/*
 * 重要函數:
 * Object.getOwnPropertyDescriptor(..) //獲取屬性描述符
 * Object.defineProperty(..) //設置屬性描述符
 */
 writeble(可讀性)
 configurable(可配置性)
 enumerable (可枚舉性)

1.6遍歷

for in

for in可用來遍歷對象的可枚舉屬性列表(包括[[Prototype]]鏈),需要手動獲取屬性值。可以遍歷數組及普通的對象

for of

es6新增,可以用來遍歷數組的屬性值,for of循環首先會向被訪問對象請求一個迭代器對象,然后通過調用迭代器對象的next()方法來遍歷所有的返回值。
數組有內置的@@iterator,

for of 如何工作?
var arr = [1, 2, 3]
var it = arr[Symbol.iterator]()//迭代器對象
console.log(it.next());//{value: 1, done: false}
console.log(it.next());//{value: 2, done: false}
console.log(it.next());//{value: 3, done: false}
console.log(it.next());//{value: undefined, done: true}

/*
 * 用es6 的Symbol.iterator 來獲取對象的迭代器內部屬性。
 * @@iterator本身并不是一個迭代器對象,而是一個返回迭代器對象的函數。
 */
對象如何內置@@iterator,遍歷屬性的值?

因為對象沒有內置一個@@iterator,無法自動完成for…of遍歷。但是,可以給你任何想遍歷的對象定義@@iterator,舉例來說:

  var obj={
      a:1,b:2
  }
  
   Object.defineProperty(obj, Symbol.iterator, {
        enumerable: false,
        writable: false,
        configurable: true,
        value: function () {
            var self = this
            var idx = 0
            var ks = Object.keys(self)
            return {
                next: function () {
                    return {
                        value: self[ks[idx++]],
                        done: (idx > ks.length)
                    }
                }
            }
        }
    })
    
    //手動遍歷
    var it = obj[Symbol.iterator]()//迭代器對象
    console.log(it.next());//{value: 1, done: false}
    console.log(it.next());//{value: 2, done: false}
    console.log(it.next());//{value: undefined, done: true}

   //for of 遍歷
    for (const v of obj) {
        console.log(v);
    }
    //2
    //3

其他數組遍歷函數

 /*
 forEach:會遍歷所有并忽略返回值
 some:會一直運行到回調函數返回 true(或者"真"值)
 every:會一直運行到回調函數返回 false(或者"假"值)
 map:
 filter:返回滿足條件的值
 reduce:
 some和every 和for的break語句類似,會提前終止遍歷
 */

2、混合類對象

面試題

1、對象的深拷貝和淺拷貝

相關知識

基本類型和引用類型

上面提過,JavaScript的主要的語言類型有六種:string、number、boolean、null、undefined、object;其中前5種屬于基本類型,最后的object屬于引用類型。

JavaScript的變量的存儲方式:棧(stack)和 堆(heap)

棧:自動分配內存空間,系統自動釋放,里面存放的是基本類型的值和引用類型的地址

堆:動態分配的內存,大小不定,也不會自動釋放。里面存放引用類型的值

基本類型與引用類型最大的區別就是 傳值 和 傳址 的區別

基本類型采用值傳遞;引用類型采用的地址(指針)傳遞,將存放在棧內存中的地址賦值給接收的 變量。

淺拷貝和深拷貝是什么?

淺拷貝:對象的淺拷貝,會對‘主’對象進行拷貝,但不會復制對象里面的對象。‘里面的對象’會在原來的對象和它的副本之間共享。

深拷貝:對對象的深拷貝,不僅將原對象的各個屬性逐個復制出去,而且將原對象各個屬性所包含的對象也依次采用深復制的方法遞歸復制到新對象上,所以對一個對象的修改并不會影響另一個對象。

舉例來說:

var anotherObject={
    b:"b"
}

var anotherArray=[]

var myObject={
    a:'a',
    b:anotherObject, //引用,不是副本
    c:anotherArray //另外一個引用
}

anotherArray.push(anotherObject,myObject)

/*
  如何準確的復制 myObject?
 淺復制 myObject,就是復制出 新對象中的 a 的值會復制出對象中a 的值,也就是 'a',
 但是對象中的 b、c兩個屬性其實只是三個引用,新對象的b、c屬性和舊對象的是一樣的。
 
 深復制 myObject,除了復制 myObject 以外還會復制 anotherObject 和 anotherArray。
 但是這里深復制 myObject會出現一個問題,anotherArray 引用 anotherObject 和 myObject,
 所以又需要復制 myObject,這樣就會由于循環引用導致死循環。
 后面會介紹如何處理這種情況。
*/

如何實現淺拷貝

object

object.assign()、擴展運算符(…)

var obj1 = {x: 1, y: 2}
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}
obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 2, y: 2}

var obj1 = {
    x: 1, 
    y: {
        m: 1
    }
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}
Array

slice()、concat、Array.from()、擴展運算符(…)、concat、for循環

var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice();
console.log(arr1); //[1, 2, [3, 4]]
console.log(arr2); //[1, 2, [3, 4]]

arr2[0] = 2 
arr2[2][1] = 5; 
console.log(arr1); //[1, 2, [3, 5]]
console.log(arr2); //[2, 2, [3, 5]]

如何實現深拷貝

JSON.parse(JSON.stringify(obj))

進行JSON.stringify()序列化的過程中,undefined、任意的函數以及 symbol 值,在序列化過程中會被忽略(出現在非數組對象的屬性值中時)或者被轉換成 null(出現在數組中時)。

var obj1 = {
    x: 1, 
    y: {
        m: 1
    },
    a:undefined,
    b:function(a,b){
      return a+b
    },
    c:Symbol("foo")
};
var obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ?, c: Symbol(foo)}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ?, c: Symbol(foo)}
console.log(obj2) //{x: 2, y: {m: 2}}
深拷貝函數的簡單實現
function deepClone(obj){
  let result = Array.isArray(obj)?[]:{};
  if(obj && typeof obj === "object"){
    for(let key in obj){
      if(obj.hasOwnProperty(key)){
        if(obj[key] && typeof obj[key] === "object"){
          result[key] = deepClone(obj[key]);
        }else{
          result[key] = obj[key];
        }
      }
    }
  }
  return result;
}

var obj1 = {
    x: {
        m: 1
    },
    y: undefined,
    z: function add(z1, z2) {
        return z1 + z2
    },
    a: Symbol("foo"),
    b: [1,2,3,4,5],
    c: null
};
var obj2 = deepClone(obj1);
obj2.x.m = 2;
obj2.b[0] = 2;
console.log(obj1);
console.log(obj2);

//obj1
{
a: Symbol(foo)
b: (5) [1, 2, 3, 4, 5]
c: null
x: {m: 1}
y: undefined
z: ? add(z1, z2)
}

//obj2
{
a: Symbol(foo)
b: (5) [2, 2, 3, 4, 5]
c: null
x: {m: 2}
y: undefined
z: ? add(z1, z2)
}

上面的深拷貝方法遇到循環引用,會陷入一個循環的遞歸的過程,從而導致爆棧。因此需要改進。

深拷貝函數的改進(防止循環遞歸)

解決因循環遞歸而暴棧的問題,只需要判斷一個對象的字段是否引用了這個對象或這個對象的任意父級即可。

function deepClone(obj, parent = null){ // 改進(1)
  let result = Array.isArray(obj)?[]:{};
  let _parent = parent;  // 改進(2)
  while(_parent){ // 改進(3)
    if(_parent.originalParent === obj){
      return _parent.currentParent;
    }
    _parent = _parent.parent;
  }
  if(obj && typeof obj === "object"){
    for(let key in obj){
      if(obj.hasOwnProperty(key)){
        if(obj[key] && typeof obj[key] === "object"){
          result[key] = deepClone(obj[key],{ // 改進(4)
            originalParent: obj,
            currentParent: result,
            parent: parent
          });
        }else{
          result[key] = obj[key];
        }
      }
    }
  }
  return result;
}

// 調試用
var obj1 = {
    x: 1, 
    y: 2
};
obj1.z = obj1;
var obj2 = deepClone(obj1);
console.log(obj1); 
console.log(obj2);
深拷貝函數最終版(支持基本的數據類型、原型鏈、RegExp、Date類型)
function deepClone(obj, parent = null){ 
  let result; // 最后的返回結果

  let _parent = parent; // 防止循環引用
  while(_parent){
    if(_parent.originalParent === obj){
      return _parent.currentParent;
    }
    _parent = _parent.parent;
  }
  
  if(obj && typeof obj === "object"){ // 返回引用數據類型(null已被判斷條件排除))
    if(obj instanceof RegExp){ // RegExp類型
      result = new RegExp(obj.source, obj.flags)
    }else if(obj instanceof Date){ // Date類型
      result = new Date(obj.getTime());
    }else{
      if(obj instanceof Array){ // Array類型
        result = []
      }else{ // Object類型,繼承原型鏈
        let proto = Object.getPrototypeOf(obj);
        result = Object.create(proto);
      }
      for(let key in obj){ // Array類型 與 Object類型 的深拷貝
        if(obj.hasOwnProperty(key)){
          if(obj[key] && typeof obj[key] === "object"){
            result[key] = deepClone(obj[key],{ 
              originalParent: obj,
              currentParent: result,
              parent: parent
            });
          }else{
            result[key] = obj[key];
          }
        }
      }
    }
  }else{ // 返回基本數據類型與Function類型,因為Function不需要深拷貝
    return obj
  }
  return result;
}

// 調試用
function construct(){
    this.a = 1,
    this.b = {
        x:2,
        y:3,
        z:[4,5,[6]]
    },
    this.c = [7,8,[9,10]],
    this.d = new Date(),
    this.e = /abc/ig,
    this.f = function(a,b){
        return a+b
    },
    this.g = null,
    this.h = undefined,
    this.i = "hello",
    this.j = Symbol("foo")
}
construct.prototype.str = "I'm prototype"
var obj1 = new construct()
obj1.k = obj1
obj2 = deepClone(obj1)
obj2.b.x = 999
obj2.c[0] = 666
console.log(obj1)
console.log(obj2)
console.log(obj1.str)
console.log(obj2.str)

注:Function類型的深拷貝:

bind():使用fn.bind()可將函數進行深拷貝,但因為this指針指向問題而不能使用;

eval(fn.toString()):只支持箭頭函數,普通函數function fn(){}則不適用;

new Function(arg1,arg2,…,function_body):需將參數與函數體提取出來;

感謝各位的閱讀!關于“JavaScript對象的基礎知識點有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

绥化市| 梁山县| 余姚市| 沙河市| 安图县| 揭东县| 宁强县| 鲜城| 陕西省| 孝昌县| 迭部县| 丰都县| 常德市| 固镇县| 固原市| 武汉市| 九龙县| 宁蒗| 柘城县| 乌兰县| 阳城县| 高陵县| 新闻| 乐平市| 云和县| 吴江市| 英山县| 肥城市| 增城市| 绥宁县| 乌拉特中旗| 嘉兴市| 孙吴县| 阳高县| 且末县| 西安市| 滨州市| 尚义县| 丁青县| 多伦县| 沙田区|